/*--------------------------------------------------------------------------*/ /*! \file nifti_tool.c * \brief a tool for nifti file perusal, manipulation and copying * written by Rick Reynolds, SSCC, NIMH, January 2005 *
 *
 * usage: nifti_tool [options] -infiles files...
 *
 * Via this tool, one should be able to:
 *
 *       - copy a set of volumes (sub-bricks) from one dataset to another
 *       - copy a dataset, restricting some dimensions to given indices
 *
 *       - display the contents of a nifti_image (or various fields)
 *       - display the contents of a nifti1_header (or various fields)
 *       - display AFNI extensions (they are text)
 *       - display the time series at coordinates i,j,k
 *       - display the data from any collapsed image
 *
 *       - do a diff on two nifti_image structs (or various fields)
 *       - do a diff on two nifti1_header structs (or various fields)
 *
 *       - add an AFNI extension
 *       - remove any extension
 *
 *       - modify any field(s) of a nifti_image
 *       - modify any field(s) of a nifti1_struct
 *
 * usage forms:
 *
 *   nifti_tool -help
 *   nifti_tool -help_hdr
 *   nifti_tool -help_hdr1
 *   nifti_tool -help_hdr2
 *   nifti_tool -help_nim
 *   nifti_tool -help_nim1
 *   nifti_tool -help_nim2
 *   nifti_tool -help_ana
 *   nifti_tool -help_datatypes
 *   nifti_tool -hist
 *   nifti_tool -ver
 *   nifti_tool -ver_man
 *   nifti_tool -see_also
 *   nifti_tool -nifti_hist
 *   nifti_tool -nifti_ver
 *   nifti_tool -with_zlib
 *
 *   nifti_tool -check_hdr -infiles f1 ...
 *   nifti_tool -check_nim -infiles f1 ...

 *   nifti_tool -disp_cext -infiles f1 ...
 *   nifti_tool -disp_exts -infiles f1 ...
 *   nifti_tool -disp_hdr  [-field fieldname] [...] -infiles f1 ...
 *   nifti_tool -disp_hdr1 [-field fieldname] [...] -infiles f1 ...
 *   nifti_tool -disp_hdr2 [-field fieldname] [...] -infiles f1 ...
 *   nifti_tool -disp_nim  [-field fieldname] [...] -infiles f1 ...
 *   nifti_tool -disp_ana  [-field fieldname] [...] -infiles f1 ...
 *   nifti_tool -disp_ts I J K [-dci_lines] -infiles f1 ...
 *   nifti_tool -disp_ci I J K T U V W [-dci_lines] -infiles f1 ...
 *
 *   nifti_tool -diff_hdr  [-field fieldname] [...] -infiles f1 f2
 *   nifti_tool -diff_hdr1 [-field fieldname] [...] -infiles f1 f2
 *   nifti_tool -diff_hdr2 [-field fieldname] [...] -infiles f1 f2
 *   nifti_tool -diff_nim  [-field fieldname] [...] -infiles f1 f2
 *
 *   nifti_tool -add_afni_ext    "extension in quotes" -infiles f1 ...
 *   nifti_tool -add_comment_ext "extension in quotes" -infiles f1 ...
 *   nifti_tool -rm_ext ext_index -infiles f1 ...
 *
 *   nifti_tool -mod_hdr  [-mod_field fieldname new_val] [...] -infiles f1 ...
 *   nifti_tool -mod_hdr2 [-mod_field fieldname new_val] [...] -infiles f1 ...
 *   nifti_tool -mod_nim  [-mod_field fieldname new_val] [...] -infiles f1 ...
 *
 * 
*/ /*-------------------------------------------------------------------------*/ /*! module history */ static const char * g_history[] = { "----------------------------------------------------------------------\n" "nifti_tool modification history:\n" "\n", "0.1 30 December 2004 [rickr]\n" " (Rick Reynolds of the National Institutes of Health, SSCC/DIRP/NIMH)\n" " - skeleton version: options read and printed\n" "\n", "1.0 07 January 2005 [rickr]\n" " - initial release version\n" "\n", "1.1 14 January 2005 [rickr]\n" " - changed all non-error/non-debug output from stderr to stdout\n" " note: creates a mismatch between normal output and debug messages\n" " - modified act_diff_hdrs and act_diff_nims to do the processing in\n" " lower-level functions\n", " - added functions diff_hdrs, diff_hdrs_list, diff_nims, diff_nims_list\n" " - added function get_field, to return a struct pointer via a fieldname\n" " - made 'quiet' output more quiet (no description on output)\n" " - made hdr and nim_fields arrays global, so do not pass in main()\n" " - return (from main()) after first act_diff() difference\n" "\n", "1.2 9 February 2005 [rickr] - minor\n" " - defined a local NTL_FERR macro (so it does not come from nifti1_io.h)\n" " - added new set_byte_order parameter to nifti_set_filenames\n" "\n", "1.3 23 February 2005 [rickr] - sourceforge.net merge\n" " - moved to utils directory\n" " - added simple casts of 3 pointers for -pedantic warnings\n" " - added a doxygen comment for the file\n" "\n", "1.4 02 March 2005 [rickr] - small update\n" " - no validation in nifti_read_header calls\n" "\n", "1.5 05 April 2005 [rickr] - small update\n" " - refuse mod_hdr for gzipped files (we cannot do partial overwrites)\n" "\n", "1.6 08 April 2005 [rickr] - added cbl, cci and dts functionality\n" " - added -cbl: 'copy brick list' dataset copy functionality\n" " - added -ccd: 'copy collapsed data' dataset copy functionality\n" " - added -disp_ts: 'disp time series' data display functionality\n" " - moved raw data display to disp_raw_data()\n" "\n", "1.7 14 April 2005 [rickr] - added data display functionality\n" " - added -dci: 'display collapsed image' functionality\n" " - modified -dts to use -dci\n" " - modified and updated the help in use_full()\n" " - changed copy_collapsed_dims to copy_collapsed_image, etc.\n", " - fixed problem in disp_raw_data() for printing NT_DT_CHAR_PTR\n" " - modified act_disp_ci():\n" " o was act_disp_ts(), now displays arbitrary collapsed image data\n" " o added missed debug filename act_disp_ci()\n" " o can now save free() of data pointer for end of file loop\n", " - modified disp_raw_data()\n" " o takes a flag for whether to print newline\n" " o trailing spaces and zeros are removed from printing floats\n" " - added clear_float_zeros(), to remove trailing zeros\n" "\n", "1.8 19 April 2005 [rickr] - COMMENT extensions\n" " - added int_list struct, and keep_hist,etypes,command fields to nt_opts\n" " - added -add_comment_ext action\n" " - allowed for removal of multiple extensions, including option of ALL\n" " - added -keep_hist option, to store the command as a COMMENT extension\n", " (includes fill_cmd_string() and add_int(), is done for all actions)\n" " - added remove_ext_list(), for removing a list of extensions by indices\n" " - added -strip_extras action, to strip all exts and descrip fields\n" "\n", "1.9 25 Aug 2005 [rickr] - const/string cleanup for warnings\n", "1.10 18 Nov 2005 [rickr] - added check_hdr and check_nim actions\n", "1.11 31 Jan 2006 [rickr] - check for new vox_offset in act_mod_hdrs\n", "1.12 02 Mar 2006 [rickr]\n" " - in act_cbl(), check for nt = 0 because of niftilib update 1.17\n", "1.13 24 Apr 2006 [rickr] - act_disp_ci(): remove time series length check\n", "1.14 04 Jun 2007 [rickr] - free_opts_mem(), to appease valgrind\n", "1.15 05 Jun 2007 [rickr] - act_check_hdrs: free(nim)->nifti_image_free()\n", "1.16 12 Jun 2007 [rickr] - allow creation of datasets via MAKE_IM\n", " - added nt_image_read, nt_read_header and nt_read_bricks\n" " to wrap nifti read functions, allowing creation of new datasets\n" " - added -make_im, -new_dim, -new_datatype and -copy_im\n" "1.17 13 Jun 2007 [rickr] - added help for -copy_im, enumerate examples\n", "1.18 23 Jun 2007 [rickr] - main returns 0 on -help, -hist, -ver\n" "1.19 28 Nov 2007 [rickr] - added -help_datatypes\n", "1.20 13 Jun 2008 [rickr]\n" " - added -with_zlib\n" " - added ability to create extension from text file (for J. Gunter)\n", "1.21 03 Aug 2008 [rickr] - ANALYZE 7.5 support\n" " - added -help_ana, -disp_ana,\n" " -swap_as_analyze, -swap_as_nifti, -swap_as_old\n" "1.22 08 Oct 2008 [rickr] - allow cbl with indices in 0..nt*nu*nv*nw-1\n" "1.23 06 Jul 2010 [rickr]\n", " - in nt_read_bricks, bsize computation should allow for large integers\n" "1.24 26 Sep 2012 [rickr]\n", " - changed ana originator from char to short\n" "2.00 29 Aug 2013 [rickr] - NIFTI-2\n", "2.01 28 Apr 2015 [rickr] - disp_hdr1/disp_hdr2 to read as those types\n" "2.02 01 Jun 2015 [rickr]\n", " - disp_hdr detects type\n" " - diff_hdr detects type\n" " - have diff_hdr1/diff_hdr2 to read as those types\n" "2.03 23 Jul 2015 [rickr] - handle a couple of unknown version cases\n", "2.04 05 Aug 2015 [rickr] - incorporate nifti-2 writing library change\n", "2.05 24 Jul 2017 [rickr]\n" " - display ANALYZE header via appropriate NIFTI-1\n" " - apply more PRId64 for 64-bit int I/O\n" "2.06 04 Jan 2019 [rickr]\n", " - add -mod_hdr2 option, to explicitly modify NIFTI-2 headers\n" " - mod_hdr and swap_as_nifti fail on valid NIFTI-2 headers\n" "2.07 19 Jul 2019 [rickr]\n", " - can apply '-field HDR_SLICE_TIMING_FIELDS' (or NIM_) for easy\n" " specification of field entries related to slice timing\n" "2.08 5 Oct 2019 [rickr]\n", " - added option -run_misc_tests for functionality testing\n" " - added many corresponding tests\n" " - added some matrix manipulation macros\n" " - warn on type, and block print buffer overflow\n" "2.09 7 Apr 2020 [rickr]\n", " - add -see_also and -ver_man, for man page generation\n", "2.10 27 Aug 2020 [rickr]\n", " - nt_image_read() takes a new make_ver parameter\n", " - possibly convert default NIFTI-2 MAKE_IM result to NIFTI-1\n" "2.11 29 Dec 2020 [rickr] - add example to create dset from raw data\n", "2.12 21 Feb 2022 [rickr]\n" " - start to deprecate -copy_im (bad name; -cbl can alter hdr on read)\n", "2.13 27 Feb 2022 [rickr]\n" " - add -copy_image (w/data conversion)\n" " - add -convert2dtype, -convert_verify, -convert_fail_choice\n", "----------------------------------------------------------------------\n" }; static char g_version[] = "2.13"; static char g_version_date[] = "February 27, 2022"; static int g_debug = 1; #include #include #include #include "nifti2_io.h" #include "nifti_tool.h" /* local prototypes */ static int free_opts_mem(nt_opts * nopt); static int num_volumes(nifti_image * nim); static char * read_file_text(const char * filename, int * length); #define NTL_FERR(func,msg,file) \ fprintf(stderr,"** ERROR (%s): %s '%s'\n",func,msg,file) /* val may be a function call, so evalulate first, and return result */ #define FREE_RETURN(val) \ do{ int tval=(val); free_opts_mem(&opts); return tval; } while(0) /* these are effectively constant, and are built only for verification */ static field_s g_hdr1_fields[NT_HDR1_NUM_FIELDS]; /* nifti_1_header fields */ static field_s g_hdr2_fields[NT_HDR2_NUM_FIELDS]; /* nifti_2_header fields */ static field_s g_ana_fields [NT_ANA_NUM_FIELDS]; /* nifti_analyze75 */ static field_s g_nim1_fields[NT_NIM_NUM_FIELDS]; /* nifti_image fields */ static field_s g_nim2_fields[NT_NIM_NUM_FIELDS]; /* nifti2_image fields */ /* slice timing hdr and nim fields */ static const char * g_hdr_timing_fnames[NT_HDR_TIME_NFIELDS] = { "slice_code", "slice_start", "slice_end", "slice_duration", "dim_info", "dim", "pixdim", "xyzt_units" }; static const char * g_nim_timing_fnames[NT_NIM_TIME_NFIELDS] = { "slice_code", "slice_start", "slice_end", "slice_duration", "slice_dim", "phase_dim", "freq_dim", "dim", "pixdim", "xyz_units", "time_units" }; int main( int argc, char * argv[] ) { nt_opts opts; int rv; if( (rv = process_opts(argc, argv, &opts)) != 0) /* then return */ { if( rv < 0 ) FREE_RETURN(1); /* free opts memory, and return */ else FREE_RETURN(0); /* valid usage */ } if( (rv = verify_opts(&opts, argv[0])) != 0 ) FREE_RETURN(rv); /* now perform the requested action(s) */ if( (rv = fill_hdr1_field_array(g_hdr1_fields)) != 0 ) FREE_RETURN(rv); if( (rv = fill_hdr2_field_array(g_hdr2_fields)) != 0 ) FREE_RETURN(rv); if( (rv = fill_nim1_field_array(g_nim1_fields)) != 0 ) FREE_RETURN(rv); if( (rv = fill_nim2_field_array(g_nim2_fields)) != 0 ) FREE_RETURN(rv); if( (rv = fill_ana_field_array(g_ana_fields)) != 0 ) FREE_RETURN(rv); /* 'check' functions, first */ if( opts.check_hdr || opts.check_nim ) /* allow for both */ FREE_RETURN( act_check_hdrs(&opts) ); /* copy or dts functions -- do not continue after these */ if( opts.cbl ) FREE_RETURN( act_cbl(&opts) ); if( opts.cci ) FREE_RETURN( act_cci(&opts) ); if( opts.copy_image ) FREE_RETURN( act_copy(&opts) ); if( opts.dts || opts.dci ) FREE_RETURN( act_disp_ci(&opts) ); /* perform modifications early, in case we allow multiple actions */ if( opts.strip && ((rv = act_strip (&opts)) != 0) ) FREE_RETURN(rv); if( opts.add_exts && ((rv = act_add_exts (&opts)) != 0) ) FREE_RETURN(rv); if( opts.rm_exts && ((rv = act_rm_ext (&opts)) != 0) ) FREE_RETURN(rv); if( opts.mod_hdr && ((rv = act_mod_hdrs (&opts)) != 0) ) FREE_RETURN(rv); if( opts.mod_hdr2 && ((rv = act_mod_hdr2s(&opts)) != 0) ) FREE_RETURN(rv); if( opts.mod_nim && ((rv = act_mod_nims (&opts)) != 0) ) FREE_RETURN(rv); if((opts.swap_hdr || opts.swap_ana || opts.swap_old ) && ((rv = act_swap_hdrs (&opts)) != 0) ) FREE_RETURN(rv); /* if a diff, return whether, a difference exists (like the UNIX command) */ if( opts.diff_hdr && ((rv = act_diff_hdrs (&opts)) != 0) ) FREE_RETURN(rv); if( opts.diff_hdr1 && ((rv = act_diff_hdr1s(&opts)) != 0) ) FREE_RETURN(rv); if( opts.diff_hdr2 && ((rv = act_diff_hdr2s(&opts)) != 0) ) FREE_RETURN(rv); if( opts.diff_nim && ((rv = act_diff_nims(&opts)) != 0) ) FREE_RETURN(rv); /* run tests */ if( opts.run_misc_tests && ((rv = act_run_misc_tests(&opts)) != 0) ) FREE_RETURN(rv); /* last action type is display */ if( opts.disp_exts && ((rv = act_disp_exts(&opts)) != 0) ) FREE_RETURN(rv); if( opts.disp_cext && ((rv = act_disp_cext(&opts)) != 0) ) FREE_RETURN(rv); if( opts.disp_hdr && ((rv = act_disp_hdr (&opts)) != 0) ) FREE_RETURN(rv); if( opts.disp_hdr1 && ((rv = act_disp_hdr1(&opts)) != 0) ) FREE_RETURN(rv); if( opts.disp_hdr2 && ((rv = act_disp_hdr2(&opts)) != 0) ) FREE_RETURN(rv); if( opts.disp_nim && ((rv = act_disp_nims(&opts)) != 0) ) FREE_RETURN(rv); if( opts.disp_ana && ((rv = act_disp_anas(&opts)) != 0) ) FREE_RETURN(rv); FREE_RETURN(0); } /*---------------------------------------------------------------------- * process user options, return 0 on success *----------------------------------------------------------------------*/ int process_opts( int argc, char * argv[], nt_opts * opts ) { int ac, count; memset(opts, 0, sizeof(*opts)); opts->prefix = NULL; opts->debug = 1; /* init debug level to basic output */ opts->cnvt_fail_choice = 1; /* default to warn on convert failure */ /* init options for creating a new dataset via "MAKE_IM" */ opts->new_datatype = NIFTI_TYPE_INT16; opts->new_dim[0] = 3; opts->new_dim[1] = 1; opts->new_dim[2] = 1; opts->new_dim[3] = 1; if( argc < 2 ) return usage(argv[0], USE_FULL); /* terminal options are first, the rest are sorted */ for( ac = 1; ac < argc; ac++ ) { if( ! strcmp(argv[ac], "-help_datatypes") ) { ac++; if( ac >= argc ) nifti_disp_type_list(3); /* show all types */ else if( argv[ac][0] == 'd' || argv[ac][0] == 'D' ) nifti_disp_type_list(1); /* show DT_* types */ else if( argv[ac][0] == 't' || argv[ac][0] == 'T' ) nifti_test_datatype_sizes(1); /* test each nbyper and swapsize */ else nifti_disp_type_list(2); /* show NIFTI_* types */ return 1; } else if( ! strcmp(argv[ac], "-help_hdr") ) return usage(argv[0], USE_FIELD_HDR2); else if( ! strcmp(argv[ac], "-help_hdr1") ) return usage(argv[0], USE_FIELD_HDR1); else if( ! strcmp(argv[ac], "-help_hdr2") ) return usage(argv[0], USE_FIELD_HDR2); else if( ! strcmp(argv[ac], "-help_nim") ) return usage(argv[0], USE_FIELD_NIM2); else if( ! strcmp(argv[ac], "-help_nim1") ) return usage(argv[0], USE_FIELD_NIM1); else if( ! strcmp(argv[ac], "-help_nim2") ) return usage(argv[0], USE_FIELD_NIM2); else if( ! strcmp(argv[ac], "-help_ana") ) return usage(argv[0], USE_FIELD_ANA); else if( ! strcmp(argv[ac], "-help") ) return usage(argv[0], USE_FULL); else if( ! strcmp(argv[ac], "-hist") ) return usage(argv[0], USE_HIST); else if( ! strcmp(argv[ac], "-see_also") ) return usage(argv[0], USE_SEE_ALSO); else if( ! strcmp(argv[ac], "-ver") ) return usage(argv[0], USE_VERSION); else if( ! strcmp(argv[ac], "-ver_man") ) return usage(argv[0], USE_VER_MAN); else if( ! strcmp(argv[ac], "-nifti_hist") ) { nifti_disp_lib_hist(1); nifti_disp_lib_hist(2); return 1; } else if( ! strcmp(argv[ac], "-nifti_ver") ) { nifti_disp_lib_version(); return 1; } else if( ! strcmp(argv[ac], "-with_zlib") ) { printf("Was NIfTI library compiled with zlib? %s\n", nifti_compiled_with_zlib() ? "YES" : "NO"); return 1; } /* begin normal execution options... */ else if( ! strcmp(argv[ac], "-add_ext") ) { int64_t new_ecode; ac++; CHECK_NEXT_OPT(ac, argc, "-add_ext"); new_ecode = strtol(argv[ac], NULL, 10); if (new_ecode <= 0 || new_ecode > INT_MAX) { fprintf(stderr,"** invalid -add_ext code, %s\n", argv[ac]); return -1; } if( add_int(&opts->etypes, (int)new_ecode) ) return -1; ac++; CHECK_NEXT_OPT(ac, argc, "-add_ext"); if( add_string(&opts->elist, argv[ac]) ) return -1; /* add extension */ opts->add_exts = 1; } else if( ! strcmp(argv[ac], "-add_afni_ext") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-add_afni_ext"); if( add_string(&opts->elist, argv[ac]) ) return -1; /* add extension */ if( add_int(&opts->etypes, NIFTI_ECODE_AFNI) ) return -1; opts->add_exts = 1; } else if( ! strncmp(argv[ac], "-add_comment_ext", 12) ) { ac++; CHECK_NEXT_OPT(ac, argc, "-add_comment_ext"); if( add_string(&opts->elist, argv[ac]) ) return -1; /* add extension */ if( add_int(&opts->etypes, NIFTI_ECODE_COMMENT) ) return -1; opts->add_exts = 1; } else if( ! strcmp(argv[ac], "-check_hdr") ) opts->check_hdr = 1; else if( ! strcmp(argv[ac], "-check_nim") ) opts->check_nim = 1; else if( ! strcmp(argv[ac], "-copy_image") ) opts->copy_image = 1; else if( ! strcmp(argv[ac], "-convert2dtype") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-convert2dtype"); opts->convert2dtype = nifti_datatype_from_string(argv[ac]); if( opts->convert2dtype == 0 ) { fprintf(stderr,"** -convert2dtype: invalid datatype %s\n",argv[ac]); fprintf(stderr," consider: nifti_tool -help_datatypes\n"); return -1; } } else if( ! strcmp(argv[ac], "-convert_verify") ) opts->cnvt_verify = 1; else if( ! strcmp(argv[ac], "-convert_fail_choice") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-convert_fail_choice"); if( !strcmp( argv[ac], "ignore") ) opts->cnvt_fail_choice = 0; else if( !strcmp( argv[ac], "warn") ) opts->cnvt_fail_choice = 1; else if( !strcmp( argv[ac], "fail") ) opts->cnvt_fail_choice = 2; else { fprintf(stderr,"** invalid -convert_fail_choice parameter\n"); fprintf(stderr," (must be ignore, warn or fail)\n"); return -1; } /* have fail_choice imply verify */ opts->cnvt_verify = 1; } else if( ! strcmp(argv[ac], "-copy_brick_list") || ! strcmp(argv[ac], "-copy_im") || ! strcmp(argv[ac], "-cbl") ) { if( ! strcmp(argv[ac], "-copy_im") ) fprintf(stderr,"** -copy_im is being deprecated, please use -cbl\n"); opts->cbl = 1; } else if( ! strcmp(argv[ac], "-copy_collapsed_image") || ! strcmp(argv[ac], "-cci") ) { /* we need to read in the 7 dimension values */ int index; opts->ci_dims[0] = 0; for( index = 1; index < 8; index++ ) { ac++; CHECK_NEXT_OPT_MSG(ac,argc,"-cci","7 dimension values are required"); if( ! isdigit(argv[ac][0]) && strcmp(argv[ac],"-1") ){ fprintf(stderr,"** -cci param %d (= '%s') is not a valid\n" " consider: 'nifti_tool -help'\n",index,argv[ac]); return -1; } opts->ci_dims[index] = atoll(argv[ac]); } opts->cci = 1; } else if( ! strcmp(argv[ac], "-debug") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-debug"); opts->debug = atoi(argv[ac]); g_debug = opts->debug; } else if( ! strcmp(argv[ac], "-diff_hdr") ) opts->diff_hdr = 1; else if( ! strcmp(argv[ac], "-diff_hdr1") ) opts->diff_hdr1 = 1; else if( ! strcmp(argv[ac], "-diff_hdr2") ) opts->diff_hdr2 = 1; else if( ! strcmp(argv[ac], "-diff_nim") ) opts->diff_nim = 1; else if( ! strncmp(argv[ac], "-disp_exts", 9) ) opts->disp_exts = 1; else if( ! strncmp(argv[ac], "-disp_cext", 9) ) opts->disp_cext = 1; else if( ! strcmp(argv[ac], "-disp_hdr") ) opts->disp_hdr = 1; else if( ! strcmp(argv[ac], "-disp_hdr1") ) opts->disp_hdr1 = 1; else if( ! strcmp(argv[ac], "-disp_hdr2") ) opts->disp_hdr2 = 1; else if( ! strcmp(argv[ac], "-disp_nim") ) opts->disp_nim = 1; else if( ! strcmp(argv[ac], "-disp_ana") ) opts->disp_ana = 1; else if( ! strcmp(argv[ac], "-dci_lines") || /* before -dts */ ! strcmp(argv[ac], "-dts_lines") ) { opts->dci_lines = 1; } else if( ! strcmp(argv[ac], "-disp_collapsed_image") || ! strcmp(argv[ac], "-disp_ci") ) { /* we need to read in the 7 dimension values */ int index; opts->ci_dims[0] = 0; for( index = 1; index < 8; index++ ) { ac++; CHECK_NEXT_OPT_MSG(ac,argc,"-disp_ci", "7 dimension values are required"); if( ! isdigit(argv[ac][0]) && strcmp(argv[ac],"-1") ){ fprintf(stderr,"** -disp_ci param %d (= '%s') is not a valid\n" " consider: 'nifti_tool -help'\n",index,argv[ac]); return -1; } opts->ci_dims[index] = atoll(argv[ac]); } opts->dci = 1; } else if( ! strcmp(argv[ac], "-disp_ts") || ! strcmp(argv[ac], "-dts") ) { /* we need to read in the ijk indices into the ci_dims array */ int index; for( index = 1; index <= 3; index++ ) { ac++; CHECK_NEXT_OPT_MSG(ac,argc,"-dts","i,j,k indices are required\n"); if( ! isdigit(argv[ac][0]) ){ fprintf(stderr,"** -dts param %d (= '%s') is not a number\n" " consider: 'nifti_tool -help'\n",index,argv[ac]); return -1; } opts->ci_dims[index] = atoll(argv[ac]); } /* and fill the rest of the array */ opts->ci_dims[0] = 0; for( index = 4; index < 8; index++ ) opts->ci_dims[index] = -1; opts->dts = 1; } else if( ! strcmp(argv[ac], "-field") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-field"); /* allow HDR/NIM_S_TIMING FIELDS as special cases */ if( ! strcmp(argv[ac], "HDR_SLICE_TIMING_FIELDS") ) { for( count = 0; count < NT_HDR_TIME_NFIELDS; count++ ) if( add_string(&opts->flist, g_hdr_timing_fnames[count]) ) return -1; } else if( ! strcmp(argv[ac], "NIM_SLICE_TIMING_FIELDS") ) { for( count = 0; count < NT_NIM_TIME_NFIELDS; count++ ) if( add_string(&opts->flist, g_nim_timing_fnames[count]) ) return -1; } else { /* otherwise, just add as a typical field */ if( add_string(&opts->flist, argv[ac]) ) return -1; /* add field */ } } else if( ! strncmp(argv[ac], "-infiles", 3) ) { /* for -infiles, get all next arguments until a '-' or done */ ac++; for( count = 0; (ac < argc) && (argv[ac][0] != '-'); ac++, count++ ) if( add_string(&opts->infiles, argv[ac]) ) return -1;/* add field */ if( count > 0 && ac < argc ) ac--; /* more options to process */ if( g_debug > 2 ) fprintf(stderr,"+d have %d file names\n", count); } else if( ! strncmp(argv[ac], "-make_image", 8) ) { opts->make_im = 1; /* will setup later, as -cbl and MAKE_IM */ } else if( ! strcmp(argv[ac], "-mod_field") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-mod_field"); if( add_string(&opts->flist, argv[ac]) ) return -1; /* add field */ ac++; CHECK_NEXT_OPT(ac, argc, "-mod_field (2)"); if( add_string(&opts->vlist, argv[ac]) ) return -1; /* add value */ } else if( ! strcmp(argv[ac], "-mod_hdr") ) opts->mod_hdr = 1; else if( ! strcmp(argv[ac], "-mod_hdr2") ) /* 3 Jan 2019 */ opts->mod_hdr2 = 1; else if( ! strcmp(argv[ac], "-mod_nim") ) opts->mod_nim = 1; else if( ! strcmp(argv[ac], "-keep_hist") ) opts->keep_hist = 1; else if( ! strncmp(argv[ac], "-new_dim", 8) ) { /* we need to read in the 8 dimension values */ int index; for( index = 0; index < 8; index++ ) { ac++; CHECK_NEXT_OPT_MSG(ac,argc,"-new_dim","8 dim values are required"); if( ! isdigit(argv[ac][0]) && strcmp(argv[ac],"-1") ){ fprintf(stderr,"** -new_dim param %d (= '%s') is not a valid\n" " consider: 'nifti_tool -help'\n",index,argv[ac]); return -1; } opts->new_dim[index] = atoll(argv[ac]); } } else if( ! strcmp(argv[ac], "-new_datatype") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-new_datatype"); opts->new_datatype = atoi(argv[ac]); } else if( ! strcmp(argv[ac], "-overwrite") ) opts->overwrite = 1; else if( ! strcmp(argv[ac], "-prefix") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-prefix"); opts->prefix = argv[ac]; } else if( ! strcmp(argv[ac], "-quiet") ) opts->debug = 0; else if( ! strcmp(argv[ac], "-rm_ext") ) { ac++; CHECK_NEXT_OPT(ac, argc, "-rm_ext"); if( strcmp(argv[ac],"ALL") == 0 ) /* special case, pass -1 */ { if( add_string(&opts->elist, "-1") ) return -1; } else { int index = atoi(argv[ac]); if( (index != -1) && ((index > 1000) || !isdigit(*argv[ac])) ){ fprintf(stderr, "** '-rm_ext' requires an extension index (read '%s')\n", argv[ac]); return -1; } if( add_string(&opts->elist, argv[ac]) ) return -1; } opts->rm_exts = 1; } else if( ! strcmp(argv[ac], "-run_misc_tests") ) opts->run_misc_tests = 1; else if( ! strncmp(argv[ac], "-strip_extras", 6) ) opts->strip = 1; else if( ! strcmp(argv[ac], "-swap_as_analyze") ) opts->swap_ana = 1; else if( ! strcmp(argv[ac], "-swap_as_nifti") ) opts->swap_hdr = 1; else if( ! strcmp(argv[ac], "-swap_as_old") ) opts->swap_old = 1; else { fprintf(stderr,"** unknown option: '%s'\n", argv[ac]); return -1; } } if( opts->make_im ) { if( opts->infiles.len > 0 ) { fprintf(stderr,"** -infiles is invalid when using -make_im\n"); return -1; } /* apply -make_im via -cbl and "MAKE_IM" */ opts->cbl = 1; if( add_string(&opts->infiles, NT_MAKE_IM_NAME) ) return -1; } /* verify for programming purposes */ if( opts->add_exts && ( opts->elist.len != opts->etypes.len ) ) { fprintf(stderr,"** ext list length (%d) != etype length (%d)\n", opts->elist.len, opts->etypes.len); return -1; } g_debug = opts->debug; nifti_set_debug_level(g_debug); fill_cmd_string(opts, argc, argv); /* copy this command */ if( g_debug > 2 ) disp_nt_opts("options read: ", opts); return 0; } /*---------------------------------------------------------------------- * verify that the options make sense *----------------------------------------------------------------------*/ int verify_opts( nt_opts * opts, char * prog ) { int ac, errs = 0; /* number of requested action types */ /* check that only one of disp, diff, mod or add_*_ext is used */ ac = (opts->check_hdr || opts->check_nim ) ? 1 : 0; ac += (opts->diff_hdr || opts->diff_hdr1 || opts->diff_hdr2 || opts->diff_nim ) ? 1 : 0; ac += (opts->disp_hdr || opts->disp_hdr1 || opts->disp_hdr2 || opts->disp_nim || opts->disp_ana || opts->disp_exts || opts->disp_cext) ? 1 : 0; ac += opts->mod_hdr; ac += opts->mod_hdr2; ac += opts->mod_nim; ac += (opts->swap_hdr || opts->swap_ana || opts->swap_old ) ? 1 : 0; ac += opts->add_exts; ac += opts->rm_exts; ac += opts->run_misc_tests; ac += (opts->strip ) ? 1 : 0; ac += (opts->copy_image ) ? 1 : 0; ac += (opts->cbl ) ? 1 : 0; ac += (opts->cci ) ? 1 : 0; ac += (opts->dts || opts->dci ) ? 1 : 0; if( ac < 1 ) { fprintf(stderr, "** no action option, so nothing to do...\n" " (try one of '-add...', '-diff...', '-disp...' or '-mod...')\n" " (see '%s -help' for details)\n", prog); return 1; } else if( ac > 1 ) { fprintf(stderr, "** only one action option is allowed, please use only one of:\n" " '-add_...', '-check_...', '-diff_...', '-disp_...',\n" " '-mod_...', '-strip', '-dts', '-cbl', '-cci'\n" " '-copy_image'\n" " (see '%s -help' for details)\n", prog); return 1; } if( (opts->add_exts || opts->rm_exts) && opts->elist.len <= 0 ) { fprintf(stderr,"** missing extensions to add or remove\n"); return 1; } /* if modify, then we need fields and corresponding values */ if( opts->mod_hdr || opts->mod_hdr2 || opts->mod_nim ) { if( opts->flist.len <= 0 ) { fprintf(stderr,"** missing field to modify (need '-mod_field' opt)\n"); return 1; } if( opts->flist.len != opts->vlist.len ) { fprintf(stderr,"** error: modifying %d fields with %d values\n", opts->flist.len, opts->vlist.len); return 1; } } /* verify the number of files given for each of 4 action types */ /* -diff_... : require nfiles == 2 */ if( opts->diff_hdr1 || opts->diff_nim ) { if( opts->infiles.len != 2 ) { fprintf(stderr,"** '-diff_XXX' options require exactly 2 inputs files\n"); return 1; } } /* if we are making changes, but not overwriting... */ else if( (opts->elist.len > 0 || opts->mod_hdr || opts->mod_hdr2 || opts->mod_nim || opts->swap_hdr || opts->swap_ana || opts->swap_old ) && !opts->overwrite ) { if( opts->infiles.len > 1 ) { fprintf(stderr,"** without -overwrite, only one input file may be" " modified at a time\n"); errs++; } else if( ! opts->prefix ) { fprintf(stderr,"** missing -prefix for output file\n"); errs++; } } if( opts->dci_lines && ! opts->dts && ! opts->dci ) { fprintf(stderr,"** option '-dci_lines' must only be used with '-dts'\n"); errs++; } if( opts->infiles.len <= 0 ) /* in any case */ { fprintf(stderr,"** missing input files (see -infiles option)\n"); errs++; } if ( opts->overwrite && opts->prefix ) { fprintf(stderr, "** please specify only one of -prefix and -overwrite\n"); errs++; } if( errs ) return 1; if( g_debug > 1 ) fprintf(stderr,"+d options seem valid\n"); return 0; } /*---------------------------------------------------------------------- * re-assemble the command string into opts->command * (commands are currently limited to 2048 bytes) *----------------------------------------------------------------------*/ int fill_cmd_string( nt_opts * opts, int argc, char * argv[]) { char * cp; int len, remain = (int)sizeof(opts->command); /* max command len */ int c, ac; int has_space; /* arguments containing space must be quoted */ int skip = 0; /* counter to skip some of the arguments */ /* get the first argument separately */ len = snprintf( opts->command, sizeof(opts->command), "\n command: %s", argv[0] ); if( len < 0 || len >= (int)sizeof(opts->command) ) { fprintf(stderr,"FCS: no space remaining for command, continuing...\n"); return 1; } cp = opts->command + len; remain -= len; /* get the rest, with special attention to input files */ for( ac = 1; ac < argc; ac++ ) { if( skip ){ skip--; continue; } /* then skip these arguments */ len = (int)strlen(argv[ac]); if( len + 3 >= remain ) { /* extra 3 for space and possible '' */ fprintf(stderr,"FCS: no space remaining for command, continuing...\n"); return 1; } /* put the argument in, possibly with '' */ has_space = 0; for( c = 0; c < len-1; c++ ) if( isspace(argv[ac][c]) ){ has_space = 1; break; } if( has_space ) len = snprintf(cp, remain, " '%s'", argv[ac]); else len = snprintf(cp, remain, " %s", argv[ac]); remain -= len; /* infiles is okay, but after the *next* argument, we may skip files */ /* (danger, will robinson! hack alert!) */ if( !strcmp(argv[ac-1],"-infiles") ) { /* if more than 4 (just to be arbitrary) input files, include only the first and last */ if( opts->infiles.len > 4 ) skip = opts->infiles.len - 2; } cp += len; } if( g_debug > 1 ){ fprintf(stderr,"+d filled command string, %d args, %d bytes\n", argc, (int)(cp - opts->command)); if( g_debug > 2 ) fprintf(stderr,"%s\n", opts->command); } return 0; } /*---------------------------------------------------------------------- * - only bother to alloc one pointer at a time (don't need efficiency here) * - return 0 on success *----------------------------------------------------------------------*/ int add_int(int_list * ilist, int val) { if( ilist->len == 0 ) ilist->list = NULL; /* just to be safe */ ilist->len++; ilist->list = (int *)realloc(ilist->list,ilist->len*sizeof(int)); if( ! ilist->list ){ fprintf(stderr,"** failed to alloc %d (int *) elements\n",ilist->len); return -1; } ilist->list[ilist->len-1] = val; return 0; } /*---------------------------------------------------------------------- * - do not duplicate the string * - only bother to alloc one pointer at a time (don't need efficiency here) * - return 0 on success *----------------------------------------------------------------------*/ int add_string(str_list * slist, const char * str) { if( slist->len == 0 ) slist->list = NULL; /* just to be safe */ slist->len++; slist->list = (const char **)realloc(slist->list,slist->len*sizeof(char *)); if( ! slist->list ){ fprintf(stderr,"** failed to alloc %d (char *) elements\n",slist->len); return -1; } slist->list[slist->len-1] = str; return 0; } /*---------------------------------------------------------------------- * display information on using the program *----------------------------------------------------------------------*/ int usage(char * prog, int level) { int c, len; if( level == USE_SHORT ) { fprintf(stdout,"usage %s [options] -infiles files...\n", prog); fprintf(stdout,"usage %s -help\n", prog); return -1; } else if( level == USE_FULL ) use_full(); /* let's not allow paths in here */ else if( level == USE_HIST ) { len = sizeof(g_history)/sizeof(char *); for( c = 0; c < len; c++) fputs(g_history[c], stdout); } else if( level == USE_FIELD_HDR1 ) { field_s nhdr_fields[NT_HDR1_NUM_FIELDS]; /* just do it all here */ fill_hdr1_field_array(nhdr_fields); disp_field_s_list("nifti_1_header: ", nhdr_fields, NT_HDR1_NUM_FIELDS); printf(" sizeof(nifti_1_header) = %d\n", (int)sizeof(nifti_1_header)); } else if( level == USE_FIELD_HDR2 ) { field_s nhdr_fields[NT_HDR2_NUM_FIELDS]; /* just do it all here */ fill_hdr2_field_array(nhdr_fields); disp_field_s_list("nifti_2_header: ", nhdr_fields, NT_HDR2_NUM_FIELDS); printf(" sizeof(nifti_2_header) = %d\n", (int)sizeof(nifti_2_header)); } else if( level == USE_FIELD_ANA ) { field_s nhdr_fields[NT_ANA_NUM_FIELDS]; /* just do it all here */ fill_ana_field_array(nhdr_fields); disp_field_s_list("nifti_analyze75: ",nhdr_fields,NT_ANA_NUM_FIELDS); printf(" sizeof(nifti_analyze75) = %d\n", (int)sizeof(nifti_analyze75)); } else if( level == USE_FIELD_NIM1 ) { field_s nim_fields[NT_NIM_NUM_FIELDS]; fill_nim1_field_array(nim_fields); disp_field_s_list("nifti1_image: ", nim_fields, NT_NIM_NUM_FIELDS); printf(" sizeof(nifti1_image) = %d\n", (int)sizeof(nifti1_image)); } else if( level == USE_FIELD_NIM2 ) { field_s nim_fields[NT_NIM_NUM_FIELDS]; fill_nim2_field_array(nim_fields); disp_field_s_list("nifti2_image: ", nim_fields, NT_NIM_NUM_FIELDS); printf(" sizeof(nifti2_image) = %d\n", (int)sizeof(nifti2_image)); } else if( level == USE_SEE_ALSO ) fprintf(stdout, "[see also]\n" "To see the direct, originally formatted help,\n" "consider the command\n\n" " %s -help\n", prog); else if( level == USE_VERSION ) fprintf(stdout, "%s, version %s (%s)\n", prog, g_version, g_version_date); else if( level == USE_VER_MAN ) fprintf(stdout, "%s %s\n\n%s\n", prog, g_version, g_version_date); else { fprintf(stdout,"** illegal level for usage(): %d\n", level); return -1; } return 1; } /*---------------------------------------------------------------------- * full usage *----------------------------------------------------------------------*/ int use_full(void) { printf( "nifti_tool - display, modify or compare nifti headers\n" "\n" " - display, modify or compare nifti structures in datasets\n" " - copy a dataset by selecting a list of volumes from the original\n" " - copy a dataset, collapsing any dimensions, each to a single index\n" " - display a time series for a voxel, or more generally, the data\n" " from any collapsed image, in ASCII text\n"); printf( "\n" " This program can be used to display information from nifti datasets,\n" " to modify information in nifti datasets, to look for differences\n" " between two nifti datasets (like the UNIX 'diff' command), and to copy\n" " a dataset to a new one, either by restricting any dimensions, or by\n" " copying a list of volumes (the time dimension) from a dataset.\n" "\n"); printf( " Only one action type is allowed, e.g. one cannot modify a dataset\n" " and then take a 'diff'.\n" "\n"); printf( " one can display - any or all fields in the nifti_1_header structure\n" " - any or all fields in the nifti_image structure\n" " - any or all fields in the nifti_analyze75 structure\n" " - the extensions in the nifti_image structure\n" " - the time series from a 4-D dataset, given i,j,k\n" " - the data from any collapsed image, given dims. list\n" "\n"); printf( " one can check - perform internal check on the nifti_1_header struct\n" " (by nifti_hdr_looks_good())\n" " - perform internal check on the nifti_image struct\n" " (by nifti_nim_is_valid())\n" "\n"); printf( " one can modify - any or all fields in the nifti_1_header structure\n" " - any or all fields in the nifti_image structure\n" " - swap all fields in NIFTI or ANALYZE header structure\n" " add/rm - any or all extensions in the nifti_image structure\n" " remove - all extensions and descriptions from the datasets\n" "\n"); printf( " one can compare - any or all field pairs of nifti_1_header structures\n" " - any or all field pairs of nifti_image structures\n" "\n" " one can copy - an arbitrary list of dataset volumes (time points)\n" " - a dataset, collapsing across arbitrary dimensions\n" " (restricting those dimensions to the given indices)\n" "\n" " one can create - a new dataset out of nothing\n" "\n"); printf( " Note: to learn about which fields exist in either of the structures,\n" " or to learn a field's type, size of each element, or the number\n" " of elements in the field, use either the '-help_hdr' option, or\n" " the '-help_nim' option. No further options are required.\n" "\n" " See -help_hdr, -help_hdr1, -help_hdr2, -help_ana,\n" " -help_nim, -help_nim1, -help_nim2.\n" "\n" " ------------------------------\n"); printf( "\n" " usage styles:\n" "\n" " nifti_tool -help : show this help\n" " nifti_tool -help_hdr : show nifti_2_header field info\n" " nifti_tool -help_hdr1 : show nifti_1_header field info\n" " nifti_tool -help_hdr2 : show nifti_2_header field info\n" " nifti_tool -help_nim : show nifti_image (2) field info\n" " nifti_tool -help_nim1 : show nifti1_image field info\n" " nifti_tool -help_nim2 : show nifti2_image field info\n" " nifti_tool -help_ana : show nifti_analyze75 field info\n" " nifti_tool -help_datatypes : show datatype table\n" "\n"); printf( " nifti_tool -ver : show the current version\n" " nifti_tool -ver_man : show man page formatted version\n" " nifti_tool -see_also : show the 'SEE ALSO' string\n" " nifti_tool -hist : show the modification history\n" " nifti_tool -nifti_ver : show the nifti library version\n" " nifti_tool -nifti_hist : show the nifti library history\n" " nifti_tool -with_zlib : was library compiled with zlib\n" "\n" "\n"); printf( " nifti_tool -check_hdr -infiles f1 ...\n" " nifti_tool -check_nim -infiles f1 ...\n" "\n"); printf( " nifti_tool -copy_brick_list -infiles f1'[indices...]'\n" " nifti_tool -copy_collapsed_image I J K T U V W -infiles f1\n" "\n"); printf( " nifti_tool -make_im -prefix new_im.nii\n" "\n"); printf( " nifti_tool -disp_hdr [-field FIELDNAME] [...] -infiles f1 ...\n" " nifti_tool -disp_hdr1 [-field FIELDNAME] [...] -infiles f1 ...\n" " nifti_tool -disp_hdr2 [-field FIELDNAME] [...] -infiles f1 ...\n" " nifti_tool -disp_nim [-field FIELDNAME] [...] -infiles f1 ...\n" " nifti_tool -disp_ana [-field FIELDNAME] [...] -infiles f1 ...\n" " nifti_tool -disp_exts -infiles f1 ...\n" " nifti_tool -disp_cext -infiles f1 ...\n" " nifti_tool -disp_ts I J K [-dci_lines] -infiles f1 ...\n" " nifti_tool -disp_ci I J K T U V W [-dci_lines] -infiles f1 ...\n" "\n"); printf( " nifti_tool -mod_hdr [-mod_field FIELDNAME NEW_VAL] [...] -infiles f1\n" " nifti_tool -mod_hdr2 [-mod_field FIELDNAME NEW_VAL] [...] -infiles f1\n" " nifti_tool -mod_nim [-mod_field FIELDNAME NEW_VAL] [...] -infiles f1\n" "\n" " nifti_tool -swap_as_nifti -overwrite -infiles f1\n" " nifti_tool -swap_as_analyze -overwrite -infiles f1\n" " nifti_tool -swap_as_old -overwrite -infiles f1\n" "\n"); printf( " nifti_tool -add_afni_ext 'extension in quotes' [...] -infiles f1\n" " nifti_tool -add_comment_ext 'extension in quotes' [...] -infiles f1\n" " nifti_tool -add_comment_ext 'file:FILENAME' [...] -infiles f1\n" " nifti_tool -rm_ext INDEX [...] -infiles f1 ...\n" " nifti_tool -strip_extras -infiles f1 ...\n" "\n"); printf( " nifti_tool -diff_hdr [-field FIELDNAME] [...] -infiles f1 f2\n" " nifti_tool -diff_hdr1 [-field FIELDNAME] [...] -infiles f1 f2\n" " nifti_tool -diff_hdr2 [-field FIELDNAME] [...] -infiles f1 f2\n" " nifti_tool -diff_nim [-field FIELDNAME] [...] -infiles f1 f2\n" "\n" " ------------------------------\n"); printf( "\n" " selected examples:\n" "\n" " A. checks header (for problems):\n" "\n" " 1. nifti_tool -check_hdr -infiles dset0.nii dset1.nii\n" " 2. nifti_tool -check_hdr -infiles *.nii *.hdr\n" " 3. nifti_tool -check_hdr -quiet -infiles *.nii *.hdr\n" "\n"); printf( " B. show header differences:\n" "\n" " 1. nifti_tool -diff_hdr -infiles dset0.nii dset1.nii \n" " 2. nifti_tool -diff_hdr1 -infiles dset0.nii dset1.nii \n" " 3. nifti_tool -diff_hdr2 -field dim -field intent_code \\\n" " -infiles dset0.nii dset1.nii \n" " 4. nifti_tool -diff_hdr1 -new_dims 3 10 20 30 0 0 0 0 \\\n" " -infiles my_dset.nii MAKE_IM \n" "\n" " C. display structures or fields:\n" "\n"); printf( " 1. nifti_tool -disp_hdr -infiles dset0.nii dset1.nii dset2.nii\n" " 2. nifti_tool -disp_hdr1 -field dim -field descrip -infiles dset.nii\n" " 3. nifti_tool -disp_hdr2 -field dim -field descrip -infiles dset.nii\n" " 4. nifti_tool -disp_exts -infiles dset0.nii dset1.nii dset2.nii\n" " 5. nifti_tool -disp_cext -infiles dset0.nii dset1.nii dset2.nii\n" " 6. nifti_tool -disp_ts 23 0 172 -infiles dset1_time.nii\n" " 7. nifti_tool -disp_ci 23 0 172 -1 0 0 0 -infiles dset1_time.nii\n" "\n"); printf( " 8. nifti_tool -disp_ana -infiles analyze.hdr\n" " 9. nifti_tool -disp_nim -infiles nifti.nii\n" " 10. nifti_tool -disp_hdr -field HDR_SLICE_TIMING_FIELDS \\\n" " -infiles epi.nii\n" " 11. nifti_tool -disp_hdr -field NIM_SLICE_TIMING_FIELDS \\\n" " -infiles epi.nii\n" "\n"); printf( " D. create a new dataset from nothing:\n" "\n" " 1. nifti_tool -make_im -prefix new_im.nii \n" " 2. nifti_tool -make_im -prefix float_im.nii \\\n" " -new_dims 3 10 20 30 0 0 0 0 -new_datatype 16\n"); printf( " 3. nifti_tool -mod_hdr -mod_field descrip 'dataset with mods' \\\n" " -new_dims 3 10 20 30 0 0 0 0 \\\n" " -prefix new_desc.nii -infiles MAKE_IM\n" "\n"); printf("\n" " 4. Given a raw data file VALS.dat of 80x40x20 floats, with\n" " grid spacing 0.5mm x 1mm x 2mm, make a 2-file NIFTI dataset\n" " and overwrite the all-zero data with 'VALS.dat'.\n" " Use -mod_hdr to specify that the output type is 2-files.\n\n" " nifti_tool -infiles MAKE_IM -prefix newdata.hdr \\\n" " -new_dims 3 80 40 20 0 0 0 0 \\\n" " -new_datatype 16 \\\n" " -mod_hdr -mod_field pixdim '1 0.5 1 2 1 1 1 1' \\\n" " -mod_hdr -mod_field magic ni1\n\n" " cp VALS.dat newdata.img\n" "\n"); printf( " E. copy dataset, brick list or collapsed image:\n" "\n" " 0. nifti_tool -copy_image -prefix new.nii -infiles dset0.nii\n" " 1. nifti_tool -cbl -prefix new.nii -infiles dset0.nii\n" " 2. nifti_tool -cbl -prefix new_07.nii -infiles dset0.nii'[0,7]'\n" " 3. nifti_tool -cbl -prefix new_partial.nii \\\n" " -infiles dset0.nii'[3..$(2)]'\n" "\n" " 4. nifti_tool -cci 5 4 17 -1 -1 -1 -1 -prefix new_5_4_17.nii\n" " 5. nifti_tool -cci 5 0 17 -1 -1 2 -1 -keep_hist \\\n" " -prefix new_5_0_17_2.nii\n" "\n"); printf( " F. modify the header (modify fields or swap entire header):\n" "\n" " 1. nifti_tool -mod_hdr -prefix dnew -infiles dset0.nii \\\n" " -mod_field dim '4 64 64 20 30 1 1 1 1'\n" " 2. nifti_tool -mod_hdr2 -prefix dnew -infiles dset2.nii \\\n" " -mod_field dim '4 64 64 20 30 1 1 1 1'\n" " 3. nifti_tool -mod_hdr -prefix dnew -infiles dset0.nii \\\n" " -mod_field descrip 'beer, brats and cheese, mmmmm...'\n" ); printf( " 3. cp old_dset.hdr nifti_swap.hdr \n" " nifti_tool -swap_as_nifti -overwrite -infiles nifti_swap.hdr\n" " 4. cp old_dset.hdr analyze_swap.hdr \n" " nifti_tool -swap_as_analyze -overwrite -infiles analyze_swap.hdr\n" " 5. nifti_tool -swap_as_old -prefix old_swap.hdr -infiles old_dset.hdr\n" " nifti_tool -diff_hdr1 -infiles nifti_swap.hdr old_swap.hdr\n" "\n"); printf( " G. strip, add or remove extensions:\n" " (in example #3, the extension is copied from a text file)\n" "\n" "\n" " 1. nifti_tool -strip_extras -overwrite -infiles *.nii\n" " 2. nifti_tool -add_comment 'converted from MY_AFNI_DSET+orig' \\\n" " -prefix dnew -infiles dset0.nii\n" ); printf( " 3. nifti_tool -add_comment 'file:my.extension.txt' \\\n" " -prefix dnew -infiles dset0.nii\n" " 4. nifti_tool -rm_ext ALL -prefix dset1 -infiles dset0.nii\n" " 5. nifti_tool -rm_ext 2 -rm_ext 3 -rm_ext 5 -overwrite \\\n" " -infiles dset0.nii\n" "\n"); printf( " H. convert to a different datatype (from whatever is there):\n" " (possibly warn or fail if conversion is not perfect)\n" "\n" " 0. nifti_tool -copy_image -prefix copy.nii -infiles dset0.nii\n" " 1. nifti_tool -copy_image -infiles dset0.nii \\\n" " -prefix copy_f32.nii \\\n" " -convert2dtype NIFTI_TYPE_FLOAT32 \\\n" " -convert_fail_choice warn\n" " 2. nifti_tool -copy_image -infiles dset0.nii \\\n" " -prefix copy_i32.nii \\\n" " -convert2dtype NIFTI_TYPE_INT32 \\\n" " -convert_fail_choice fail\n" "\n" ); printf(" ------------------------------\n"); printf( "\n" " options for check actions:\n" "\n"); printf( " -check_hdr : check for a valid nifti_1_header struct\n" "\n" " This action is used to check the nifti_1_header structure for\n" " problems. The nifti_hdr_looks_good() function is used for the\n" " test, and currently checks:\n" " \n" " dim[], sizeof_hdr, magic, datatype\n" " \n" " More tests can be requested of the author.\n" "\n"); printf( " e.g. perform checks on the headers of some datasets\n" " nifti_tool -check_hdr -infiles dset0.nii dset1.nii\n" " nifti_tool -check_hdr -infiles *.nii *.hdr\n" " \n" " e.g. add the -quiet option, so that only errors are reported\n" " nifti_tool -check_hdr -quiet -infiles *.nii *.hdr\n" "\n"); printf( " -check_nim : check for a valid nifti_image struct\n" "\n" " This action is used to check the nifti_image structure for\n" " problems. This is tested via both nifti_convert_n1hdr2nim()\n" " and nifti_nim_is_valid(), though other functions are called\n" " below them, of course. Current checks are:\n" "\n"); printf( " dim[], sizeof_hdr, datatype, fname, iname, nifti_type\n" " \n" " Note that creation of a nifti_image structure depends on good\n" " header fields. So errors are terminal, meaning this check would\n" " probably report at most one error, even if more exist. The\n" " -check_hdr action is more complete.\n" "\n"); printf( " More tests can be requested of the author.\n" "\n"); printf( " e.g. nifti_tool -check_nim -infiles dset0.nii dset1.nii\n" " e.g. nifti_tool -check_nim -infiles *.nii *.hdr\n" "\n"); printf( " ------------------------------\n"); printf( "\n" " options for create action:\n" "\n"); printf( " -make_im : create a new dataset from nothing\n" "\n" " With this the user can create a new dataset of a basic style,\n" " which can then be modified with other options. This will create\n" " zero-filled data of the appropriate size.\n" " \n"); printf( " The default is a 1x1x1 image of shorts. These settings can be\n" " modified with the -new_dim option, to set the 8 dimension values,\n" " and the -new_datatype, to provide the integral type for the data.\n" "\n"); printf( " See -new_dim, -new_datatype and -infiles for more information.\n" " \n" " Note that any -infiles dataset of the name MAKE_IM will also be\n" " created on the fly.\n" "\n"); printf( " -new_dim D0 .. D7 : specify the dim array for the a new dataset.\n" "\n" " e.g. -new_dim 4 64 64 27 120 0 0 0\n" "\n" " This dimension list will apply to any dataset created via\n" " MAKE_IM or -make_im. All 8 values are required. Recall that\n" " D0 is the number of dimensions, and D1 through D7 are the sizes.\n" " \n"); printf( " -new_datatype TYPE : specify the dim array for the a new dataset.\n" "\n" " e.g. -new_datatype 16\n" " default: -new_datatype 4 (short)\n" "\n" " This dimension list will apply to any dataset created via\n" " MAKE_IM or -make_im. TYPE should be one of the NIFTI_TYPE_*\n" " numbers, from nifti1.h.\n" " \n"); printf( " ------------------------------\n"); printf( "\n" " options for copy actions:\n" "\n"); printf( " -copy_image : copy a NIFTI dataset to a new one\n" "\n" " This basic action allows the user to copy a dataset to a new one.\n" "\n" " This offers a more pure NIFTI I/O copy, while still allowing for\n" " options like alteration of the datatype.\n" "\n"); printf( " -convert2dtype TYPE : convert input dset to given TYPE\n" "\n" " This option allows one to convert the data to a new datatype\n" " upon read. If both the input and new types are valid, the\n" " the conversion will be attempted.\n" "\n" " As values cannot always be copied correctly, one should decide\n" " what to do in case of a conversion error. To control response\n" " to a conversion error, consider options -convert_verify and\n" " -convert_fail_choice.\n" "\n"); printf( " For example, converting NIFTI_TYPE_FLOAT32 to NIFTI_TYPE_UINT16,\n" " a value of 53000.0 would exceed the maximum short, while 7.25\n" " could not be exactly represented as a short.\n" "\n"); printf( " Valid TYPE values include all NIFTI types, except for\n" " FLOAT128 and any RGB or COMPLEX one.\n" "\n" " For a list of potential values for TYPE, see the output from:\n" " nifti_tool -help_datatypes\n" "\n" " See also -convert_verify, -convert_fail_choice\n" "\n"); printf( " -convert_fail_choice CHOICE : set what to do on conversion failures\n" "\n" " Used with -convert2dtype and -convert_verify, this option\n" " specifies how to behave when a datatype conversion is not exact\n" " (e.g. 7.25 converted to a short integer would be 7).\n" "\n" " Valid values for CHOICE are:\n" " ignore : just let the failures happen\n" " warn : warn about errors, but still convert\n" " fail : bad conversions are terminal failures\n" "\n" " This option implies -convert_verify, so they are not both needed.\n" "\n" " See also -convert2dtype, -convert_verify\n" "\n"); printf( " -convert_verify : verify that conversions were exact\n" "\n" " Used with -convert2dtype, this option specifies that any\n" " conversions should be verified for exactness. What to do in the\n" " case of a bad conversion is controlled by -convert_fail_choice,\n" " with a default of warning.\n" "\n" " See also -convert2dtype, -convert_fail_choice\n" "\n"); printf( " -copy_brick_list : copy a list of volumes to a new dataset\n" " -cbl : (a shorter, alternative form)\n" "\n"); printf( " This action allows the user to copy a list of volumes (over time)\n" " from one dataset to another. The listed volumes can be in any\n" " order and contain repeats, but are of course restricted to\n" " the set of values {1, 2, ..., nt-1}, from dimension 4.\n" "\n"); printf( " This option is a flag. The index list is specified with the input\n" " dataset, contained in square brackets. Note that square brackets\n" " are special to most UNIX shells, so they should be contained\n" " within single quotes. Syntax of an index list:\n" "\n" " notes:\n" "\n"); printf( " - indices start at zero\n" " - indices end at nt-1, which has the special symbol '$'\n" " - single indices should be separated with commas, ','\n" " e.g. -infiles dset0.nii'[0,3,8,5,2,2,2]'\n" " - ranges may be specified using '..' or '-' \n"); printf( " e.g. -infiles dset0.nii'[2..95]'\n" " e.g. -infiles dset0.nii'[2..$]'\n" " - ranges may have step values, specified in ()\n" " example: 2 through 95 with a step of 3, i.e. {2,5,8,11,...,95}\n" " e.g. -infiles dset0.nii'[2..95(3)]'\n" "\n"); printf( " e.g. to copy sub-bricks 0 and 7:\n" " nifti_tool -cbl -prefix new_07.nii -infiles dset0.nii'[0,7]'\n" "\n" " e.g. to copy an entire dataset:\n" " nifti_tool -cbl -prefix new_all.nii -infiles dset0.nii'[0..$]'\n" "\n"); printf( " e.g. to copy every other time point, skipping the first three:\n" " nifti_tool -cbl -prefix new_partial.nii \\\n" " -infiles dset0.nii'[3..$(2)]'\n" "\n" "\n" " -copy_collapsed_image ... : copy a list of volumes to a new dataset\n" " -cci I J K T U V W : (a shorter, alternative form)\n" "\n"); printf( " This action allows the user to copy a collapsed dataset, where\n" " some dimensions are collapsed to a given index. For instance, the\n" " X dimension could be collapsed to i=42, and the time dimensions\n" " could be collapsed to t=17. To collapse a dimension, set Di to\n" " the desired index, where i is in {0..ni-1}. Any dimension that\n" " should not be collapsed must be listed as -1.\n" "\n"); printf( " Any number (of valid) dimensions can be collapsed, even down to a\n" " a single value, by specifying enough valid indices. The resulting\n" " dataset will then have a reduced number of non-trivial dimensions.\n" "\n" " Assume dset0.nii has nim->dim[8] = { 4, 64, 64, 21, 80, 1, 1, 1 }.\n" " Note that this is a 4-dimensional dataset.\n" "\n"); printf( " e.g. copy the time series for voxel i,j,k = 5,4,17\n" " nifti_tool -cci 5 4 17 -1 -1 -1 -1 -prefix new_5_4_17.nii\n" "\n" " e.g. read the single volume at time point 26\n" " nifti_tool -cci -1 -1 -1 26 -1 -1 -1 -prefix new_t26.nii\n" "\n"); printf( " Assume dset1.nii has nim->dim[8] = { 6, 64, 64, 21, 80, 4, 3, 1 }.\n" " Note that this is a 6-dimensional dataset.\n" "\n" " e.g. copy all time series for voxel i,j,k = 5,0,17, with v=2\n" " (and add the command to the history)\n" " nifti_tool -cci 5 0 17 -1 -1 2 -1 -keep_hist \\\n" " -prefix new_5_0_17_2.nii\n" "\n"); printf( " e.g. copy all data where i=3, j=19 and v=2\n" " (I do not claim to know a good reason to do this)\n" " nifti_tool -cci 3 19 -1 -1 -1 2 -1 -prefix new_mess.nii\n" "\n" " See '-disp_ci' for more information (which displays/prints the\n" " data, instead of copying it to a new dataset).\n" "\n" " ------------------------------\n"); printf( "\n" " options for display actions:\n" "\n" " -disp_hdr : display nifti_*_header fields for datasets\n" "\n" " This flag means the user wishes to see some of the nifti_*_header\n" " fields in one or more nifti datasets. The user may want to specify\n" " multiple '-field' options along with this. This option requires\n" " one or more files input, via '-infiles'.\n" "\n" " This displays the header in its native format.\n" "\n"); printf( " If no '-field' option is present, all fields will be displayed.\n" " Using '-field HDR_SLICE_TIMING_FIELDS' will include header fields\n" " related to slice timing.\n" " Using '-field NIM_SLICE_TIMING_FIELDS' will include nifti_image\n" " fields related to slice timing.\n" "\n" " e.g. to display the contents of all fields:\n" " nifti_tool -disp_hdr -infiles dset0.nii\n" " nifti_tool -disp_hdr -infiles dset0.nii dset1.nii dset2.nii\n" "\n" " e.g. to display the contents of select fields:\n" " nifti_tool -disp_hdr -field dim -infiles dset0.nii\n" " nifti_tool -disp_hdr -field dim -field descrip -infiles dset0.nii\n" "\n" " e.g. a special case to display slice timing fields:\n" " nifti_tool -disp_hdr -field HDR_SLICE_TIMING_FIELDS \n" " -infiles dset0.nii\n" "\n"); printf( "\n" " -disp_hdr1 : display nifti_1_header fields for datasets\n" "\n" " Like -disp_hdr, but only display NIFTI-1 format.\n" "\n" " This attempts to convert other NIFTI versions to NIFTI-1.\n" "\n"); printf( "\n" " -disp_hdr2 : display nifti_2_header fields for datasets\n" "\n" " Like -disp_hdr, but only display NIFTI-2 format.\n" "\n" " This attempts to convert other NIFTI versions to NIFTI-2.\n" "\n"); printf( " -disp_nim : display nifti_image fields for datasets\n" "\n" " This flag option works the same way as the '-disp_hdr' option,\n" " except that the fields in question are from the nifti_image\n" " structure.\n" "\n" " e.g. a special case to display slice timing fields:\n" " nifti_tool -disp_nim -field NIM_SLICE_TIMING_FIELDS \n" " -infiles dset0.nii\n" "\n"); printf( " -disp_ana : display nifti_analyze75 fields for datasets\n" "\n" " This flag option works the same way as the '-disp_hdr' option,\n" " except that the fields in question are from the nifti_analyze75\n" " structure.\n" "\n"); printf( " -disp_cext : display CIFTI-type extensions\n" "\n" " This flag option is used to display all CIFTI extension data.\n" "\n"); printf( " -disp_exts : display all AFNI-type extensions\n" "\n" " This flag option is used to display all nifti_1_extension data,\n" " for extensions of type AFNI (4), COMMENT (6) or CIFTI (32).\n" "\n"); printf( " e.g. to display the extensions in datasets:\n" " nifti_tool -disp_exts -infiles dset0.nii\n" " nifti_tool -disp_exts -infiles dset0.nii dset1.nii dset2.nii\n" "\n"); printf( " -disp_ts I J K : display ASCII time series at i,j,k = I,J,K\n" "\n" " This option is used to display the time series data for the voxel\n" " at i,j,k indices I,J,K. The data is displayed in text, either all\n" " on one line (the default), or as one number per line (via the\n" " '-dci_lines' option).\n" "\n"); printf( " Notes:\n" "\n" " o This function applies only to 4-dimensional datasets.\n" " o The '-quiet' option can be used to suppress the text header,\n" " leaving only the data.\n" " o This option is short for using '-disp_ci' (display collapsed\n" " image), restricted to 4-dimensional datasets. i.e. :\n" " -disp_ci I J K -1 -1 -1 -1\n" "\n"); printf( " e.g. to display the time series at voxel 23, 0, 172:\n" " nifti_tool -disp_ts 23 0 172 -infiles dset1_time.nii\n" " nifti_tool -disp_ts 23 0 172 -dci_lines -infiles dset1_time.nii\n" " nifti_tool -disp_ts 23 0 172 -quiet -infiles dset1_time.nii\n" "\n"); printf( " -disp_collapsed_image : display ASCII values for collapsed dataset\n" " -disp_ci I J K T U V W : (a shorter, alternative form)\n" "\n" " This option is used to display all of the data from a collapsed\n" " image, given the dimension list. The data is displayed in text,\n" " either all on one line (the default), or as one number per line\n" " (by using the '-dci_lines' flag).\n" "\n"); printf( " The '-quiet' option can be used to suppress the text header.\n" "\n" " e.g. to display the time series at voxel 23, 0, 172:\n" " nifti_tool -disp_ci 23 0 172 -1 0 0 0 -infiles dset1_time.nii\n" "\n" " e.g. to display z-slice 14, at time t=68:\n" " nifti_tool -disp_ci -1 -1 14 68 0 0 0 -infiles dset1_time.nii\n" "\n" " See '-ccd' for more information, which copies such data to a new\n" " dataset, instead of printing it to the terminal window.\n" "\n" " ------------------------------\n"); printf( "\n" " options for modification actions:\n" "\n" " -mod_hdr : modify nifti_1_header fields for datasets\n" "\n" " This action is used to modify some of the nifti_1_header fields in\n" " one or more datasets. The user must specify a list of fields to\n" " modify via one or more '-mod_field' options, which include field\n" " names, along with the new (set of) values.\n" "\n"); printf( " The user can modify a dataset in place, or use '-prefix' to\n" " produce a new dataset, to which the changes have been applied.\n" " It is recommended to normally use the '-prefix' option, so as not\n" " to ruin a dataset.\n" "\n"); printf( " Note that some fields have a length greater than 1, meaning that\n" " the field is an array of numbers, or a string of characters. In\n" " order to modify an array of numbers, the user must provide the\n" " correct number of values, and contain those values in quotes, so\n" " that they are seen as a single option.\n" "\n"); printf( " To modify a string field, put the string in quotes.\n" "\n" " The '-mod_field' option takes a field_name and a list of values.\n" "\n" " e.g. to modify the contents of various fields:\n" "\n"); printf( " nifti_tool -mod_hdr -prefix dnew -infiles dset0.nii \\\n" " -mod_field qoffset_x -17.325\n" " nifti_tool -mod_hdr -prefix dnew -infiles dset0.nii \\\n" " -mod_field dim '4 64 64 20 30 1 1 1 1'\n" " nifti_tool -mod_hdr -prefix dnew -infiles dset0.nii \\\n" " -mod_field descrip 'beer, brats and cheese, mmmmm...'\n" "\n"); printf( " e.g. to modify the contents of multiple fields:\n" " nifti_tool -mod_hdr -prefix dnew -infiles dset0.nii \\\n" " -mod_field qoffset_x -17.325 -mod_field slice_start 1\n" "\n" " e.g. to modify the contents of multiple files (must overwrite):\n" " nifti_tool -mod_hdr -overwrite -mod_field qoffset_x -17.325 \\\n" " -infiles dset0.nii dset1.nii\n" "\n"); printf( " -mod_hdr2 : modify nifti_2_header fields for datasets\n" "\n" " This action option is like -mod_hdr, except that this -mod_hdr2\n" " option applies to NIFTI-2 datasets, while -mod_hdr applies to\n" " NIFTI-1 datasets.\n" "\n" " The same -mod_field options are then applied to specify changes.\n" "\n"); printf( " -mod_nim : modify nifti_image fields for datasets\n" "\n" " This action option is used the same way that '-mod_hdr' is used,\n" " except that the fields in question are from the nifti_image\n" " structure.\n" "\n"); printf( " -strip_extras : remove extensions and descriptions from datasets\n" "\n" " This action is used to attempt to 'clean' a dataset of general\n" " text, in order to make it more anonymous. Extensions and the\n" " nifti_image descrip field are cleared by this action.\n" "\n"); printf( " e.g. to strip all *.nii datasets in this directory:\n" " nifti_tool -strip_extras -overwrite -infiles *.nii\n" "\n"); printf( " -swap_as_nifti : swap the header according to nifti_1_header\n" "\n" " Perhaps a NIfTI header is mal-formed, and the user explicitly\n" " wants to swap it before performing other operations. This action\n" " will swap the field bytes under the assumption that the header is\n" " in the NIfTI format.\n" "\n"); printf( " ** The recommended course of action is to make a copy of the\n" " dataset and overwrite the header via -overwrite. If the header\n" " needs such an operation, it is likely that the data would not\n" " otherwise be read in correctly.\n" "\n"); printf( " -swap_as_analyze : swap the header according to nifti_analyze75\n" "\n" " Perhaps an ANALYZE header is mal-formed, and the user explicitly\n" " wants to swap it before performing other operations. This action\n" " will swap the field bytes under the assumption that the header is\n" " in the ANALYZE 7.5 format.\n" "\n"); printf( " ** The recommended course of action is to make a copy of the\n" " dataset and overwrite the header via -overwrite. If the header\n" " needs such an operation, it is likely that the data would not\n" " otherwise be read in correctly.\n" "\n"); printf( " -swap_as_old : swap the header using the old method\n" "\n" " As of library version 1.35 (3 Aug, 2008), nifticlib now swaps all\n" " fields of a NIfTI dataset (including UNUSED ones), and it swaps\n" " ANALYZE datasets according to the nifti_analyze75 structure.\n" " This is a significant different in the case of ANALYZE datasets.\n" "\n"); printf( " The -swap_as_old option was added to compare the results of the\n" " swapping methods, or to undo one swapping method and replace it\n" " with another (such as to undo the old method and apply the new).\n" "\n"); printf(" ------------------------------\n"); printf( "\n" " options for adding/removing extensions:\n" "\n" " -add_afni_ext EXT : add an AFNI extension to the dataset\n" "\n" " This option is used to add AFNI-type extensions to one or more\n" " datasets. This option may be used more than once to add more than\n" " one extension.\n" "\n" " If EXT is of the form 'file:FILENAME', then the extension will\n" " be read from the file, FILENAME.\n" "\n"); printf( " The '-prefix' option is recommended, to create a new dataset.\n" " In such a case, only a single file may be taken as input. Using\n" " '-overwrite' allows the user to overwrite the current file, or\n" " to add the extension(s) to multiple files, overwriting them.\n" "\n"); printf( " e.g. to add a generic AFNI extension:\n" " nifti_tool -add_afni_ext 'wow, my first extension' -prefix dnew \\\n" " -infiles dset0.nii\n" "\n" " e.g. to add multiple AFNI extensions:\n" " nifti_tool -add_afni_ext 'wow, my first extension :)' \\\n" " -add_afni_ext 'look, my second...' \\\n" " -prefix dnew -infiles dset0.nii\n" "\n"); printf( " e.g. to add an extension, and overwrite the dataset:\n" " nifti_tool -add_afni_ext 'some AFNI extension' -overwrite \\\n" " -infiles dset0.nii dset1.nii \n" "\n"); printf( " -add_comment_ext EXT : add a COMMENT extension to the dataset\n" "\n" " This option is used to add COMMENT-type extensions to one or more\n" " datasets. This option may be used more than once to add more than\n" " one extension. This option may also be used with '-add_afni_ext'.\n" "\n" " If EXT is of the form 'file:FILENAME', then the extension will\n" " be read from the file, FILENAME.\n" "\n"); printf( " The '-prefix' option is recommended, to create a new dataset.\n" " In such a case, only a single file may be taken as input. Using\n" " '-overwrite' allows the user to overwrite the current file, or\n" " to add the extension(s) to multiple files, overwriting them.\n" "\n"); printf( " e.g. to add a comment about the dataset:\n" " nifti_tool -add_comment 'converted from MY_AFNI_DSET+orig' \\\n" " -prefix dnew \\\n" " -infiles dset0.nii\n" "\n"); printf( " e.g. to add multiple extensions:\n" " nifti_tool -add_comment 'add a comment extension' \\\n" " -add_afni_ext 'and an AFNI XML style extension' \\\n" " -add_comment 'dataset copied from dset0.nii' \\\n" " -prefix dnew -infiles dset0.nii\n" "\n"); printf( " -rm_ext INDEX : remove the extension given by INDEX\n" "\n" " This option is used to remove any single extension from the\n" " dataset. Multiple extensions require multiple options.\n" "\n" " notes - extension indices begin with 0 (zero)\n" " - to view the current extensions, see '-disp_exts'\n" " - all extensions can be removed using ALL or -1 for INDEX\n" "\n"); printf( " e.g. to remove the extension #0:\n" " nifti_tool -rm_ext 0 -overwrite -infiles dset0.nii\n" "\n" " e.g. to remove ALL extensions:\n" " nifti_tool -rm_ext ALL -prefix dset1 -infiles dset0.nii\n" " nifti_tool -rm_ext -1 -prefix dset1 -infiles dset0.nii\n" "\n"); printf( " e.g. to remove the extensions #2, #3 and #5:\n" " nifti_tool -rm_ext 2 -rm_ext 3 -rm_ext 5 -overwrite \\\n" " -infiles dset0.nii\n" "\n" " ------------------------------\n"); printf( "\n" " options for showing differences:\n" "\n" " -diff_hdr : display header field diffs between two datasets\n" "\n" " This option is used to find differences between two NIFTI-*\n" " dataset headers. If any fields are different, the contents of\n" " those fields are displayed (unless the '-quiet' option is used).\n" "\n" " The NIFTI versions must agree.\n" "\n" " -diff_hdr1 : display header diffs between NIFTI-1 datasets\n" "\n" " This option is used to find differences between two NIFTI-1\n" " dataset headers.\n" "\n" " -diff_hdr2 : display header diffs between NIFTI-2 datasets\n" "\n" " This option is used to find differences between two NIFTI-2\n" " dataset headers.\n" "\n"); printf( " A list of fields can be specified by using multiple '-field'\n" " options. If no '-field' option is given, all fields will be\n" " checked.\n" "\n" " Exactly two dataset names must be provided via '-infiles'.\n" "\n" " e.g. to display all nifti_2_header field differences:\n" " nifti_tool -diff_hdr2 -infiles dset0.nii dset1.nii\n" "\n"); printf( " e.g. to display selected field differences:\n" " nifti_tool -diff_hdr -field dim -field intent_code \\\n" " -infiles dset0.nii dset1.nii \n" "\n" " -diff_nim : display nifti_image field diffs between datasets\n" "\n" " This option works the same as '-diff_hdr', except that the fields\n" " in question are from the nifti_image structure.\n" "\n" " ------------------------------\n"); printf( "\n" " miscellaneous options:\n" "\n" " -debug LEVEL : set the debugging level\n" "\n" " Level 0 will attempt to operate with no screen output, but errors.\n" " Level 1 is the default.\n" " Levels 2 and 3 give progressively more information.\n" "\n" " e.g. -debug 2\n" "\n"); printf( " -field FIELDNAME : provide a field to work with\n" "\n" " This option is used to provide a field to display, modify or\n" " compare. This option can be used along with one of the action\n" " options presented above.\n" "\n" " Special cases of FIELDNAME that translate to lists of fields:\n" "\n" " HDR_SLICE_TIMING_FIELDS : fields related to slice timing\n" "\n" " slice_code : code for slice acquisition order\n" " slice_start : first slice applying to slice_code\n" " slice_end : last slice applying to slice_code\n" " slice_duration : time to acquire one slice\n" " dim_info : slice/phase/freq_dim (2+2+2 lower bits)\n" " dim : dimensions of data\n" " pixdim : grid/dimension spacing (e.g. time)\n" " xyzt_units : time/space units for pixdim (3+3 bits)\n" "\n" " See '-disp_hdr', above, for complete examples.\n" "\n" " HDR_SLICE_TIMING_FIELDS : fields related to slice timing\n" "\n" " slice_code : code for slice acquisition order\n" " slice_start : first slice applying to slice_code\n" " slice_end : last slice applying to slice_code\n" " slice_duration : time to acquire one slice\n" " slice_dim : slice dimension (unset or in 1,2,3)\n" " phase_dim : phase dimension (unset or in 1,2,3)\n" " freq_dim : freq dimension (unset or in 1,2,3)\n" " dim : dimensions of data\n" " pixdim : grid/dimension spacing (e.g. time)\n" " xyzt_units : time/space units for pixdim (3+3 bits)\n" "\n" " See '-disp_nim', above, for complete examples.\n" "\n" " e.g. nifti_tool -field descrip\n" " e.g. nifti_tool -field descrip -field dim\n" "\n"); printf( " -infiles file0... : provide a list of files to work with\n" "\n" " This parameter is required for any of the actions, in order to\n" " provide a list of files to process. If input filenames do not\n" " have an extension, the directory we be searched for any\n" " appropriate files (such as .nii or .hdr).\n" "\n"); printf( " Note: if the filename has the form MAKE_IM, then a new dataset\n" " will be created, without the need for file input.\n" "\n"); printf( " See '-mod_hdr', above, for complete examples.\n" "\n" " e.g. nifti_tool -infiles file0.nii\n" " e.g. nifti_tool -infiles file1.nii file2 file3.hdr\n" "\n"); printf( " -mod_field NAME 'VALUE_LIST' : provide new values for a field\n" "\n" " This parameter is required for any the modification actions.\n" " If the user wants to modify any fields of a dataset, this is\n" " where the fields and values are specified.\n" "\n"); printf( " NAME is a field name (in either the nifti_1_header structure or\n" " the nifti_image structure). If the action option is '-mod_hdr',\n" " then NAME must be the name of a nifti_1_header field. If the\n" " action is '-mod_nim', NAME must be from a nifti_image structure.\n" "\n"); printf( " VALUE_LIST must be one or more values, as many as are required\n" " for the field, contained in quotes if more than one is provided.\n" "\n" " Use 'nifti_tool -help_hdr' to get a list of nifti_2_header fields\n" " Use 'nifti_tool -help_hdr1' to get a list of nifti_1_header fields\n" " Use 'nifti_tool -help_hdr2' to get a list of nifti_2_header fields\n" " Use 'nifti_tool -help_nim' to get a list of nifti_image fields\n" " Use 'nifti_tool -help_nim1' to get a list of nifti1_image fields\n" " Use 'nifti_tool -help_nim2' to get a list of nifti2_image fields\n" " Use 'nifti_tool -help_ana' to get a list of nifti_analyze75 fields\n" "\n" " See '-mod_hdr', above, for complete examples.\n" "\n"); printf( " e.g. modifying nifti_1_header fields:\n" " -mod_field descrip 'toga, toga, toga'\n" " -mod_field qoffset_x 19.4 -mod_field qoffset_z -11\n" " -mod_field pixdim '1 0.9375 0.9375 1.2 1 1 1 1'\n" "\n"); printf( " -keep_hist : add the command as COMMENT (to the 'history')\n" "\n" " When this option is used, the current command will be added\n" " as a NIFTI_ECODE_COMMENT type extension. This provides the\n" " ability to keep a history of commands affecting a dataset.\n" "\n" " e.g. -keep_hist\n" "\n"); printf( " -overwrite : any modifications will be made to input files\n" "\n" " This option is used so that all field modifications, including\n" " extension additions or deletions, will be made to the files that\n" " are input.\n" "\n"); printf( " In general, the user is recommended to use the '-prefix' option\n" " to create new files. But if overwriting the contents of the\n" " input files is preferred, this is how to do it.\n" "\n" " See '-mod_hdr' or '-add_afni_ext', above, for complete examples.\n" "\n" " e.g. -overwrite\n" "\n"); printf( " -prefix : specify an output file to write change into\n" "\n" " This option is used to specify an output file to write, after\n" " modifications have been made. If modifications are being made,\n" " then either '-prefix' or '-overwrite' is required.\n" "\n" " If no extension is given, the output extension will be '.nii'.\n" "\n"); printf( " e.g. -prefix new_dset\n" " e.g. -prefix new_dset.nii\n" " e.g. -prefix new_dset.hdr\n" "\n" " -quiet : report only errors or requested information\n" "\n" " This option is equivalent to '-debug 0'.\n" "\n" " ------------------------------\n"); printf( "\n" " basic help options:\n" "\n" " -help : show this help\n" "\n" " e.g. nifti_tool -help\n" "\n" " -help_hdr : show nifti_2_header field info\n" "\n" " e.g. nifti_tool -help_hdr\n" "\n" " -help_hdr1 : show nifti_1_header field info\n" "\n" " e.g. nifti_tool -help_hdr1\n" "\n" " -help_hdr2 : show nifti_2_header field info\n" "\n" " e.g. nifti_tool -help_hdr2\n" "\n" " -help_nim : show nifti_image field info (currently NIFTI-2)\n" "\n" " e.g. nifti_tool -help_nim\n" "\n" " -help_nim1 : show nifti1_image field info\n" "\n" " e.g. nifti_tool -help_nim1\n" "\n" " -help_nim2 : show nifti2_image field info\n" "\n" " e.g. nifti_tool -help_nim2\n" "\n" " -help_ana : show nifti_analyze75 field info\n" "\n" " e.g. nifti_tool -help_ana\n" ); printf( "\n" " -help_datatypes [TYPE] : display datatype table\n" "\n" " e.g. nifti_tool -help_datatypes\n" " e.g. nifti_tool -help_datatypes N\n" "\n" " This displays the contents of the nifti_type_list table.\n" " An additional 'D' or 'N' parameter will restrict the type\n" " name to 'DT_' or 'NIFTI_TYPE_' names, 'T' will test.\n"); printf( "\n" " -ver : show the program version number\n" "\n" " e.g. nifti_tool -ver\n" "\n" " -ver_man : show the version, formatted for a man page\n" "\n" " e.g. nifti_tool -ver_man\n" "\n" " -see_also : show the 'SEE ALSO' string for man pages\n" "\n" " e.g. nifti_tool -see_also\n" "\n" " -hist : show the program modification history\n" "\n" " e.g. nifti_tool -hist\n" "\n"); printf( " -nifti_ver : show the nifti library version number\n" "\n" " e.g. nifti_tool -nifti_ver\n" "\n" " -nifti_hist : show the nifti library modification history\n" "\n" " e.g. nifti_tool -nifti_hist\n" "\n" " -with_zlib : print whether library was compiled with zlib\n" "\n" " e.g. nifti_tool -with_zlib\n" "\n" " ------------------------------\n" "\n" " R. Reynolds\n" " version %s (%s)\n\n", g_version, g_version_date ); return 1; } /*---------------------------------------------------------------------- * display the contents of the struct and all lists *----------------------------------------------------------------------*/ int disp_nt_opts( const char *mesg, nt_opts * opts) { int c; if( mesg ) fputs(mesg, stderr); if( ! opts ) { fprintf(stderr,"** disp_nt_opts: missing opts\n"); return -1; } fprintf(stderr,"nt_opts @ %p\n" " check_hdr, check_nim = %d, %d\n" " diff_hdr1, diff_hdr2 = %d, %d\n" " diff_hdr, diff_nim = %d, %d\n" " disp_hdr1, disp_hdr2 = %d, %d\n" " disp_hdr, disp_nim = %d, %d\n" " disp_ana, disp_exts = %d, %d\n" " disp_cext = %d\n" " add_exts, rm_exts = %d, %d\n" " run_misc_tests = %d\n" " mod_hdr, mod_hdr2 = %d, %d\n" " mod_nim = %d\n" " swap_hdr, swap_ana = %d, %d\n" " swap_old = %d\n" " cbl, cci = %d, %d\n" " dts, dci_lines = %d, %d\n" " make_im = %d\n", (void *)opts, opts->check_hdr, opts->check_nim, opts->diff_hdr1, opts->diff_hdr2, opts->diff_hdr, opts->diff_nim, opts->disp_hdr1, opts->disp_hdr2, opts->disp_hdr, opts->disp_nim, opts->disp_ana, opts->disp_exts, opts->disp_cext, opts->add_exts, opts->rm_exts, opts->run_misc_tests, opts->mod_hdr, opts->mod_hdr2, opts->mod_nim, opts->swap_hdr, opts->swap_ana, opts->swap_old, opts->cbl, opts->cci, opts->dts, opts->dci_lines, opts->make_im ); fprintf(stderr," ci_dims[8] = "); disp_raw_data(opts->ci_dims, DT_INT64, 8, ' ', 1); fprintf(stderr," new_dim[8] = "); disp_raw_data(opts->new_dim, DT_INT64, 8, ' ', 1); fprintf(stderr,"\n" " new_datatype = %d\n" " debug, keep_hist = %d, %d\n" " overwrite = %d\n" " prefix = '%s'\n", opts->new_datatype, opts->debug, opts->keep_hist, opts->overwrite, opts->prefix ? opts->prefix : "(NULL)" ); fprintf(stderr," elist (length %d) :\n", opts->elist.len); for( c = 0; c < opts->elist.len; c++ ) fprintf(stderr," %d : %s\n", c, opts->elist.list[c]); fprintf(stderr," etypes (length %d) : ", opts->etypes.len); disp_raw_data(opts->etypes.list, DT_INT32, opts->etypes.len, ' ', 0); fputc('\n',stderr); fprintf(stderr," flist (length %d) :\n", opts->flist.len); for( c = 0; c < opts->flist.len; c++ ) fprintf(stderr," %d : %s\n", c, opts->flist.list[c]); fprintf(stderr," vlist (length %d) :\n", opts->vlist.len); for( c = 0; c < opts->vlist.len; c++ ) fprintf(stderr," %d : %s\n", c, opts->vlist.list[c]); fprintf(stderr," infiles (length %d) :\n", opts->infiles.len); for( c = 0; c < opts->infiles.len; c++ ) fprintf(stderr," %d : %s\n", c, opts->infiles.list[c]); fprintf(stderr," command len : %d\n",(int)strlen(opts->command)); return 0; } /*---------------------------------------------------------------------- * For each file, add all extensions with type NIFTI_ECODE_AFNI. * Though it should not matter, copy the trailing null characters. *----------------------------------------------------------------------*/ int act_add_exts( nt_opts * opts ) { nifti_image * nim; const char * ext; char * edata = NULL; int fc, ec, elen; if( g_debug > 2 ){ fprintf(stderr,"+d adding %d extensions to %d files...\n" " extension types are: ", opts->elist.len, opts->infiles.len); disp_raw_data(opts->etypes.list, DT_INT32, opts->etypes.len, ' ', 1); } if( opts->prefix && opts->infiles.len != 1 ){ fprintf(stderr,"** error: we have a prefix but %d files\n", opts->infiles.len); return 1; } if( opts->elist.len <= 0 ) return 0; for( fc = 0; fc < opts->infiles.len; fc++ ) { nim = nt_image_read( opts, opts->infiles.list[fc], 1, 0 ); if( !nim ) return 1; /* errors come from the library */ for( ec = 0; ec < opts->elist.len; ec++ ){ ext = opts->elist.list[ec]; elen = (int)strlen(ext); if( !strncmp(ext,"file:",5) ){ edata = read_file_text(ext+5, &elen); if( !edata || elen <= 0 ) { fprintf(stderr,"** failed to read extension data from '%s'\n", ext+5); continue; } ext = edata; } if( ! nifti_is_valid_ecode(opts->etypes.list[ec]) ) fprintf(stderr,"** warning: applying unknown ECODE %d\n", opts->etypes.list[ec]); if( nifti_add_extension(nim, ext, elen, opts->etypes.list[ec]) ){ nifti_image_free(nim); return 1; } /* if extension came from file, free the data */ if( edata ){ free(edata); edata = NULL; } } if( opts->keep_hist && nifti_add_extension(nim, opts->command, (int)strlen(opts->command), NIFTI_ECODE_COMMENT) ) fprintf(stderr,"** failed to add command to image as extension\n"); if( opts->prefix && nifti_set_filenames(nim, opts->prefix, !opts->overwrite, 1) ) { nifti_image_free(nim); return 1; } if( g_debug > 1 ) fprintf(stderr,"+d writing %s with %d new extension(s)\n", opts->infiles.list[fc], opts->elist.len); if( nifti_image_write_status(nim) ) { fprintf(stderr,"** failed to write image %s\n", opts->infiles.list[fc]); nifti_image_free(nim); return 1; } nifti_image_free(nim); } if( g_debug > 0 ) fprintf(stderr,"+d added %d extension(s) to %d files\n", opts->elist.len, opts->infiles.len); return 0; } /*---------------------------------------------------------------------- * Return the allocated file contents. *----------------------------------------------------------------------*/ static char * read_file_text(const char * filename, int * length) { FILE * fp; char * text; int64_t len64; size_t bytes; if( !filename || !length ) { fprintf(stderr,"** bad params to read_file_text\n"); return NULL; } len64 = nifti_get_filesize(filename); if( len64 <= 0 ) { fprintf(stderr,"** RFT: file '%s' appears empty\n", filename); return NULL; } else if( len64 > INT_MAX ) { fprintf(stderr,"** RFT: file '%s' size exceeds 32-bit limit\n", filename); return NULL; } fp = fopen(filename, "r"); if( !fp ) { fprintf(stderr,"** RFT: failed to open '%s' for reading\n", filename); return NULL; } /* allocate the bytes, and fill them with the file contents */ text = (char *)malloc(len64 * sizeof(char)); if( !text ) { fprintf(stderr,"** RFT: failed to allocate %" PRId64 " bytes\n", len64); fclose(fp); return NULL; } bytes = fread(text, sizeof(char), len64, fp); fclose(fp); /* in any case */ if( bytes != len64 ) { fprintf(stderr,"** RFT: read only %zu of %" PRId64 " bytes from %s\n", bytes, len64, filename); free(text); return NULL; } /* success */ if( g_debug > 1 ) { fprintf(stderr,"++ found extension of length %" PRId64 " in file %s\n", len64, filename); if( g_debug > 2 ) fprintf(stderr,"++ text is:\n%s\n", text); } *length = (int)len64; return text; } /*---------------------------------------------------------------------- * For each file, strip the extra fields. * * Clear extensions and descrip field. No other generic strings will get * passed to nifti_1_header struct. * * - this may make the datasets more anonymous * - no history is appended here *----------------------------------------------------------------------*/ int act_strip( nt_opts * opts ) { nifti_image * nim; int fc; if( g_debug > 2 ) fprintf(stderr,"+d stripping extras from %d files\n", opts->infiles.len); if( opts->prefix && opts->infiles.len != 1 ){ fprintf(stderr,"** error: we have a prefix but %d files\n", opts->infiles.len); return 1; } for( fc = 0; fc < opts->infiles.len; fc++ ) { nim = nt_image_read( opts, opts->infiles.list[fc], 1, 0 ); if( !nim ) return 1; /* errors come from the library */ /* now remove the extensions */ nifti_free_extensions(nim); memset(nim->descrip, 0, 80); if( opts->prefix && nifti_set_filenames(nim, opts->prefix, !opts->overwrite, 1) ){ nifti_image_free(nim); return 1; } if( g_debug > 1 ) fprintf(stderr,"+d writing %s without extensions or 'descrip'\n", nim->fname); if( nifti_image_write_status(nim) ) { fprintf(stderr,"** failed to write image %s\n", nim->fname); nifti_image_free(nim); return 1; } if( g_debug > 3 ) nifti_image_infodump(nim); nifti_image_free(nim); } if( g_debug > 0 ) fprintf(stderr,"+d stripped extras from %d files\n", opts->infiles.len); return 0; } /*---------------------------------------------------------------------- * For each file, remove the given extension for the given indices. * * Note that index = -1 means to remove them all. *----------------------------------------------------------------------*/ int act_rm_ext( nt_opts * opts ) { nifti_image * nim; int fc, ext_ind, num_ext; if( g_debug > 2 ) fprintf(stderr,"+d removing %d extensions from %d files...\n", opts->elist.len, opts->infiles.len); if( opts->elist.len <= 0 ) return 0; if( opts->prefix && opts->infiles.len != 1 ){ fprintf(stderr,"** error: we have a prefix but %d files\n", opts->infiles.len); return 1; } else if( opts->overwrite && opts->infiles.len != 1 && strcmp(opts->elist.list[0], "-1") ) { fprintf(stderr,"** error: for multiple files, can only delete ALL\n"); return 1; } ext_ind = atoi(opts->elist.list[0]); if( ext_ind < -1 ){ fprintf(stderr,"** bad extension index to remove: %d\n", ext_ind); return 1; } if( g_debug > 1 ) fprintf(stderr,"+d removing extension index %d\n",ext_ind); for( fc = 0; fc < opts->infiles.len; fc++ ) { nim = nt_image_read( opts, opts->infiles.list[fc], 1, 0 ); if( !nim ) return 1; /* errors come from the library */ /* note the number of extensions for later */ num_ext = nim->num_ext; /* now remove the extensions */ if( remove_ext_list(nim, opts->elist.list, opts->elist.len) ) return 1; if( opts->keep_hist && nifti_add_extension(nim, opts->command, (int)strlen(opts->command), NIFTI_ECODE_COMMENT) ) fprintf(stderr,"** failed to add command to image as extension\n"); if( opts->prefix && nifti_set_filenames(nim, opts->prefix, !opts->overwrite, 1) ){ nifti_image_free(nim); return 1; } if( g_debug > 1 ) fprintf(stderr,"+d writing %s with %d fewer extension(s)\n", nim->fname, ext_ind == -1 ? num_ext : opts->elist.len); if( nifti_image_write_status(nim) ) { fprintf(stderr,"** failed to write image %s\n", nim->fname); nifti_image_free(nim); return 1; } nifti_image_free(nim); } if( g_debug > 0 ) fprintf(stderr,"+d removed %s extension(s) from %d files\n", ext_ind == -1 ? "ALL" : "1", opts->infiles.len); return 0; } /*---------------------------------------------------------------------- * remove extensions by index * * return: 0 on success, -1 on failure *----------------------------------------------------------------------*/ int remove_ext_list( nifti_image * nim, const char ** elist, int len ) { int * marks; int c, ec, extval; if( len > nim->num_ext ){ fprintf(stderr, "** cannot remove %d exts from image '%s' with only %d\n", len, nim->fname, nim->num_ext); return -1; } if( len <= 0 ){ fprintf(stderr,"** REL: (%d) no extensions to remove?\n",len); return -1; } extval = atoi(elist[0]); /* check the first value */ /* first special case, elist[0] == -1 */ if( extval == -1 ) { if( g_debug > 1 ) fprintf(stderr,"+d removing ALL (%d) extensions from '%s'\n", nim->num_ext, nim->fname ); nifti_free_extensions(nim); return 0; } if( g_debug > 2 ) fprintf(stderr,"+d removing %d exts from '%s'\n", len, nim->fname ); if( ! (marks = (int *)calloc(nim->num_ext, sizeof(int))) ) { fprintf(stderr,"** failed to alloc %d marks\n",nim->num_ext); return -1; } /* mark all extensions for removal */ for( ec = 0; ec < len; ec++ ) { extval = atoi(elist[ec]); if( extval < 0 || extval >= nim->num_ext ){ fprintf(stderr,"** ext #%d (= %d) is out of range [0,%d] for %s\n", ec, extval, nim->num_ext-1, nim->fname); free(marks); return -1; } if( marks[extval] ){ fprintf(stderr,"** ext #%d (= %d) is a duplicate", ec, extval); free(marks); return -1; } marks[extval]++; } /* now remove them - count from top down to do lazy programming */ for( ec = nim->num_ext-1; ec >= 0; ec-- ) { if( !marks[ec] ) continue; /* do not delete this one */ if( g_debug > 2 ) disp_nifti1_extension("+d removing ext: ",nim->ext_list+ec,-1); /* delete this data, and shift the list down (yeah, inefficient) */ if( nim->ext_list[ec].edata ) free( nim->ext_list[ec].edata ); /* move anything above down one */ for( c = ec+1; c < nim->num_ext; c++ ) nim->ext_list[c-1] = nim->ext_list[c]; nim->num_ext--; } if( g_debug > 3 ) fprintf(stderr,"-d done removing extensions\n"); if( nim->num_ext == 0 ){ /* did we trash the only extension? */ if( g_debug > 1 ) fprintf(stderr,"-d removed ALL extensions from %s\n",nim->fname); free(nim->ext_list); nim->ext_list = NULL; } free(marks); return 0; } /*---------------------------------------------------------------------- * check for diffs between all fields in opts->flist, or in the * entire header - the 2 NIFTI versions must match * * if quiet mode (debug == 0) return on first diff * * return: 1 if diffs exist, 0 otherwise *----------------------------------------------------------------------*/ int act_diff_hdrs( nt_opts * opts ) { void * nhdr0, * nhdr1; int diffs = 0, nva=0, nvb=0; if( opts->infiles.len != 2 ){ fprintf(stderr,"** -diff_hdr requires 2 -infiles, have %d\n", opts->infiles.len); return 1; } if( g_debug > 2 ) fprintf(stderr,"-d nifti_*_header diff between %s and %s...\n", opts->infiles.list[0], opts->infiles.list[1]); /* get the nifiti headers (but do not validate them) */ /* nhdr0 = nt_read_header(opts, opts->infiles.list[0], NULL, 0); */ nhdr0 = nt_read_header(opts->infiles.list[0], &nva, NULL, 0, opts->new_datatype, opts->new_dim); if( ! nhdr0 ) return 1; /* errors have been printed */ nhdr1 = nt_read_header(opts->infiles.list[1], &nvb, NULL, 0, opts->new_datatype, opts->new_dim); if( ! nhdr1 ){ free(nhdr0); return 1; } if( g_debug > 1 ) { fprintf(stderr,"\n-d nifti_?_header diffs between '%s' and '%s'...\n", opts->infiles.list[0], opts->infiles.list[1]); fprintf(stderr," have NIFTI-%d and NIFTI-%d\n", nva, nvb); } /* treat ANALYZE as NIFTI-1 */ if( nva <= 0 || nvb <= 0 ) { if( nva < 0 || nvb < 0 ) fprintf(stderr,"** resetting invalid NIFTI version(s) to 1\n"); if( nva <= 0 ) nva = 1; if( nvb <= 0 ) nvb = 1; } /* a difference is fatal */ if( nva != nvb ) { fprintf(stderr,"** %s is NIFTI-%d, while %s is NIFTI-%d\n" " they must match to compare headers\n", opts->infiles.list[0], nva, opts->infiles.list[1], nvb); free(nhdr0); free(nhdr1); return 1; } if( opts->flist.len <= 0 ) { if(nva==1) diffs = diff_hdr1s(nhdr0, nhdr1, g_debug > 0); else diffs = diff_hdr2s(nhdr0, nhdr1, g_debug > 0); } else { if(nva==1) diffs = diff_hdr1s_list(nhdr0, nhdr1, &opts->flist, g_debug>0); else diffs = diff_hdr2s_list(nhdr0, nhdr1, &opts->flist, g_debug>0); } if( diffs == 0 && g_debug > 1 ) fprintf(stderr,"+d no differences found\n"); else if ( g_debug > 2 ) fprintf(stderr,"+d %d differences found\n", diffs); free(nhdr0); free(nhdr1); return (diffs > 0); } /*---------------------------------------------------------------------- * check for diffs between all fields in opts->flist, or in the * entire nifti_1_header * * if quiet mode (debug == 0) return on first diff * * return: 1 if diffs exist, 0 otherwise *----------------------------------------------------------------------*/ int act_diff_hdr1s( nt_opts * opts ) { nifti_1_header * nhdr0, * nhdr1; int diffs = 0, nv=1; if( opts->infiles.len != 2 ){ fprintf(stderr,"** -diff_hdr1 requires 2 -infiles, have %d\n", opts->infiles.len); return 1; } if( g_debug > 2 ) fprintf(stderr,"-d nifti_1_header diff between %s and %s...\n", opts->infiles.list[0], opts->infiles.list[1]); /* get the nifiti headers (but do not validate them) */ /* nhdr0 = nt_read_header(opts, opts->infiles.list[0], NULL, 0); */ nhdr0 = nt_read_header(opts->infiles.list[0], &nv, NULL, 0, opts->new_datatype, opts->new_dim); if( ! nhdr0 ) return 1; /* errors have been printed */ if( ! nifti_hdr1_looks_good(nhdr0) ) fprintf(stderr,"** warning: invalid NIFTI-1 hdr: %s\n", opts->infiles.list[0]); nhdr1 = nt_read_header(opts->infiles.list[1], &nv, NULL, 0, opts->new_datatype, opts->new_dim); if( ! nhdr1 ){ free(nhdr0); return 1; } if( ! nifti_hdr1_looks_good(nhdr1) ) fprintf(stderr,"** warning: invalid NIFTI-1 hdr: %s\n", opts->infiles.list[1]); if( g_debug > 1 ) fprintf(stderr,"\n-d nifti_1_header diffs between '%s' and '%s'...\n", opts->infiles.list[0], opts->infiles.list[1]); if( opts->flist.len <= 0 ) diffs = diff_hdr1s(nhdr0, nhdr1, g_debug > 0); else diffs = diff_hdr1s_list(nhdr0, nhdr1, &opts->flist, g_debug > 0); if( diffs == 0 && g_debug > 1 ) fprintf(stderr,"+d no differences found\n"); else if ( g_debug > 2 ) fprintf(stderr,"+d %d differences found\n", diffs); free(nhdr0); free(nhdr1); return (diffs > 0); } /*---------------------------------------------------------------------- * check for diffs between all fields in opts->flist, or in the * entire nifti_2_header * * if quiet mode (debug == 0) return on first diff * * return: 1 if diffs exist, 0 otherwise *----------------------------------------------------------------------*/ int act_diff_hdr2s( nt_opts * opts ) { nifti_2_header * nhdr0, * nhdr1; int diffs = 0, nv=2; if( opts->infiles.len != 2 ){ fprintf(stderr,"** -diff_hdr2 requires 2 -infiles, have %d\n", opts->infiles.len); return 1; } if( g_debug > 2 ) fprintf(stderr,"-d nifti_2_header diff between %s and %s...\n", opts->infiles.list[0], opts->infiles.list[1]); /* get the nifiti headers (but do not validate them) */ /* nhdr0 = nt_read_header(opts, opts->infiles.list[0], NULL, 0); */ nhdr0 = nt_read_header(opts->infiles.list[0], &nv, NULL, 0, opts->new_datatype, opts->new_dim); if( ! nhdr0 ) return 1; /* errors have been printed */ if( ! nifti_hdr2_looks_good(nhdr0) ) fprintf(stderr,"** warning invalid NIFTI-2 hdr: %s\n", opts->infiles.list[0]); nhdr1 = nt_read_header(opts->infiles.list[1], &nv, NULL, 0, opts->new_datatype, opts->new_dim); if( ! nhdr1 ){ free(nhdr0); return 1; } if( ! nifti_hdr2_looks_good(nhdr1) ) fprintf(stderr,"** warning invalid NIFTI-2 hdr: %s\n", opts->infiles.list[1]); if( g_debug > 1 ) fprintf(stderr,"\n-d nifti_2_header diffs between '%s' and '%s'...\n", opts->infiles.list[0], opts->infiles.list[1]); if( opts->flist.len <= 0 ) diffs = diff_hdr2s(nhdr0, nhdr1, g_debug > 0); else diffs = diff_hdr2s_list(nhdr0, nhdr1, &opts->flist, g_debug > 0); if( diffs == 0 && g_debug > 1 ) fprintf(stderr,"+d no differences found\n"); else if ( g_debug > 2 ) fprintf(stderr,"+d %d differences found\n", diffs); free(nhdr0); free(nhdr1); return (diffs > 0); } /*---------------------------------------------------------------------- * check for diffs between all fields in opts->flist, or in the * entire nifti_image * * if quiet mode (debug == 0) return on first diff * * return: 1 if diffs exist, 0 otherwise *----------------------------------------------------------------------*/ int act_diff_nims( nt_opts * opts ) { nifti_image * nim0, * nim1; int diffs = 0; if( opts->infiles.len != 2 ){ fprintf(stderr,"** -diff_nim requires 2 -infiles, have %d\n", opts->infiles.len); return 1; } if( g_debug > 2 ) fprintf(stderr,"-d nifti_image diff between %s and %s...\n", opts->infiles.list[0], opts->infiles.list[1]); /* get the nifiti images */ nim0 = nt_image_read(opts, opts->infiles.list[0], 0, 0); if( ! nim0 ) return 1; /* errors have been printed */ nim1 = nt_image_read(opts, opts->infiles.list[1], 0, 0); if( ! nim1 ){ free(nim0); return 1; } if( g_debug > 1 ) fprintf(stderr,"\n-d nifti_image diffs between '%s' and '%s'...\n", opts->infiles.list[0], opts->infiles.list[1]); if( opts->flist.len <= 0 ) diffs = diff_nims(nim0, nim1, g_debug > 0); else diffs = diff_nims_list(nim0, nim1, &opts->flist, g_debug > 0); if( diffs == 0 && g_debug > 1 ) fprintf(stderr,"+d no differences found\n"); else if ( g_debug > 2 ) fprintf(stderr,"+d %d differences found\n", diffs); nifti_image_free(nim0); nifti_image_free(nim1); return (diffs > 0); } /*---------------------------------------------------------------------- * for each file, read nifti1_header * if checking header, check it * if checking nifti_image, convert and check it *----------------------------------------------------------------------*/ int act_check_hdrs( nt_opts * opts ) { nifti_1_header * nhdr; nifti_image * nim; int filenum, rv, nver=1; if( g_debug > 2 ) fprintf(stderr,"-d checking hdrs/nims for %d nifti datasets...\n", opts->infiles.len); for( filenum = 0; filenum < opts->infiles.len; filenum++ ) { /* do not validate the header structure */ nhdr = nt_read_header(opts->infiles.list[filenum], &nver, NULL, 0, opts->new_datatype, opts->new_dim); if( !nhdr ) continue; /* errors are printed from library */ if( opts->check_hdr ) { if( g_debug > 1 ) fprintf(stdout,"\nchecking nifti_1_header for file '%s'\n", opts->infiles.list[filenum]); rv = nifti_hdr1_looks_good(nhdr); if( rv && g_debug > 0 ) /* if quiet, no GOOD response */ printf("header IS GOOD for file %s\n",opts->infiles.list[filenum]); else if( ! rv ) printf("header FAILURE for file %s\n",opts->infiles.list[filenum]); } if( opts->check_nim ) { nim = nifti_convert_n1hdr2nim(*nhdr, opts->infiles.list[filenum]); if( !nim ) continue; /* errors are printed from library */ if( g_debug > 1 ) fprintf(stdout,"\nchecking nifti_image for file '%s'\n", opts->infiles.list[filenum]); rv = nifti_nim_is_valid(nim, 1); /* complain about errors */ if( rv && g_debug > 0 ) /* if quiet, no GOOD response */ printf("nifti_image IS GOOD for file %s\n", opts->infiles.list[filenum]); else if( ! rv ) printf("nifti_image FAILURE for file %s\n", opts->infiles.list[filenum]); nifti_image_free(nim); } free(nhdr); } return 0; } /*---------------------------------------------------------------------- * display all extensions for each dataset *----------------------------------------------------------------------*/ int act_disp_exts( nt_opts * opts ) { nifti_image * nim; char mesg[32], *mptr; int ec, fc; if( g_debug > 2 ) fprintf(stderr,"-d displaying all extensions for %d files...\n", opts->infiles.len); for( fc = 0; fc < opts->infiles.len; fc++ ) { nim = nt_image_read(opts, opts->infiles.list[fc], 0, 0); if( !nim ) return 1; /* errors are printed from library */ if( g_debug > 0 ) fprintf(stdout,"header file '%s', num_ext = %d\n", nim->fname, nim->num_ext); for( ec = 0; ec < nim->num_ext; ec++ ) { snprintf(mesg, sizeof(mesg), " ext #%d : ", ec); if( g_debug > 0 ) mptr = mesg; else mptr = NULL; disp_nifti1_extension(mptr, nim->ext_list + ec, -1); } nifti_image_free(nim); } return 0; } /*---------------------------------------------------------------------- * display all GIFTI extensions for each dataset *----------------------------------------------------------------------*/ int act_disp_cext( nt_opts * opts ) { nifti_image * nim; int ec, fc, found; if( g_debug > 2 ) fprintf(stderr,"-d displaying CIFTI extensions for %d files...\n", opts->infiles.len); for( fc = 0; fc < opts->infiles.len; fc++ ) { nim = nt_image_read(opts, opts->infiles.list[fc], 0, 0); if( !nim ) return 1; /* errors are printed from library */ if( g_debug > 1 ) fprintf(stdout,"header file '%s', num_ext = %d\n", nim->fname, nim->num_ext); found = 0; for( ec = 0; ec < nim->num_ext; ec++ ) { if( nim->ext_list[ec].ecode != NIFTI_ECODE_CIFTI ) continue; found++; if( found == 1 && g_debug > 1 ) fprintf(stdout,"header file '%s', ext %d of %d is CIFTI\n", nim->fname, ec, nim->num_ext); disp_cifti_extension(NULL, nim->ext_list + ec, -1); } if( g_debug && ! found ) fprintf(stdout,"header file '%s': no CIFTI extension\n", nim->fname); nifti_image_free(nim); } return 0; } /*---------------------------------------------------------------------- * for each file, read nifti*_header and display all fields *----------------------------------------------------------------------*/ int act_disp_hdr( nt_opts * opts ) { void * nhdr; field_s * fnhdr; const char ** sptr; int nfields, filenum, fc, nver=0; if( g_debug > 2 ) fprintf(stderr,"-d displaying %d fields for %d nifti datasets...\n", opts->flist.len, opts->infiles.len); for( filenum = 0; filenum < opts->infiles.len; filenum++ ) { /* do not validate the header structure */ nver = 0; nhdr = nt_read_header(opts->infiles.list[filenum], &nver, NULL, g_debug>1, opts->new_datatype, opts->new_dim); if( !nhdr ) return 1; /* errors are printed from library */ if( nver < 0 ) { fprintf(stderr,"** resetting invalid NIFTI version to 1\n"); nver = 1; } /* set the number of fields to display */ nfields = opts->flist.len > 0 ? opts->flist.len : nver <= 1 ? NT_HDR1_NUM_FIELDS : NT_HDR2_NUM_FIELDS; if( g_debug > 0 ) fprintf(stdout,"\nN-%d header file '%s', num_fields = %d\n", nver, opts->infiles.list[filenum], nfields); if( g_debug > 1 ) { if( nver <= 1 ) fprintf(stderr,"-d header is: %s\n", nifti_hdr1_looks_good(nhdr) ? "valid" : "invalid"); else fprintf(stderr,"-d header is: %s\n", nifti_hdr2_looks_good(nhdr) ? "valid" : "invalid"); } if( opts->flist.len <= 0 ) { /* then display all fields */ if( nver <= 1 ) fnhdr = g_hdr1_fields; else fnhdr = g_hdr2_fields; disp_field("\nall fields:\n", fnhdr, nhdr, nfields, g_debug>0); } else { /* print only the requested fields... */ /* must locate each field before printing it */ sptr = opts->flist.list; for( fc = 0; fc < opts->flist.len; fc++ ) { if( nver == 1 ) fnhdr = get_hdr1_field(*sptr, filenum == 0); else fnhdr = get_hdr2_field(*sptr, filenum == 0); if( fnhdr ) disp_field(NULL, fnhdr, nhdr, 1, g_debug>0 && fc == 0); sptr++; } } free(nhdr); } return 0; } /*---------------------------------------------------------------------- * for each file, read nifti1_header and display all fields *----------------------------------------------------------------------*/ int act_disp_hdr1( nt_opts * opts ) { nifti_1_header * nhdr; field_s * fnhdr; const char ** sptr; int nfields, filenum, fc, nver=-1; /* set the number of fields to display */ nfields = opts->flist.len > 0 ? opts->flist.len : NT_HDR1_NUM_FIELDS; if( g_debug > 2 ) fprintf(stderr,"-d displaying %d fields for %d nifti datasets...\n", nfields, opts->infiles.len); for( filenum = 0; filenum < opts->infiles.len; filenum++ ) { /* do not validate the header structure */ nhdr = nt_read_header(opts->infiles.list[filenum], &nver, NULL, g_debug>1, opts->new_datatype, opts->new_dim); if( !nhdr ) return 1; /* errors are printed from library */ if( g_debug > 0 ) fprintf(stdout,"\nheader file '%s', num_fields = %d\n", opts->infiles.list[filenum], nfields); if( g_debug > 1 ) fprintf(stderr,"-d header is: %s\n", nifti_hdr1_looks_good(nhdr) ? "valid" : "invalid"); if( opts->flist.len <= 0 ) /* then display all fields */ disp_field("\nall fields:\n", g_hdr1_fields, nhdr, nfields, g_debug>0); else /* print only the requested fields... */ { /* must locate each field before printing it */ sptr = opts->flist.list; for( fc = 0; fc < opts->flist.len; fc++ ) { fnhdr = get_hdr1_field(*sptr, filenum == 0); if( fnhdr ) disp_field(NULL, fnhdr, nhdr, 1, g_debug>0 && fc == 0); sptr++; } } free(nhdr); } return 0; } /*---------------------------------------------------------------------- * for each file, read nifti1_header and display all fields *----------------------------------------------------------------------*/ int act_disp_hdr2( nt_opts * opts ) { nifti_2_header * nhdr; field_s * fnhdr; const char ** sptr; int nfields, filenum, fc, nver=-2; /* set the number of fields to display */ nfields = opts->flist.len > 0 ? opts->flist.len : NT_HDR2_NUM_FIELDS; if( g_debug > 2 ) fprintf(stderr,"-d displaying %d N-2 fields for %d nifti datasets...\n", nfields, opts->infiles.len); for( filenum = 0; filenum < opts->infiles.len; filenum++ ) { /* do not validate the header structure */ nhdr = nt_read_header(opts->infiles.list[filenum], &nver, NULL, g_debug>1, opts->new_datatype, opts->new_dim); if( !nhdr ) return 1; /* errors are printed from library */ if( g_debug > 0 ) fprintf(stdout,"\nNIFTI-2 header file '%s', num_fields = %d\n", opts->infiles.list[filenum], nfields); if( g_debug > 1 ) fprintf(stderr,"-d header is: %s\n", nifti_hdr2_looks_good(nhdr) ? "valid" : "invalid"); if( opts->flist.len <= 0 ) /* then display all fields */ disp_field("\nall fields:\n", g_hdr2_fields, nhdr, nfields, g_debug>0); else /* print only the requested fields... */ { /* must locate each field before printing it */ sptr = opts->flist.list; for( fc = 0; fc < opts->flist.len; fc++ ) { fnhdr = get_hdr2_field(*sptr, filenum == 0); if( fnhdr ) disp_field(NULL, fnhdr, nhdr, 1, g_debug>0 && fc == 0); sptr++; } } free(nhdr); } return 0; } /*---------------------------------------------------------------------- * for each file, read nifti_analyze75 and display all fields *----------------------------------------------------------------------*/ int act_disp_anas( nt_opts * opts ) { nifti_analyze75 * nhdr; field_s * fnhdr; const char ** sptr; int nfields, filenum, fc, nver=1; /* set the number of fields to display */ nfields = opts->flist.len > 0 ? opts->flist.len : NT_ANA_NUM_FIELDS; if( g_debug > 2 ) fprintf(stderr,"-d displaying %d fields for %d ANALYZE datasets...\n", nfields, opts->infiles.len); for( filenum = 0; filenum < opts->infiles.len; filenum++ ) { /* do not validate the header structure */ nhdr = nt_read_header(opts->infiles.list[filenum], &nver, NULL, 0, opts->new_datatype, opts->new_dim); if( !nhdr ) return 1; /* errors are printed from library */ if( g_debug > 0 ) fprintf(stdout,"\nanalyze header file '%s', num_fields = %d\n", opts->infiles.list[filenum], nfields); if( g_debug > 1 ) fprintf(stderr,"-d analyze header is: %s\n", nifti_hdr1_looks_good((nifti_1_header *)nhdr) ? "valid" : "invalid"); if( opts->flist.len <= 0 ) /* then display all fields */ disp_field("\nall fields:\n", g_ana_fields, nhdr, nfields, g_debug>0); else /* print only the requested fields... */ { /* must locate each field before printing it */ sptr = opts->flist.list; for( fc = 0; fc < opts->flist.len; fc++ ) { fnhdr = get_hdr1_field(*sptr, filenum == 0); if( fnhdr ) disp_field(NULL, fnhdr, nhdr, 1, g_debug>0 && fc == 0); sptr++; } } free(nhdr); } return 0; } /*---------------------------------------------------------------------- * for each file, get nifti_image and display all fields *----------------------------------------------------------------------*/ int act_disp_nims( nt_opts * opts ) { nifti_image * nim; field_s * fnim; const char ** sptr; int nfields, filenum, fc; /* set the number of fields to display */ nfields = opts->flist.len > 0 ? opts->flist.len : NT_NIM_NUM_FIELDS; if( g_debug > 2 ) fprintf(stderr,"-d displaying %d fields for %d nifti datasets...\n", nfields, opts->infiles.len); for( filenum = 0; filenum < opts->infiles.len; filenum++ ) { nim = nt_image_read(opts, opts->infiles.list[filenum], 0, 0); if( !nim ) return 1; /* errors are printed from library */ if( g_debug > 0 ) fprintf(stdout,"\nheader file '%s', num_fields = %d, fields:\n\n", nim->fname, nfields); if( opts->flist.len <= 0 ) /* then display all fields */ disp_field("all fields:\n", g_nim2_fields, nim, nfields, g_debug > 0); else /* print only the requested fields... */ { /* must locate each field before printing it */ sptr = opts->flist.list; for( fc = 0; fc < opts->flist.len; fc++ ) { fnim = get_nim_field(*sptr, filenum == 0); if( fnim ) disp_field(NULL, fnim, nim, 1, g_debug > 0 && fc == 0); sptr++; } } nifti_image_free(nim); } return 0; } /*---------------------------------------------------------------------- * - read header * - modify header (assuming nifti-1 format) * - if -prefix duplicate file * - else if swapped, swap back * - overwrite file header (allows (danger-of) no evaluation of data) *----------------------------------------------------------------------*/ int act_mod_hdrs( nt_opts * opts ) { nifti_1_header * nhdr; nifti_image * nim; /* for reading/writing entire datasets */ int filec, swap, nver=1; const char * fname; char * dupname; char func[] = { "act_mod_hdrs" }; if( g_debug > 2 ) fprintf(stderr,"-d modifying %d fields for %d nifti headers...\n", opts->flist.len, opts->infiles.len); if( opts->flist.len <= 0 || opts->infiles.len <= 0 ) return 0; for( filec = 0; filec < opts->infiles.len; filec++ ) { fname = opts->infiles.list[filec]; /* for convenience and mod file */ if( nifti_is_gzfile(fname) ){ fprintf(stderr,"** sorry, cannot modify a gzipped file: %s\n", fname); continue; } /* do not validate the header structure */ nhdr = nt_read_header(fname, &nver, &swap, 0, opts->new_datatype, opts->new_dim); if( !nhdr ) return 1; /* if this is a valid NIFTI-2 header, fail */ if( ! nifti_hdr1_looks_good(nhdr) ) { nifti_2_header * n2hdr; int n2ver=2; n2hdr = nt_read_header(fname, &n2ver, NULL, 0, 0, 0); if( nifti_hdr2_looks_good(n2hdr) ) { if( g_debug > 0 ) fprintf(stderr,"** refusing to modify NIFTI-2 header " "as NIFTI-1 in %s\n", fname); free(nhdr); free(n2hdr); return 1; } free(n2hdr); } if( g_debug > 1 ) { fprintf(stderr,"-d modifying %d fields of '%s' header\n", opts->flist.len, fname); fprintf(stderr,"-d header is: %s\n", nifti_hdr1_looks_good(nhdr) ? "valid" : "invalid"); } /* okay, let's actually trash the data fields */ if( modify_all_fields(nhdr, opts, g_hdr1_fields, NT_HDR1_NUM_FIELDS) ) { free(nhdr); return 1; } dupname = NULL; /* unless we duplicate file */ /* possibly duplicate the current dataset before writing new header */ if( opts->prefix ) { /* if MAKE_IM, request NIFTI-1 in this case 18 Aug 2020 [rickr] */ nim = nt_image_read(opts, fname, 1, 1); /* get data */ if( !nim ) { fprintf(stderr,"** failed to dup file '%s' before modifying\n", fname); return 1; } if( opts->keep_hist && nifti_add_extension(nim, opts->command, (int)strlen(opts->command), NIFTI_ECODE_COMMENT) ) fprintf(stderr,"** failed to add command to image as extension\n"); if( nifti_set_filenames(nim, opts->prefix, 1, 1) ) { NTL_FERR(func,"failed to set prefix for new file: ",opts->prefix); nifti_image_free(nim); return 1; } dupname = nifti_strdup(nim->fname); /* so we know to free it */ fname = dupname; /* create the duplicate file */ if( nifti_image_write_status(nim) ) { fprintf(stderr,"** failed to write image %s\n", nim->fname); nifti_image_free(nim); return 1; } /* if we added a history note, get the new offset into the header */ /* mod: if the new offset is valid, use it 31 Jan 2006 [rickr] */ if( nim->iname_offset >= 348 ) nhdr->vox_offset = nim->iname_offset; nifti_image_free(nim); } else if ( swap ) swap_nifti_header(nhdr, NIFTI_VERSION(*nhdr)); /* if all is well, overwrite header in fname dataset */ (void)write_hdr_to_file(nhdr, fname); /* errors printed in function */ if( dupname ) free(dupname); free(nhdr); } return 0; } /*---------------------------------------------------------------------- * This is the same as act_mod_hdrs, but applies to NIFTI-2. * * - read header * - modify header (assuming nifti-2 format, fails on valid nifti-1) * - if -prefix duplicate file * - else if swapped, swap back * - overwrite file header (allows (danger-of) no evaluation of data) *----------------------------------------------------------------------*/ int act_mod_hdr2s( nt_opts * opts ) { nifti_2_header * nhdr; nifti_image * nim; /* for reading/writing entire datasets */ int filec, swap, nver=2; const char * fname; char * dupname; char func[] = { "act_mod_hdr2s" }; if( g_debug > 2 ) fprintf(stderr,"-d modifying %d fields for %d nifti-2 headers...\n", opts->flist.len, opts->infiles.len); if( opts->flist.len <= 0 || opts->infiles.len <= 0 ) return 0; for( filec = 0; filec < opts->infiles.len; filec++ ) { fname = opts->infiles.list[filec]; /* for convenience and mod file */ if( nifti_is_gzfile(fname) ){ fprintf(stderr,"** sorry, cannot modify a gzipped file: %s\n", fname); continue; } /* do not validate the header structure */ nhdr = nt_read_header(fname, &nver, &swap, 0, opts->new_datatype, opts->new_dim); if( !nhdr ) return 1; /* but if this is a valid NIFTI-1 header, fail */ if( ! nifti_hdr2_looks_good(nhdr) ) { nifti_1_header * n1hdr; int n1ver=1; n1hdr = nt_read_header(fname, &n1ver, NULL, 0, 0, 0); if( nifti_hdr1_looks_good(n1hdr) ) { if( g_debug > 0 ) fprintf(stderr,"** refusing to modify NIFTI-1 header " "as NIFTI-2 in %s\n", fname); free(nhdr); free(n1hdr); return 1; } free(n1hdr); } if( g_debug > 1 ) { fprintf(stderr,"-d modifying %d fields of '%s' header\n", opts->flist.len, fname); fprintf(stderr,"-d header is: %s\n", nifti_hdr2_looks_good(nhdr) ? "valid" : "invalid"); } /* okay, let's actually trash the data fields */ if( modify_all_fields(nhdr, opts, g_hdr2_fields, NT_HDR2_NUM_FIELDS) ) { free(nhdr); return 1; } dupname = NULL; /* unless we duplicate file */ /* possibly duplicate the current dataset before writing new header */ if( opts->prefix ) { /* if MAKE_IM, request NIFTI-2 in this case 18 Aug 2020 [rickr] */ nim = nt_image_read(opts, fname, 1, 2); /* get data */ if( !nim ) { fprintf(stderr,"** failed to dup file '%s' before modifying\n", fname); return 1; } if( opts->keep_hist && nifti_add_extension(nim, opts->command, (int)strlen(opts->command), NIFTI_ECODE_COMMENT) ) fprintf(stderr,"** failed to add command to image as extension\n"); if( nifti_set_filenames(nim, opts->prefix, 1, 1) ) { NTL_FERR(func,"failed to set prefix for new file: ",opts->prefix); nifti_image_free(nim); return 1; } dupname = nifti_strdup(nim->fname); /* so we know to free it */ fname = dupname; /* create the duplicate file */ if( nifti_image_write_status(nim) ) { fprintf(stderr,"** failed to write image %s\n", nim->fname); nifti_image_free(nim); return 1; } /* if we added a history note, get the new offset into the header */ /* mod: if the new offset is valid, use it 31 Jan 2006 [rickr] */ if( nim->iname_offset >= 540 ) nhdr->vox_offset = nim->iname_offset; nifti_image_free(nim); } else if ( swap ) swap_nifti_header(nhdr, NIFTI_VERSION(*nhdr)); /* if all is well, overwrite header in fname dataset */ (void)write_hdr2_to_file(nhdr, fname); /* errors printed in function */ if( dupname ) free(dupname); free(nhdr); } return 0; } /*---------------------------------------------------------------------- * - read header * - swap header (fail on nifti2) * - if -prefix duplicate file * - overwrite file header (allows (danger-of) no evaluation of data) *----------------------------------------------------------------------*/ int act_swap_hdrs( nt_opts * opts ) { nifti_1_header * nhdr; nifti_image * nim; /* for reading/writing entire datasets */ int filec, swap, nver=1; const char * fname; char * dupname; char func[] = { "act_swap_hdrs" }; /* count requested operations: "there can be only one", and not Sean */ swap = opts->swap_hdr + opts->swap_ana + opts->swap_old; if( swap > 1 ) { fprintf(stderr,"** can perform only one swap method\n"); return 1; } else if( ! swap ) return 0; /* probably shouldn't be here */ if( g_debug > 2 ) fprintf(stderr,"-d swapping headers of %d files...\n",opts->infiles.len); for( filec = 0; filec < opts->infiles.len; filec++ ) { fname = opts->infiles.list[filec]; /* for convenience and mod file */ if( nifti_is_gzfile(fname) ){ fprintf(stderr,"** sorry, cannot swap a gzipped header: %s\n", fname); continue; } /* do not validate the header structure */ nhdr = nt_read_header(fname, &nver, &swap, 0, opts->new_datatype, opts->new_dim); if( !nhdr ) return 1; /* but if this is a valid NIFTI-2 header, fail (not ready for NIFTI-2) */ if( ! nifti_hdr1_looks_good(nhdr) ) { nifti_2_header * n2hdr; int n2ver=2; n2hdr = nt_read_header(fname, &n2ver, NULL, 0, 0, 0); if( nifti_hdr2_looks_good(n2hdr) ) { /* if in debug mode, swap and display before failing */ if( g_debug > 1 ) { swap_nifti_header(n2hdr, 2); disp_field("\nswapped NIFTI-2 header:\n", g_hdr2_fields, n2hdr, NT_HDR2_NUM_FIELDS, 1); } if( g_debug > 0 ) fprintf(stderr,"** refusing to swap NIFTI-2 header " "as NIFTI-1 in %s\n", fname); free(nhdr); free(n2hdr); return 1; } free(n2hdr); } if( g_debug > 1 ) { const char * str = "NIfTI"; if( opts->swap_ana || (opts->swap_old && !NIFTI_VERSION(*nhdr)) ) str = "ANALYZE"; fprintf(stderr,"-d %sswapping %s header of file %s\n", opts->swap_old ? "OLD " : "", str, fname); } if( ! swap ) { /* if not yet swapped, do as the user requested */ if( opts->swap_old ) old_swap_nifti_header(nhdr, NIFTI_VERSION(*nhdr)); else swap_nifti_header(nhdr, opts->swap_ana ? 0 : 1); } else { /* swapped already: if not correct, need to undo */ /* if swapped the wrong way, undo and swap as the user requested */ if ( opts->swap_ana && NIFTI_VERSION(*nhdr) ) { /* want swapped as ANALYZE, but was swapped as NIFTI */ swap_nifti_header(nhdr, 1); /* undo NIFTI */ swap_nifti_header(nhdr, 0); /* swap ANALYZE */ } else if( opts->swap_hdr && !NIFTI_VERSION(*nhdr) ) { /* want swapped as NIFTI, but was swapped as ANALYZE */ swap_nifti_header(nhdr, 0); /* undo ANALYZE */ swap_nifti_header(nhdr, 1); /* swap NIFTI */ } else if ( opts->swap_old ) { /* undo whichever was done and apply the old way */ swap_nifti_header(nhdr, NIFTI_VERSION(*nhdr)); old_swap_nifti_header(nhdr, NIFTI_VERSION(*nhdr)); } /* else it was swapped the right way to begin with */ } dupname = NULL; /* unless we duplicate file */ /* possibly duplicate the current dataset before writing new header */ if( opts->prefix ) { /* if MAKE_IM, request NIFTI-1 in this case 18 Aug 2020 [rickr] */ nim = nt_image_read(opts, fname, 1, 1); /* get data */ if( !nim ) { fprintf(stderr,"** failed to dup file '%s' before modifying\n", fname); return 1; } if( opts->keep_hist && nifti_add_extension(nim, opts->command, (int)strlen(opts->command), NIFTI_ECODE_COMMENT) ) fprintf(stderr,"** failed to add command to image as extension\n"); if( nifti_set_filenames(nim, opts->prefix, 1, 1) ) { NTL_FERR(func,"failed to set prefix for new file: ",opts->prefix); nifti_image_free(nim); return 1; } dupname = nifti_strdup(nim->fname); /* so we know to free it */ fname = dupname; /* create the duplicate file */ if( nifti_image_write_status(nim) ) { fprintf(stderr,"** failed to write image %s\n", nim->fname); nifti_image_free(nim); return 1; } /* if we added a history note, get the new offset into the header */ /* mod: if the new offset is valid, use it 31 Jan 2006 [rickr] */ if( nim->iname_offset >= 348 ) nhdr->vox_offset = nim->iname_offset; nifti_image_free(nim); } /* if all is well, overwrite header in fname dataset */ (void)write_hdr_to_file(nhdr, fname); /* errors printed in function */ if( dupname ) free(dupname); free(nhdr); } return 0; } /*---------------------------------------------------------------------- * - read image w/data, modify and write *----------------------------------------------------------------------*/ int act_mod_nims( nt_opts * opts ) { nifti_image * nim; /* for reading/writing entire datasets */ int filec; char func[] = { "act_mod_nims" }; if( g_debug > 2 ) fprintf(stderr,"-d modifying %d fields for %d nifti images...\n", opts->flist.len, opts->infiles.len); if( opts->flist.len <= 0 || opts->infiles.len <= 0 ) return 0; for( filec = 0; filec < opts->infiles.len; filec++ ) { nim = nt_image_read(opts, opts->infiles.list[filec], 1, 0); /* data */ if( !nim ) return 1; if( g_debug > 1 ) fprintf(stderr,"-d modifying %d fields from '%s' image\n", opts->flist.len, opts->infiles.list[filec]); /* okay, let's actually trash the data fields */ if( modify_all_fields(nim, opts, g_nim2_fields, NT_NIM_NUM_FIELDS) ) { nifti_image_free(nim); return 1; } /* add command as COMMENT extension */ if( opts->keep_hist && nifti_add_extension(nim, opts->command, (int)strlen(opts->command), NIFTI_ECODE_COMMENT) ) fprintf(stderr,"** failed to add command to image as extension\n"); /* possibly duplicate the current dataset before writing new header */ if( opts->prefix ) if( nifti_set_filenames(nim, opts->prefix, 1, 1) ) { NTL_FERR(func,"failed to set prefix for new file: ",opts->prefix); nifti_image_free(nim); return 1; } /* and write it out, piece of cake :) */ if( nifti_image_write_status(nim) ) { NTL_FERR(func,"failed to write image: ", nim->fname); nifti_image_free(nim); return 1; } nifti_image_free(nim); } return 0; } /*---------------------------------------------------------------------- * overwrite nifti_1_header in the given file *----------------------------------------------------------------------*/ int write_hdr_to_file( nifti_1_header * nhdr, const char * fname ) { znzFile fp; size_t bytes; char func[] = { "write_hdr_to_file" }; int rv = 0; fp = znzopen(fname,"r+b",nifti_is_gzfile(fname)); if( znz_isnull(fp) ){ NTL_FERR(func, "failed to re-open mod file", fname); return 1; } bytes = znzwrite(nhdr, 1, sizeof(nifti_1_header), fp); if( bytes != sizeof(nifti_1_header)){ NTL_FERR(func, "failed to write header to file",fname); fprintf(stderr," - wrote %d of %d bytes\n", (int)bytes,(int)sizeof(nifti_1_header)); rv = 1; } if( g_debug > 3 ) disp_nifti_1_header("+d writing new header to file : ", nhdr); znzclose(fp); return rv; } /*---------------------------------------------------------------------- * overwrite nifti_2_header in the given file *----------------------------------------------------------------------*/ int write_hdr2_to_file( nifti_2_header * nhdr, const char * fname ) { znzFile fp; size_t bytes; char func[] = { "write_hdr2_to_file" }; int rv = 0; fp = znzopen(fname,"r+b",nifti_is_gzfile(fname)); if( znz_isnull(fp) ){ NTL_FERR(func, "failed to re-open mod file", fname); return 1; } bytes = znzwrite(nhdr, 1, sizeof(nifti_2_header), fp); if( bytes != sizeof(nifti_2_header)){ NTL_FERR(func, "failed to write N-2 header to file",fname); fprintf(stderr," - wrote %d of %d bytes\n", (int)bytes,(int)sizeof(nifti_2_header)); rv = 1; } if( g_debug > 3 ) disp_nifti_2_header("+d writing new N2 header to file : ", nhdr); znzclose(fp); return rv; } /*---------------------------------------------------------------------- * modify all fields in the list *----------------------------------------------------------------------*/ int modify_all_fields( void * basep, nt_opts * opts, field_s * fields, int flen) { field_s * fp; int fc, lc; /* field and list counters */ if( opts->flist.len <= 0 ) return 0; if( opts->flist.len != opts->vlist.len ){ fprintf(stderr,"** have %d fields but %d new values\n", opts->flist.len, opts->vlist.len); return 1; } if( basep == NULL ) { fprintf(stderr,"** modify_all_fields: have NULL basep\n"); return 1; } for( lc = 0; lc < opts->flist.len; lc++ ) { /* is it in the list? */ fp = fields; for( fc = 0; fc < flen; fc++, fp++ ) if( strcmp(opts->flist.list[lc], fp->name) == 0 ) break; if( fc == flen ) /* do no modifications on failure */ { fprintf(stderr,"** field '%s' not found in structure\n", opts->flist.list[lc]); return 1; } if( modify_field( basep, fp, opts->vlist.list[lc]) ) return 1; } return 0; } /*---------------------------------------------------------------------- * modify a single field with the given value field * * pointer fields are not allowed here *----------------------------------------------------------------------*/ int modify_field(void * basep, field_s * field, const char * data) { float fval; const char * posn = data; int val, max, fc, nchars; if( g_debug > 1 ) fprintf(stderr,"+d modifying field '%s' with '%s'\n", field->name, data); if( !data || strlen(data) == 0 ) { fprintf(stderr,"** no data for '%s' field modification\n",field->name); return 1; } switch( field->type ) { case DT_UNKNOWN: case NT_DT_POINTER: case NT_DT_CHAR_PTR: case NT_DT_EXT_PTR: default: fprintf(stderr,"** refusing to modify a pointer field, '%s'\n", field->name); return 1; case DT_INT8: { max = 127; for( fc = 0; fc < field->len; fc++ ) { if( sscanf(posn, " %d%n", &val, &nchars) != 1 ) { fprintf(stderr,"** found %d of %d modify values\n", fc,field->len); return 1; } if( val > max || val < -(max+1) ) { fprintf(stderr, "** mod val #%d (= %d) outside byte range [-%d,%d]\n", fc, val, max+1, max); return 1; } /* otherwise, we're good */ (((char *)basep + field->offset))[fc] = (char)val; if( g_debug > 1 ) fprintf(stderr,"+d setting posn %d of '%s' to %d\n", fc, field->name, val); posn += nchars; } } break; case DT_INT16: { max = 32767; for( fc = 0; fc < field->len; fc++ ) { if( sscanf(posn, " %d%n", &val, &nchars) != 1 ) { fprintf(stderr,"** found %d of %d modify values\n", fc,field->len); return 1; } if( val > max || val < -(max+1) ) { fprintf(stderr, "** mod val #%d (= %d) outside byte range [-%d,%d]\n", fc, val, max+1, max); return 1; } /* otherwise, we're good */ ((short *)((char *)basep + field->offset))[fc] = (short)val; if( g_debug > 1 ) fprintf(stderr,"+d setting posn %d of '%s' to %d\n", fc, field->name, val); posn += nchars; } } break; case DT_INT32: { for( fc = 0; fc < field->len; fc++ ) { if( sscanf(posn, " %d%n", &val, &nchars) != 1 ) { fprintf(stderr,"** found %d of %d modify values\n", fc,field->len); return 1; } ((int *)((char *)basep + field->offset))[fc] = val; if( g_debug > 1 ) fprintf(stderr,"+d setting posn %d of '%s' to %d\n", fc, field->name, val); posn += nchars; } } break; case DT_INT64: { int64_t v64; for( fc = 0; fc < field->len; fc++ ) { if( sscanf(posn, " %" PRId64 "%n", &v64, &nchars) != 1 ) { fprintf(stderr,"** found %d of %d modify values\n", fc,field->len); return 1; } ((int64_t *)((char *)basep + field->offset))[fc] = v64; if( g_debug > 1 ) fprintf(stderr,"+d setting posn %d of '%s' to %" PRId64 "\n", fc, field->name, v64); posn += nchars; } } break; case DT_FLOAT32: { for( fc = 0; fc < field->len; fc++ ) { if( sscanf(posn, " %f%n", &fval, &nchars) != 1 ) { fprintf(stderr,"** found %d of %d modify values\n", fc,field->len); return 1; } /* otherwise, we're good */ ((float *)((char *)basep + field->offset))[fc] = fval; if( g_debug > 1 ) fprintf(stderr,"+d setting posn %d of '%s' to %f\n", fc, field->name, fval); posn += nchars; } } break; case DT_FLOAT64: { double f64; for( fc = 0; fc < field->len; fc++ ) { if( sscanf(posn, " %lf%n", &f64, &nchars) != 1 ) { fprintf(stderr,"** found %d of %d modify values\n", fc,field->len); return 1; } /* otherwise, we're good */ ((double *)((char *)basep + field->offset))[fc] = f64; if( g_debug > 1 ) fprintf(stderr,"+d setting posn %d of '%s' to %f\n", fc, field->name, f64); posn += nchars; } } break; case NT_DT_STRING: { char * dest = (char *)basep + field->offset; nchars = strlen(data); strncpy(dest, data, field->len); if( nchars < field->len ) /* clear the rest */ memset(dest+nchars, '\0', field->len-nchars); } break; } return 0; } /*---------------------------------------------------------------------- * These type conversion functions might be worth putting in the library, * but we can try them in nifti_tool for now. *---------------------------------------------------------------------- */ /*---------------------------------------------------------------------- * convert the actual data to the given new_type * * MODIFY: nim->nbyper, datatype, data (or NBL) * * new_type : NIFTI_TYPE to convert to * verify : flag: verify conversion accuracy * (clear this if conversion is_lossless()) * (fails if conversion does not invert) * fail_choice : what to do if a check fails * 0 : nothing * 1 : warn * 2 : panic; abort; planetary meltdown; take ball, go home * * On success, replace the data (and type and nbyper) in question. * * return 0 on success *----------------------------------------------------------------------*/ static int convert_datatype(nifti_image * nim, nifti_brick_list * NBL, int new_type, int verify, int fail_choice) { void * newdata=NULL; int rv; if( !nim || !nifti_datatype_is_valid(new_type, 1) ) { fprintf(stderr, "** convert datatype: no data (%p) or bad type (%d)\n", (void *)nim, new_type); return 1; } if( g_debug > 1 ) { fprintf(stderr, "++ convert datatype: %s to %s, v,f = %d,%d\n", nifti_datatype_to_string(nim->datatype), nifti_datatype_to_string(new_type), verify, fail_choice); fprintf(stderr, " lossless = %d\n", is_lossless(nim->datatype, new_type)); } /* handle the most challenging case first: same type */ if( nim->datatype == new_type ){ if( g_debug > 1) fprintf(stderr,"-- convert_DT: same datatype, nothing to do\n"); return 0; } /* handle the second most challenging case next: no data */ if( (!nim->data && !NBL) || nim->nvox <= 0 ) { nim->datatype = new_type; nifti_datatype_sizes(nim->datatype, &(nim->nbyper), NULL); return 0; /* done */ } /* if doing a lossless conversion, do not check (faster) */ if( is_lossless(nim->datatype, new_type) ) verify = 0; /* if NBL, finish here, since we have to deal with the NBL struct */ if( NBL ) { if( convert_NBL_data(NBL, nim->datatype, new_type, verify,fail_choice) ) return 1; /* failure has been dealt with already */ /* success (data pointers have been replaced in NBL) */ nim->datatype = new_type; nifti_datatype_sizes(new_type, &(nim->nbyper), NULL); return 0; } /* non-NBL: do the actual conversion (newdata will get allocated) */ rv = convert_raw_data(&newdata, nim->data, nim->datatype, new_type, nim->nvox, verify); /* 0:success, 1:whine or die, -1:other error */ if( g_debug > 2 ) fprintf(stderr,"++ convert_RD: rv %d, newdata %p\n", rv, newdata); /* some unknown failure, already reported */ if( rv < 0 ) return 1; /* whine, if we feel it is necessary (then just deal with data and rv) */ if( rv > 0 ) fprintf(stderr, "** %s: inaccurate data conversion from %s to %s\n", (fail_choice==2) ? "error" : "warning", nifti_datatype_to_string(nim->datatype), nifti_datatype_to_string(new_type)); /* destroy old data if conversion failed and choice == 2 */ if( rv > 0 && fail_choice == 2 ) { if( g_debug > 2 ) fprintf(stderr,"-- convert_RD: destroying new data\n"); free(newdata); newdata = NULL; return 1; /* return failure */ } /* else, for conversion failure or success, keep data and return success */ if( g_debug > 2 ) fprintf(stderr,"-- convert_RD: keeping new data\n"); free(nim->data); nim->data = newdata; nim->datatype = new_type; nifti_datatype_sizes(new_type, &(nim->nbyper), NULL); /* return success, new data was applied */ return 0; } /*---------------------------------------------------------------------- * replace NBL data via conversion, complete as in convert_datatype() * - need to call convert_raw_data() per volume * - have full operation pass or fail - so create new NBL * - return 0 on success (match convert_datatype) *----------------------------------------------------------------------*/ static int convert_NBL_data(nifti_brick_list * NBL, int old_type, int new_type, int verify, int fail_choice) { nifti_brick_list NBLnew; /* NBL to replace old one */ int64_t nbvals, bind; /* nvals per brick, brick index */ int nbyper=0, rv=0, cfail=0; if( g_debug > 1 ) fprintf(stderr,"-- convert_NBL_data ...\n"); /* is there anything to work with? */ if( NBL->nbricks <= 0 || NBL->bsize <= 0 || !NBL->bricks ) { if( g_debug > 1 ) fprintf(stderr,"-- cNBLd: no NBL data to convert\n"); return 0; } /* be "sure" there is something to convert */ for( bind=0; bindnbricks; bind++ ) if( !NBL->bricks[bind] ) { fprintf(stderr,"** cNBLd: empty brick %" PRId64 "\n", bind); return 1; } /* set nbvals */ nifti_datatype_sizes(old_type, &nbyper, NULL); nbvals = NBL->bsize / nbyper; if( NBL->bsize != nbyper*nbvals ) { fprintf(stderr,"** cNBLd: bad bsize,nbyper: %" PRId64 ", %d\n", NBL->bsize, nbyper); return 1; } /* start real work: populate NBLnew */ nifti_datatype_sizes(new_type, &nbyper, NULL); NBLnew.bsize = nbvals * nbyper; NBLnew.nbricks = NBL->nbricks; NBLnew.bricks = (void **)calloc(NBLnew.nbricks, sizeof(void *)); if( ! NBLnew.bricks ) { fprintf(stderr,"** cNBLd: failed to allocate %" PRId64 " void pointers\n", NBLnew.nbricks); return 1; } /* fill the bricks until done or error */ for( bind=0; bind < NBLnew.nbricks; bind++ ) { rv = convert_raw_data(NBLnew.bricks+bind, NBL->bricks[bind], old_type, new_type, nbvals, verify); /* break on serious error */ if( rv < 0 ) break; /* track any conversion failures, but continue */ if( rv > 0 ) cfail = 1; } /* whine on conversion failure */ if( cfail ) fprintf(stderr, "** NBL %s: inaccurate data conversion from %s to %s\n", (fail_choice==2) ? "error" : "warning", nifti_datatype_to_string(old_type), nifti_datatype_to_string(new_type)); /* if there was a serious error, free everything and return failure */ if( rv < 0 || (cfail && fail_choice == 2) ) { if( g_debug > 2 ) fprintf(stderr,"-- cNBLd: destroying new data\n"); nifti_free_NBL(&NBLnew); return 1; } if( g_debug > 2 ) fprintf(stderr,"-- NBL convert_RD: keeping new data\n"); /* replace old NBL */ nifti_free_NBL(NBL); NBL->nbricks = NBLnew.nbricks; NBL->bsize = NBLnew.bsize; NBL->bricks = NBLnew.bricks; return 0; } /*---------------------------------------------------------------------- * perform actual data conversion (basic checks are already done) * * It is not clear how to do this without an NxN set of cases, since * the types must be expicitly noted for each pair, even with macros. * * So it is all written out, even when in and out types match, so that * the case blocks only vary in the I/O types. If someone wants to * convert from f32 to f32, we will still go through with the casting * process. It builds character. * * If verify, warn on any conversion errors. * * return allocated data in 'retdata' * return : 0 on success * 1 on conversion errors * -1 on other failures *----------------------------------------------------------------------*/ static int convert_raw_data(void ** retdata, void * olddata, int old_type, int new_type, int64_t nvox, int verify) { void * newdata=NULL; const char * typestr; int nbyper, errs=0; /* were the conversion errors? */ int tried; /* did we even try (unapplied types) */ /* for any messages */ typestr = nifti_datatype_to_string(new_type); if( !retdata ) { fprintf(stderr, "** convert_raw_data: missing retdata to fill\n"); return -1; } *retdata = NULL; /* init, just in case */ /* do not allow some cases for either type (e.g. where we do not have * a simple datum to apply (RGB, complex)) */ if( ! is_valid_conversion_type(old_type) ) { fprintf(stderr,"** data conversion not ready for orig datatype %s\n", nifti_datatype_to_string(old_type)); return -1; } if( ! is_valid_conversion_type(new_type) ) { fprintf(stderr,"** data conversion not ready for new datatype %s\n", typestr); return -1; } /* allocate new memory (calloc, in case of partial filling) */ nifti_datatype_sizes(new_type, &nbyper, NULL); /* get nbyper */ newdata = calloc(nvox, nbyper); if( !newdata ) { fprintf(stderr,"** failed to alloc for %" PRId64 " %s elements\n", nvox, typestr); return -1; } /* ---------------------------------------------------------------------- * Enter the dragon. * * I do not see how to do this without an NxN list, even with macros. * So live with a nested set of switch cases spanning 1000+ lines... * BTW, I visually tested by separating every new_type case into its * own file and diffing against the first. Good times. */ tried = 0; /* verify that we get to a conversion case */ switch( new_type ) { case NIFTI_TYPE_INT8: /* new type */ { switch( old_type ) { case NIFTI_TYPE_INT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, char, olddata, char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, char, olddata, char, nvox); tried = 1; break; } case NIFTI_TYPE_UINT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, char, olddata, unsigned char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, char, olddata, unsigned char, nvox); tried = 1; break; } case NIFTI_TYPE_INT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, char, olddata, short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, char, olddata, short, nvox); tried = 1; break; } case NIFTI_TYPE_UINT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, char, olddata, unsigned short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, char, olddata, unsigned short, nvox); tried = 1; break; } case NIFTI_TYPE_INT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, char, olddata, int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, char, olddata, int, nvox); tried = 1; break; } case NIFTI_TYPE_UINT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, char, olddata, unsigned int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, char, olddata, unsigned int, nvox); tried = 1; break; } case NIFTI_TYPE_INT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, char, olddata, int64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, char, olddata, int64_t, nvox); tried = 1; break; } case NIFTI_TYPE_UINT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, char, olddata, uint64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, char, olddata, uint64_t, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, char, olddata, float, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, char, olddata, float, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, char, olddata, double, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, char, olddata, double, nvox); tried = 1; break; } default: /* not reachable */ break; } /* switch on old type */ break; } case NIFTI_TYPE_UINT8: /* new type */ { switch( old_type ) { case NIFTI_TYPE_INT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned char, olddata, char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned char, olddata, char, nvox); tried = 1; break; } case NIFTI_TYPE_UINT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned char, olddata, unsigned char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned char, olddata, unsigned char, nvox); tried = 1; break; } case NIFTI_TYPE_INT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned char, olddata, short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned char, olddata, short, nvox); tried = 1; break; } case NIFTI_TYPE_UINT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned char, olddata, unsigned short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned char, olddata, unsigned short, nvox); tried = 1; break; } case NIFTI_TYPE_INT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned char, olddata, int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned char, olddata, int, nvox); tried = 1; break; } case NIFTI_TYPE_UINT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned char, olddata, unsigned int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned char, olddata, unsigned int, nvox); tried = 1; break; } case NIFTI_TYPE_INT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned char, olddata, int64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned char, olddata, int64_t, nvox); tried = 1; break; } case NIFTI_TYPE_UINT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned char, olddata, uint64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned char, olddata, uint64_t, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned char, olddata, float, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned char, olddata, float, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned char, olddata, double, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned char, olddata, double, nvox); tried = 1; break; } default: /* not reachable */ break; } /* switch on old type */ break; } case NIFTI_TYPE_INT16: /* new type */ { switch( old_type ) { case NIFTI_TYPE_INT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, short, olddata, char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, short, olddata, char, nvox); tried = 1; break; } case NIFTI_TYPE_UINT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, short, olddata, unsigned char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, short, olddata, unsigned char, nvox); tried = 1; break; } case NIFTI_TYPE_INT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, short, olddata, short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, short, olddata, short, nvox); tried = 1; break; } case NIFTI_TYPE_UINT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, short, olddata, unsigned short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, short, olddata, unsigned short, nvox); tried = 1; break; } case NIFTI_TYPE_INT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, short, olddata, int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, short, olddata, int, nvox); tried = 1; break; } case NIFTI_TYPE_UINT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, short, olddata, unsigned int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, short, olddata, unsigned int, nvox); tried = 1; break; } case NIFTI_TYPE_INT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, short, olddata, int64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, short, olddata, int64_t, nvox); tried = 1; break; } case NIFTI_TYPE_UINT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, short, olddata, uint64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, short, olddata, uint64_t, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, short, olddata, float, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, short, olddata, float, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, short, olddata, double, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, short, olddata, double, nvox); tried = 1; break; } default: /* not reachable */ break; } /* switch on old type */ break; } case NIFTI_TYPE_UINT16: /* new type */ { switch( old_type ) { case NIFTI_TYPE_INT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned short, olddata, char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned short, olddata, char, nvox); tried = 1; break; } case NIFTI_TYPE_UINT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned short, olddata, unsigned char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned short, olddata, unsigned char, nvox); tried = 1; break; } case NIFTI_TYPE_INT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned short, olddata, short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned short, olddata, short, nvox); tried = 1; break; } case NIFTI_TYPE_UINT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned short, olddata, unsigned short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned short, olddata, unsigned short, nvox); tried = 1; break; } case NIFTI_TYPE_INT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned short, olddata, int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned short, olddata, int, nvox); tried = 1; break; } case NIFTI_TYPE_UINT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned short, olddata, unsigned int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned short, olddata, unsigned int, nvox); tried = 1; break; } case NIFTI_TYPE_INT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned short, olddata, int64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned short, olddata, int64_t, nvox); tried = 1; break; } case NIFTI_TYPE_UINT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned short, olddata, uint64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned short, olddata, uint64_t, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned short, olddata, float, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned short, olddata, float, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned short, olddata, double, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned short, olddata, double, nvox); tried = 1; break; } default: /* not reachable */ break; } /* switch on old type */ break; } case NIFTI_TYPE_INT32: /* new type */ { switch( old_type ) { case NIFTI_TYPE_INT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int, olddata, char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int, olddata, char, nvox); tried = 1; break; } case NIFTI_TYPE_UINT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int, olddata, unsigned char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int, olddata, unsigned char, nvox); tried = 1; break; } case NIFTI_TYPE_INT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int, olddata, short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int, olddata, short, nvox); tried = 1; break; } case NIFTI_TYPE_UINT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int, olddata, unsigned short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int, olddata, unsigned short, nvox); tried = 1; break; } case NIFTI_TYPE_INT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int, olddata, int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int, olddata, int, nvox); tried = 1; break; } case NIFTI_TYPE_UINT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int, olddata, unsigned int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int, olddata, unsigned int, nvox); tried = 1; break; } case NIFTI_TYPE_INT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int, olddata, int64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int, olddata, int64_t, nvox); tried = 1; break; } case NIFTI_TYPE_UINT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int, olddata, uint64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int, olddata, uint64_t, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int, olddata, float, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int, olddata, float, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int, olddata, double, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int, olddata, double, nvox); tried = 1; break; } default: /* not reachable */ break; } /* switch on old type */ break; } case NIFTI_TYPE_UINT32: /* new type */ { switch( old_type ) { case NIFTI_TYPE_INT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned int, olddata, char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned int, olddata, char, nvox); tried = 1; break; } case NIFTI_TYPE_UINT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned int, olddata, unsigned char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned int, olddata, unsigned char, nvox); tried = 1; break; } case NIFTI_TYPE_INT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned int, olddata, short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned int, olddata, short, nvox); tried = 1; break; } case NIFTI_TYPE_UINT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned int, olddata, unsigned short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned int, olddata, unsigned short, nvox); tried = 1; break; } case NIFTI_TYPE_INT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned int, olddata, int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned int, olddata, int, nvox); tried = 1; break; } case NIFTI_TYPE_UINT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned int, olddata, unsigned int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned int, olddata, unsigned int, nvox); tried = 1; break; } case NIFTI_TYPE_INT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned int, olddata, int64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned int, olddata, int64_t, nvox); tried = 1; break; } case NIFTI_TYPE_UINT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned int, olddata, uint64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned int, olddata, uint64_t, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned int, olddata, float, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned int, olddata, float, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, unsigned int, olddata, double, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, unsigned int, olddata, double, nvox); tried = 1; break; } default: /* not reachable */ break; } /* switch on old type */ break; } case NIFTI_TYPE_INT64: /* new type */ { switch( old_type ) { case NIFTI_TYPE_INT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int64_t, olddata, char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int64_t, olddata, char, nvox); tried = 1; break; } case NIFTI_TYPE_UINT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int64_t, olddata, unsigned char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int64_t, olddata, unsigned char, nvox); tried = 1; break; } case NIFTI_TYPE_INT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int64_t, olddata, short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int64_t, olddata, short, nvox); tried = 1; break; } case NIFTI_TYPE_UINT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int64_t, olddata, unsigned short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int64_t, olddata, unsigned short, nvox); tried = 1; break; } case NIFTI_TYPE_INT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int64_t, olddata, int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int64_t, olddata, int, nvox); tried = 1; break; } case NIFTI_TYPE_UINT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int64_t, olddata, unsigned int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int64_t, olddata, unsigned int, nvox); tried = 1; break; } case NIFTI_TYPE_INT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int64_t, olddata, int64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int64_t, olddata, int64_t, nvox); tried = 1; break; } case NIFTI_TYPE_UINT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int64_t, olddata, uint64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int64_t, olddata, uint64_t, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int64_t, olddata, float, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int64_t, olddata, float, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, int64_t, olddata, double, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, int64_t, olddata, double, nvox); tried = 1; break; } default: /* not reachable */ break; } /* switch on old type */ break; } case NIFTI_TYPE_UINT64: /* new type */ { switch( old_type ) { case NIFTI_TYPE_INT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, uint64_t, olddata, char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, uint64_t, olddata, char, nvox); tried = 1; break; } case NIFTI_TYPE_UINT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, uint64_t, olddata, unsigned char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, uint64_t, olddata, unsigned char, nvox); tried = 1; break; } case NIFTI_TYPE_INT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, uint64_t, olddata, short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, uint64_t, olddata, short, nvox); tried = 1; break; } case NIFTI_TYPE_UINT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, uint64_t, olddata, unsigned short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, uint64_t, olddata, unsigned short, nvox); tried = 1; break; } case NIFTI_TYPE_INT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, uint64_t, olddata, int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, uint64_t, olddata, int, nvox); tried = 1; break; } case NIFTI_TYPE_UINT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, uint64_t, olddata, unsigned int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, uint64_t, olddata, unsigned int, nvox); tried = 1; break; } case NIFTI_TYPE_INT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, uint64_t, olddata, int64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, uint64_t, olddata, int64_t, nvox); tried = 1; break; } case NIFTI_TYPE_UINT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, uint64_t, olddata, uint64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, uint64_t, olddata, uint64_t, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, uint64_t, olddata, float, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, uint64_t, olddata, float, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, uint64_t, olddata, double, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, uint64_t, olddata, double, nvox); tried = 1; break; } default: /* not reachable */ break; } /* switch on old type */ break; } case NIFTI_TYPE_FLOAT32: /* new type */ { switch( old_type ) { case NIFTI_TYPE_INT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, float, olddata, char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, float, olddata, char, nvox); tried = 1; break; } case NIFTI_TYPE_UINT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, float, olddata, unsigned char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, float, olddata, unsigned char, nvox); tried = 1; break; } case NIFTI_TYPE_INT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, float, olddata, short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, float, olddata, short, nvox); tried = 1; break; } case NIFTI_TYPE_UINT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, float, olddata, unsigned short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, float, olddata, unsigned short, nvox); tried = 1; break; } case NIFTI_TYPE_INT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, float, olddata, int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, float, olddata, int, nvox); tried = 1; break; } case NIFTI_TYPE_UINT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, float, olddata, unsigned int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, float, olddata, unsigned int, nvox); tried = 1; break; } case NIFTI_TYPE_INT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, float, olddata, int64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, float, olddata, int64_t, nvox); tried = 1; break; } case NIFTI_TYPE_UINT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, float, olddata, uint64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, float, olddata, uint64_t, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, float, olddata, float, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, float, olddata, float, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, float, olddata, double, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, float, olddata, double, nvox); tried = 1; break; } default: /* not reachable */ break; } /* switch on old type */ break; } case NIFTI_TYPE_FLOAT64: /* new type */ { switch( old_type ) { case NIFTI_TYPE_INT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, double, olddata, char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, double, olddata, char, nvox); tried = 1; break; } case NIFTI_TYPE_UINT8: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, double, olddata, unsigned char, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, double, olddata, unsigned char, nvox); tried = 1; break; } case NIFTI_TYPE_INT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, double, olddata, short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, double, olddata, short, nvox); tried = 1; break; } case NIFTI_TYPE_UINT16: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, double, olddata, unsigned short, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, double, olddata, unsigned short, nvox); tried = 1; break; } case NIFTI_TYPE_INT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, double, olddata, int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, double, olddata, int, nvox); tried = 1; break; } case NIFTI_TYPE_UINT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, double, olddata, unsigned int, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, double, olddata, unsigned int, nvox); tried = 1; break; } case NIFTI_TYPE_INT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, double, olddata, int64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, double, olddata, int64_t, nvox); tried = 1; break; } case NIFTI_TYPE_UINT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, double, olddata, uint64_t, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, double, olddata, uint64_t, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT32: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, double, olddata, float, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, double, olddata, float, nvox); tried = 1; break; } case NIFTI_TYPE_FLOAT64: { /* old type */ if( verify ) NT_DCONVERT_W_CHECKS(newdata, double, olddata, double, nvox, errs); else NT_DCONVERT_NO_CHECKS(newdata, double, olddata, double, nvox); tried = 1; break; } default: /* not reachable */ break; } /* switch on old type */ break; } default: /* not reachable */ break; } /* we should have at least tried every given case */ if ( !tried ) { fprintf(stderr, "** CND: did not try to convert %s to %s\n", nifti_datatype_to_string(old_type), nifti_datatype_to_string(new_type)); free(newdata); return -1; } /* assign converted data */ *retdata = newdata; /* possibly prepare to whine */ if ( verify && errs ) return 1; /* success */ return 0; } /*---------------------------------------------------------------------- * types will be made valid for conversion over time * todo: * NIFTI_TYPE_RGB24 * NIFTI_TYPE_RGBA32 NIFTI_TYPE_FLOAT128: - long double is not reliably 16 bytes? * NIFTI_TYPE_COMPLEX64 * NIFTI_TYPE_COMPLEX128 * NIFTI_TYPE_COMPLEX256 *----------------------------------------------------------------------*/ static int is_valid_conversion_type(int dtype) { switch( dtype ) { case NIFTI_TYPE_INT8: case NIFTI_TYPE_UINT8: case NIFTI_TYPE_INT16: case NIFTI_TYPE_UINT16: case NIFTI_TYPE_INT32: case NIFTI_TYPE_UINT32: case NIFTI_TYPE_INT64: case NIFTI_TYPE_UINT64: case NIFTI_TYPE_FLOAT32: case NIFTI_TYPE_FLOAT64: return 1; default: break; } return 0; } /*---------------------------------------------------------------------- * return whether a conversion can be done without checks * (e.g. int16 to int32, or int32 to float64) * * - note general type (int, float, complex), nbyper and whether signed * * Order of logic: consider RGB, complex, float and int general types * * - any RGB (if either type is RGB/RGBA) * - any complex (if either type is complex) * - any float (float or int, others are gone) * - both ints (signed or unsigned ints, others are gone) * * return 1 if lossless, 0 if lossy, -1 on error *----------------------------------------------------------------------*/ static int is_lossless(int old_type, int new_type) { int o_signed, n_signed; /* is signed type (old,new) */ int o_inttyp; /* is integral type (old) */ int o_rgbtyp, n_rgbtyp; /* is RGB type (old,new) */ int has_int_space; /* is there int/mati ssa space? */ /*-- invalid types are either binary (bits) or unknown --*/ if( ! nifti_datatype_is_valid(old_type, 1) || ! nifti_datatype_is_valid(new_type, 1) ) { if( g_debug > 0 ) fprintf(stderr,"** is_lossless: invalid types %d, %d\n", old_type, new_type); return -1; } /*---- assign general attributes (populate all local vars) ----*/ o_signed = type_is_signed(old_type); /* signed? */ n_signed = type_is_signed(new_type); o_inttyp = nifti_is_inttype(old_type); /* integral? only using old */ /* RGB? */ o_rgbtyp = ( old_type == NIFTI_TYPE_RGB24 || old_type == NIFTI_TYPE_RGBA32 ); n_rgbtyp = ( new_type == NIFTI_TYPE_RGB24 || new_type == NIFTI_TYPE_RGBA32 ); /* integral space */ has_int_space = int_size_of_type(new_type) >= int_size_of_type(old_type); /*---- RGB type (either) ----*/ if( o_rgbtyp || n_rgbtyp ) { /* if old is RGB, just require int space */ if( o_rgbtyp ) return has_int_space; /* else only new is RGB/A */ /* if old is signed or not an int type, return lossy */ if( o_signed || !o_inttyp ) return 0; /* else, just require space */ return has_int_space; } /*---- complex type (either) ----*/ if( type_is_complex(old_type) || type_is_complex(new_type) ) { /* complex to non-complex: lossy */ if( ! type_is_complex(new_type) ) return 0; /* so new type is complex, it just needs to be big enough */ /* (it is sufficient to compare int portions) */ return has_int_space; } /*---- float (non-int) type - similar to complex ----*/ if( !nifti_is_inttype(old_type) || !nifti_is_inttype(new_type) ) { /* non-int to int: lossy */ if( nifti_is_inttype(new_type) ) return 0; /* so new type is float, it just needs to be big enough */ /* (it is sufficient to compare int portions) */ return has_int_space; } /*---- int type (signed or unsigned, no RGB) ----*/ /* signed to unsigned is lossy, else just require space */ if( o_signed && !n_signed ) return 0; /* lossy (lost sign) */ /* just left with need for int bits space */ return has_int_space; } /*---------------------------------------------------------------------- * return the size of int precision, in bits * (the sign does not count) * * Doing this is bits allows us to deal with the sign. * * assuming IEEE 754 standard: * float32 handles 24 bits ( 3 bytes) * float64 handles 53 bits ( 6 bytes) * float128 handles 113 bits (14 bytes) * * Assume a proper type, only test in main or exported functions. *----------------------------------------------------------------------*/ static int int_size_of_type(int dtype) { switch( dtype ) { /* sort by ints (unsigned, signed), RGB, float */ case DT_BINARY: return 1; /* these use the full size */ case NIFTI_TYPE_UINT8: return 8; case NIFTI_TYPE_UINT16: return 16; case NIFTI_TYPE_UINT32: return 32; case NIFTI_TYPE_UINT64: return 64; case NIFTI_TYPE_INT8: return 7; /* these lose 1 sign bit */ case NIFTI_TYPE_INT16: return 15; case NIFTI_TYPE_INT32: return 31; case NIFTI_TYPE_INT64: return 63; case NIFTI_TYPE_RGB24: return 24; /* RGB: full size as UINT */ case NIFTI_TYPE_RGBA32: return 32; /* have complex match the float of half size */ case NIFTI_TYPE_FLOAT32: return 24; /* float: use mantissa */ case NIFTI_TYPE_COMPLEX64: return 24; /* complex: match half float */ case NIFTI_TYPE_FLOAT64: return 53; case NIFTI_TYPE_COMPLEX128: return 53; case NIFTI_TYPE_FLOAT128: return 113; case NIFTI_TYPE_COMPLEX256: return 113; default: break; /* prefer return at end */ } return 0; } /*---------------------------------------------------------------------- * Is the type a signed one? * Assume a proper type, only test in main or exported functions. *----------------------------------------------------------------------*/ static int type_is_signed(int dtype) { switch( dtype ) { case NIFTI_TYPE_UINT8: case NIFTI_TYPE_RGB24: case NIFTI_TYPE_UINT16: case NIFTI_TYPE_UINT32: case NIFTI_TYPE_UINT64: case NIFTI_TYPE_RGBA32: return 0; default: return 1; } return 1; /* unnecessary, but let's avoid compiler whining */ } /*---------------------------------------------------------------------- * Is the type a complex one? * Assume a proper type, only test in main or exported functions. *----------------------------------------------------------------------*/ static int type_is_complex(int dtype) { switch ( dtype ) { case NIFTI_TYPE_COMPLEX64: case NIFTI_TYPE_COMPLEX128: case NIFTI_TYPE_COMPLEX256: return 1; default: break; } return 0; } /*---------------------------------------------------------------------- * fill the nifti_1_header field list *----------------------------------------------------------------------*/ int fill_hdr1_field_array( field_s * nh_fields ) { nifti_1_header nhdr; field_s * nhf = nh_fields; int rv, errs; memset(nhf, 0, NT_HDR1_NUM_FIELDS*sizeof(field_s)); /* this macro takes (TYPE, NAME, NUM) and does: fill_field(nhdr, TYPE, NT_OFF(nhdr,NAME), NUM, "NAME"); nhf++; */ errs = 0; NT_SFILL(nhdr, nhf, DT_INT32, sizeof_hdr, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, NT_DT_STRING, data_type, 10, rv); errs += rv; NT_SFILL(nhdr, nhf, NT_DT_STRING, db_name, 18, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT32, extents, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT16, session_error, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, NT_DT_STRING, regular, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT8, dim_info, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT16, dim, 8, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, intent_p1, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, intent_p2, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, intent_p3, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT16, intent_code, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT16, datatype, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT16, bitpix, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT16, slice_start, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, pixdim, 8, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, vox_offset, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, scl_slope, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, scl_inter, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT16, slice_end, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT8, slice_code, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT8, xyzt_units, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, cal_max, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, cal_min, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, slice_duration, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, toffset, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT32, glmax, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT32, glmin, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, NT_DT_STRING, descrip, 80, rv); errs += rv; NT_SFILL(nhdr, nhf, NT_DT_STRING, aux_file, 24, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT16, qform_code, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT16, sform_code, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, quatern_b, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, quatern_c, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, quatern_d, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, qoffset_x, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, qoffset_y, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, qoffset_z, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, srow_x, 4, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, srow_y, 4, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT32, srow_z, 4, rv); errs += rv; NT_SFILL(nhdr, nhf, NT_DT_STRING, intent_name, 16, rv); errs += rv; NT_SFILL(nhdr, nhf, NT_DT_STRING, magic, 4, rv); errs += rv; if( errs > 0 ){ fprintf(stderr, "** %d fill_fields errors!\n", errs); return 1; } /* failure here is a serious problem */ if( check_total_size("nifti_1_header test: ", nh_fields, NT_HDR1_NUM_FIELDS, sizeof(nhdr)) ) return 1; if( g_debug > 3 ) disp_field_s_list("nh_fields: ", nh_fields, NT_HDR1_NUM_FIELDS); return 0; } /*---------------------------------------------------------------------- * fill the nifti_2_header field list *----------------------------------------------------------------------*/ int fill_hdr2_field_array( field_s * nh_fields ) { nifti_2_header nhdr; field_s * nhf = nh_fields; int rv, errs; memset(nhf, 0, NT_HDR2_NUM_FIELDS*sizeof(field_s)); /* this macro takes (TYPE, NAME, NUM) and does: fill_field(nhdr, TYPE, NT_OFF(nhdr,NAME), NUM, "NAME"); nhf++; */ errs = 0; NT_SFILL(nhdr, nhf, DT_INT32, sizeof_hdr, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, NT_DT_STRING, magic, 8, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT16, datatype, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT16, bitpix, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT64, dim, 8, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, intent_p1, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, intent_p2, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, intent_p3, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, pixdim, 8, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT64, vox_offset, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, scl_slope, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, scl_inter, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, cal_max, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, cal_min, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, slice_duration, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, toffset, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT64, slice_start, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT64, slice_end, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, NT_DT_STRING, descrip, 80, rv); errs += rv; NT_SFILL(nhdr, nhf, NT_DT_STRING, aux_file, 24, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT32, qform_code, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT32, sform_code, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, quatern_b, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, quatern_c, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, quatern_d, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, qoffset_x, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, qoffset_y, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, qoffset_z, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, srow_x, 4, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, srow_y, 4, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_FLOAT64, srow_z, 4, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT32, slice_code, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT32, xyzt_units, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT32, intent_code, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, NT_DT_STRING, intent_name, 16, rv); errs += rv; NT_SFILL(nhdr, nhf, DT_INT8, dim_info, 1, rv); errs += rv; NT_SFILL(nhdr, nhf, NT_DT_STRING, unused_str, 15, rv); errs += rv; if( errs > 0 ){ fprintf(stderr, "** %d fill_fields errors!\n", errs); return 1; } /* failure here is a serious problem */ if( check_total_size("nifti_2_header test: ", nh_fields, NT_HDR2_NUM_FIELDS, sizeof(nhdr)) ) return 1; if( g_debug > 3 ) disp_field_s_list("n2h_fields: ", nh_fields, NT_HDR2_NUM_FIELDS); return 0; } /*---------------------------------------------------------------------- * fill the nifti_image field list *----------------------------------------------------------------------*/ int fill_nim1_field_array( field_s * nim_fields ) { nifti1_image nim; field_s * nif = nim_fields; int rv, errs; memset(nif, 0, NT_NIM_NUM_FIELDS*sizeof(field_s)); errs = 0; NT_SFILL(nim, nif, DT_INT32, ndim, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, nx, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, ny, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, nz, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, nt, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, nu, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, nv, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, nw, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, dim, 8, rv); errs += rv; /* nvox: int32 -> size_t, 29 Jul 2007 -> int64_t, 29 Aug 2013 */ NT_SFILL(nim, nif, DT_INT64, nvox, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, nbyper, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, datatype, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, dx, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, dy, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, dz, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, dt, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, du, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, dv, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, dw, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, pixdim, 8, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, scl_slope, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, scl_inter, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, cal_min, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, cal_max, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, qform_code, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, sform_code, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, freq_dim, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, phase_dim, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, slice_dim, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, slice_code, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, slice_start, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, slice_end, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, slice_duration, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, quatern_b, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, quatern_c, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, quatern_d, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, qoffset_x, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, qoffset_y, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, qoffset_z, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, qfac, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, qto_xyz, 16, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, qto_ijk, 16, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, sto_xyz, 16, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, sto_ijk, 16, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, toffset, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, xyz_units, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, time_units, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, nifti_type, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, intent_code, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, intent_p1, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, intent_p2, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT32, intent_p3, 1, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_STRING, intent_name, 16, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_STRING, descrip, 80, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_STRING, aux_file, 24, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_CHAR_PTR, fname, 1, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_CHAR_PTR, iname, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, iname_offset, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, swapsize, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, byteorder, 1, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_POINTER, data, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, num_ext, 1, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_EXT_PTR, ext_list, 1, rv); errs += rv; if( errs > 0 ){ fprintf(stderr, "** %d fill_fields errors " "(note that pointers get aligned)\n", errs); return 1; } if( g_debug > 3 ) /* failure here is not an error condition */ check_total_size("nifti1_image test: ", nim_fields, NT_NIM_NUM_FIELDS, sizeof(nim)); if( g_debug > 3 ) disp_field_s_list("nim1_fields: ", nim_fields, NT_NIM_NUM_FIELDS); return 0; } /*---------------------------------------------------------------------- * fill the nifti2_image field list *----------------------------------------------------------------------*/ int fill_nim2_field_array( field_s * nim_fields ) { nifti2_image nim; field_s * nif = nim_fields; int rv, errs; memset(nif, 0, NT_NIM_NUM_FIELDS*sizeof(field_s)); errs = 0; NT_SFILL(nim, nif, DT_INT32, ndim, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT64, nx, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT64, ny, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT64, nz, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT64, nt, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT64, nu, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT64, nv, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT64, nw, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT64, dim, 8, rv); errs += rv; NT_SFILL(nim, nif, DT_INT64, nvox, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, nbyper, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, datatype, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, dx, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, dy, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, dz, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, dt, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, du, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, dv, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, dw, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, pixdim, 8, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, scl_slope, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, scl_inter, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, cal_min, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, cal_max, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, qform_code, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, sform_code, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, freq_dim, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, phase_dim, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, slice_dim, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, slice_code, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT64, slice_start, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT64, slice_end, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, slice_duration, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, quatern_b, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, quatern_c, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, quatern_d, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, qoffset_x, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, qoffset_y, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, qoffset_z, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, qfac, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, qto_xyz, 16, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, qto_ijk, 16, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, sto_xyz, 16, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, sto_ijk, 16, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, toffset, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, xyz_units, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, time_units, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, nifti_type, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, intent_code, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, intent_p1, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, intent_p2, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_FLOAT64, intent_p3, 1, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_STRING, intent_name, 16, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_STRING, descrip, 80, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_STRING, aux_file, 24, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_CHAR_PTR, fname, 1, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_CHAR_PTR, iname, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT64, iname_offset, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, swapsize, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, byteorder, 1, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_POINTER, data, 1, rv); errs += rv; NT_SFILL(nim, nif, DT_INT32, num_ext, 1, rv); errs += rv; NT_SFILL(nim, nif, NT_DT_EXT_PTR, ext_list, 1, rv); errs += rv; if( errs > 0 ){ fprintf(stderr, "** %d fill_fields errors " "(note that pointers get aligned)\n", errs); return 1; } if( g_debug > 4 ) /* failure here is not an error condition */ check_total_size("nifti2_image test: ", nim_fields, NT_NIM_NUM_FIELDS, sizeof(nim)); if( g_debug > 3 ) disp_field_s_list("nim2_fields: ", nim_fields, NT_NIM_NUM_FIELDS); return 0; } /*---------------------------------------------------------------------- * fill the nifti_analyze75 field list *----------------------------------------------------------------------*/ int fill_ana_field_array( field_s * ah_fields ) { nifti_analyze75 nhdr; field_s * ahf = ah_fields; int rv, errs; memset(ahf, 0, NT_ANA_NUM_FIELDS*sizeof(field_s)); /* this macro takes (TYPE, NAME, NUM) and does: fill_field(nhdr, TYPE, NT_OFF(nhdr,NAME), NUM, "NAME"); nhf++; */ errs = 0; NT_SFILL(nhdr, ahf, DT_INT32, sizeof_hdr, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, NT_DT_STRING, data_type, 10, rv); errs += rv; NT_SFILL(nhdr, ahf, NT_DT_STRING, db_name, 18, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT32, extents, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT16, session_error, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, NT_DT_STRING, regular, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT8, hkey_un0, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT16, dim, 8, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT16, unused8, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT16, unused9, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT16, unused10, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT16, unused11, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT16, unused12, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT16, unused13, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT16, unused14, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT16, datatype, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT16, bitpix, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT16, dim_un0, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_FLOAT32, pixdim, 8, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_FLOAT32, vox_offset, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_FLOAT32, funused1, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_FLOAT32, funused2, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_FLOAT32, funused3, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_FLOAT32, cal_max, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_FLOAT32, cal_min, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_FLOAT32, compressed, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_FLOAT32, verified, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT32, glmax, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT32, glmin, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, NT_DT_STRING, descrip, 80, rv); errs += rv; NT_SFILL(nhdr, ahf, NT_DT_STRING, aux_file, 24, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT8, orient, 1, rv); errs += rv; /* originator is 5 (3) shorts, not 10 chars 26 Sep 2012 [rickr] */ NT_SFILL(nhdr, ahf, DT_INT16, originator, 5, rv); errs += rv; NT_SFILL(nhdr, ahf, NT_DT_STRING, generated, 10, rv); errs += rv; NT_SFILL(nhdr, ahf, NT_DT_STRING, scannum, 10, rv); errs += rv; NT_SFILL(nhdr, ahf, NT_DT_STRING, patient_id, 10, rv); errs += rv; NT_SFILL(nhdr, ahf, NT_DT_STRING, exp_date, 10, rv); errs += rv; NT_SFILL(nhdr, ahf, NT_DT_STRING, exp_time, 10, rv); errs += rv; NT_SFILL(nhdr, ahf, NT_DT_STRING, hist_un0, 3, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT32, views , 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT32, vols_added, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT32, start_field, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT32, field_skip, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT32, omax, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT32, omin, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT32, smax, 1, rv); errs += rv; NT_SFILL(nhdr, ahf, DT_INT32, smin, 1, rv); errs += rv; if( errs > 0 ){ fprintf(stderr, "** %d ana fill_fields errors!\n", errs); return 1; } /* failure here is a serious problem */ if( check_total_size("nifti_analyze75 test: ", ah_fields, NT_ANA_NUM_FIELDS, sizeof(nhdr)) ) return 1; if( g_debug > 3 ) disp_field_s_list("ah_fields: ", ah_fields, NT_ANA_NUM_FIELDS); return 0; } /*---------------------------------------------------------------------- * compare sizes to offset, including total *----------------------------------------------------------------------*/ int check_total_size( const char *mesg, field_s * fields, int nfields, int tot_size ) { field_s * fp; int c, total; int bad_offs; total = 0; bad_offs = 0; for( c = 0, fp = fields; c < nfields; c++, fp++ ){ if( fp->offset != total ){ if( g_debug > 3 ) fprintf(stderr,"** bad offset for field '%s'\n" " offset = %d, total = %d\n", fp->name, fp->offset, total); bad_offs++; } total += fp->size * fp->len; } if( g_debug > 1 || (g_debug > 0 && bad_offs > 0) ){ fputs(mesg, stderr); c = 0; if( bad_offs > 0 ){ fprintf(stderr,"** found %d bad offsets\n", bad_offs); c++; } if( total != tot_size ){ fprintf(stderr,"** computed total %d not equal to struct size %d\n", total, tot_size); c++; } if( c == 0 ) fputs("... okay\n", stderr); } if( bad_offs > 0 ) return 1; return 0; } /*---------------------------------------------------------------------- * fill the field structure with the given data *----------------------------------------------------------------------*/ int fill_field( field_s * fp, int type, int offset, int num, const char * name ) { fp->type = type; fp->offset = offset; fp->size = 1; /* init before check */ fp->len = num; strncpy(fp->name, name, NT_FIELD_NAME_LEN-1); switch( type ){ case DT_UNKNOWN: case DT_INT8: case NT_DT_STRING: fp->size = 1; break; case DT_INT16: fp->size = 2; break; case DT_INT32: case DT_FLOAT32: fp->size = 4; break; case DT_INT64: case DT_UINT64: case DT_FLOAT64: case DT_COMPLEX64: fp->size = 8; break; case NT_DT_POINTER: case NT_DT_CHAR_PTR: case NT_DT_EXT_PTR: fp->size = (int)sizeof(void *); break; default: fprintf(stderr,"** fill_field: invalid type %d\n", type ); return 1; } return 0; } /*---------------------------------------------------------------------- * return a string matching the type *----------------------------------------------------------------------*/ const char * field_type_str( int type ) { if( type == DT_INT8 ) return "DT_INT8"; if( type == DT_INT16 ) return "DT_INT16"; if( type == DT_INT32 ) return "DT_INT32"; if( type == DT_INT64 ) return "DT_INT64"; if( type == DT_UINT8 ) return "DT_UINT8"; if( type == DT_UINT16 ) return "DT_UINT16"; if( type == DT_UINT32 ) return "DT_UINT32"; if( type == DT_UINT64 ) return "DT_UINT64"; if( type == DT_FLOAT32 ) return "DT_FLOAT32"; if( type == DT_FLOAT64 ) return "DT_FLOAT64"; if( type == DT_COMPLEX64 ) return "DT_COMPLEX64"; if( type == DT_COMPLEX128 ) return "DT_COMPLEX128"; if( type == DT_RGB24 ) return "DT_RGB24"; if( type == NT_DT_STRING ) return "NT_DT_STRING"; if( type == NT_DT_POINTER ) return "NT_DT_POINTER"; if( type == NT_DT_CHAR_PTR ) return "NT_DT_CHAR_PTR"; /* longest: 14 */ if( type == NT_DT_EXT_PTR ) return "NT_DT_EXT_PTR"; return "DT_UNKNOWN"; /* for DT_UNKNOWN, or as an else */ } /*---------------------------------------------------------------------- * display the contents of all of the field structures *----------------------------------------------------------------------*/ int disp_field_s_list( const char *mesg, field_s * fp, int nfields ) { int c, total=0; if( mesg ) fputs(mesg, stdout); fprintf(stdout," %d fields:\n" " name size len offset type\n" " ------------------- ---- --- ------ --------------\n", nfields); for( c = 0; c < nfields; c++, fp++ ) { fprintf(stdout," %-*s %4d %3d %4d %-14s\n", NT_FIELD_NAME_LEN-1, fp->name, fp->size, fp->len, fp->offset, field_type_str(fp->type)); total += fp->size*fp->len; } fprintf(stdout, "\n total size: %d\n\n", total); return 0; } /*---------------------------------------------------------------------- * display the contents of all of the field structures *----------------------------------------------------------------------*/ int disp_field(const char *mesg, field_s *fieldp, void * str, int nfields, int header) { field_s * fp; int c; if( mesg ) fputs(mesg, stdout); if( header && g_debug > 0 ){ fprintf(stdout, " name offset nvals values\n"); fprintf(stdout, " ------------------- ------ ----- ------\n"); } fp = fieldp; for( c = 0; c < nfields; c++, fp++ ) { /* start by displaying the field information */ if( g_debug > 0 ) fprintf(stdout, " %-*.*s %4d %3d ", NT_FIELD_NAME_LEN-1, NT_FIELD_NAME_LEN-1, fp->name, fp->offset, fp->len); /* now, print the value(s), depending on the type */ switch( fp->type ){ case DT_UNKNOWN: default: fprintf(stdout,"(unknown data type)\n"); break; case DT_INT8: case DT_UINT8: case DT_INT16: case DT_UINT16: case DT_INT32: case DT_UINT32: case DT_INT64: case DT_FLOAT32: case DT_FLOAT64: disp_raw_data((char *)str+fp->offset, fp->type, fp->len, ' ', 1); break; case NT_DT_POINTER: fprintf(stdout,"(raw data of unknown type)\n"); break; case NT_DT_CHAR_PTR: /* look for string of length <= 40 */ { char * sp; int len; /* start by sucking the pointer stored here */ sp = *(char **)((char *)str + fp->offset); if( ! sp ){ fprintf(stdout,"(NULL)\n"); break; } /* anything? */ /* see if we have a printable string here */ for(len = 0; len <= 40 && *sp && isprint(*sp); len++, sp++ ) ; if( len > 40 ) fprintf(stdout,"(apparent long string)\n"); else if ( len == 0 ) fprintf(stdout,"(empty string)\n"); else if( *sp && !isprint(*sp) ) /* if no termination, it's bad */ fprintf(stdout,"(non-printable string)\n"); else /* woohoo! a good string */ fprintf(stdout,"'%.40s'\n",*(char **)((char *)str + fp->offset)); break; } case NT_DT_EXT_PTR: { nifti1_extension * extp; /* yank the address sitting there into extp */ extp = *(nifti1_extension **)((char *)str + fp->offset); /* the user may use -disp_exts to display all of them */ if( extp ) disp_nifti1_extension(NULL, extp, 6); else fprintf(stdout,"(NULL)\n"); break; } case NT_DT_STRING: { char * charp = (char *)str + fp->offset; fprintf(stdout,"%.*s\n", fp->len, charp); break; } } } return 0; } /*---------------------------------------------------------------------- * no display, just return whether any fields differ *----------------------------------------------------------------------*/ int diff_field(field_s *fieldp, void * str0, void * str1, int nfields) { field_s * fp; char * cp0, * cp1; int fnum, c, size; fp = fieldp; for( fnum = 0; fnum < nfields; fnum++, fp++ ) { switch( fp->type ){ case DT_UNKNOWN: /* all basic types are easy */ case DT_INT8: case DT_INT16: case DT_INT32: case DT_INT64: case DT_FLOAT32: case DT_FLOAT64: case NT_DT_STRING: size = fp->size * fp->len; /* total field size */ cp0 = (char *)str0 + fp->offset; cp1 = (char *)str1 + fp->offset; for( c = 0; c < size; c++, cp0++, cp1++ ) if( *cp0 != *cp1 ) break; if(c < size) return 1; /* found a diff */ break; case NT_DT_POINTER: /* let's pass on these - no diff */ case NT_DT_CHAR_PTR: break; case NT_DT_EXT_PTR: { nifti1_extension * ext0, * ext1; ext0 = *(nifti1_extension **)((char *)str0 + fp->offset); ext1 = *(nifti1_extension **)((char *)str1 + fp->offset); if( ! ext0 && ! ext1 ) break; /* continue on */ if( ext0 && ! ext1 ) return 1; /* pointer diff is diff */ if( ! ext0 && ext1 ) return 1; /* just check size and type for a single extension */ if( ext0->esize != ext1->esize ) return 1; if( ext0->ecode != ext1->ecode ) return 1; break; } } } return 0; /* no diffs found */ } /*---------------------------------------------------------------------- * display a single extension *----------------------------------------------------------------------*/ int disp_cifti_extension( const char *mesg, nifti1_extension * ext, int maxlen) { FILE * outfp = stdout; int len; if( mesg ) fputs(mesg, outfp); if( !ext ) { fprintf(stderr,"** no extension to display\n"); return 1; } if( ext->ecode != NIFTI_ECODE_CIFTI ) { fprintf(stderr,"** extension code %d is not CIFTI\n", ext->ecode); return 1; } if( g_debug > 1 ) fprintf(outfp,"ecode = %d, esize = %d, edata = ", ext->ecode,ext->esize); if( !ext->edata ) fprintf(outfp,"(NULL)\n"); else { len = ext->esize-8; if( maxlen >= 0 && len > maxlen ) len = maxlen; fprintf(outfp,"%.*s\n", len, (char *)ext->edata); } fflush(outfp); return 0; } /*---------------------------------------------------------------------- * display a single extension *----------------------------------------------------------------------*/ int disp_nifti1_extension( const char *mesg, nifti1_extension * ext, int maxlen) { FILE * outfp = stdout; int len; if( mesg ) fputs(mesg, outfp); if( !ext ) { fprintf(stderr,"** no extension to display\n"); return 1; } if( g_debug > 0 ) fprintf(outfp,"ecode = %d, esize = %d, edata = ", ext->ecode,ext->esize); if( !ext->edata ) fprintf(outfp,"(NULL)\n"); else if ( ext->ecode == NIFTI_ECODE_AFNI || ext->ecode == NIFTI_ECODE_COMMENT || ext->ecode == NIFTI_ECODE_CIFTI ) { len = ext->esize-8; if( maxlen >= 0 && len > maxlen ) len = maxlen; fprintf(outfp,"%.*s\n", len, (char *)ext->edata); } else fprintf(outfp,"(unknown data type)\n"); fflush(outfp); return 0; } /*---------------------------------------------------------------------- * return the appropritate pointer into the g_hdr1_fields struct *----------------------------------------------------------------------*/ field_s * get_hdr1_field( const char * fname, int show_fail ) { field_s * fp; int c; if( ! fname || *fname == '\0' ) return NULL; fp = g_hdr1_fields; for( c = 0; c < NT_HDR1_NUM_FIELDS; c++, fp++ ) if( strcmp(fname, fp->name) == 0 ) break; if( c == NT_HDR1_NUM_FIELDS ) { if( show_fail > 0 ) fprintf(stderr,"** get_hdr1_field: field not found in hdr: %s\n",fname); return NULL; } return fp; } /*---------------------------------------------------------------------- * return the appropritate pointer into the g_hdr1_fields struct *----------------------------------------------------------------------*/ field_s * get_hdr2_field( const char * fname, int show_fail ) { field_s * fp; int c; if( ! fname || *fname == '\0' ) return NULL; fp = g_hdr2_fields; for( c = 0; c < NT_HDR2_NUM_FIELDS; c++, fp++ ) if( strcmp(fname, fp->name) == 0 ) break; if( c == NT_HDR2_NUM_FIELDS ) { if( show_fail > 0 ) fprintf(stderr,"** get_hdr2_field: field not found in hdr: %s\n",fname); return NULL; } return fp; } /*---------------------------------------------------------------------- * return the appropritate pointer into the g_hdr1_fields struct *----------------------------------------------------------------------*/ field_s * get_nim_field( const char * fname, int show_fail ) { field_s * fp; int c; if( ! fname || *fname == '\0' ) return NULL; fp = g_nim2_fields; for( c = 0; c < NT_NIM_NUM_FIELDS; c++, fp++ ) if( strcmp(fname, fp->name) == 0 ) break; if( c == NT_NIM_NUM_FIELDS ) { if( show_fail > 0 ) fprintf(stderr,"** get_nim_field: field not found in hdr: %s\n",fname); return NULL; } return fp; } /*---------------------------------------------------------------------- * return the number of fields that differ *----------------------------------------------------------------------*/ int diff_hdr1s( nifti_1_header * s0, nifti_1_header * s1, int display ) { field_s * fp = g_hdr1_fields; int c, ndiff = 0; for( c = 0; c < NT_HDR1_NUM_FIELDS; c++, fp++ ) if( diff_field(fp, s0, s1, 1) ) { if( display ) disp_field(NULL, fp, s0, 1, ndiff == 0); if( display ) disp_field(NULL, fp, s1, 1, 0); ndiff++; } return ndiff; } /*---------------------------------------------------------------------- * return the number of fields that differ *----------------------------------------------------------------------*/ int diff_hdr2s( nifti_2_header * s0, nifti_2_header * s1, int display ) { field_s * fp = g_hdr2_fields; int c, ndiff = 0; for( c = 0; c < NT_HDR2_NUM_FIELDS; c++, fp++ ) if( diff_field(fp, s0, s1, 1) ) { if( display ) disp_field(NULL, fp, s0, 1, ndiff == 0); if( display ) disp_field(NULL, fp, s1, 1, 0); ndiff++; } return ndiff; } /*---------------------------------------------------------------------- * return the number of fields that differ *----------------------------------------------------------------------*/ int diff_nims( nifti_image * s0, nifti_image * s1, int display ) { field_s * fp = g_nim2_fields; int c, ndiff = 0; for( c = 0; c < NT_NIM_NUM_FIELDS; c++, fp++ ) if( diff_field(fp, s0, s1, 1) ) { if( display ) disp_field(NULL, fp, s0, 1, ndiff == 0); if( display ) disp_field(NULL, fp, s1, 1, 0); ndiff++; } return ndiff; } /*---------------------------------------------------------------------- * return the number of fields that differ *----------------------------------------------------------------------*/ int diff_hdr1s_list( nifti_1_header * s0, nifti_1_header * s1, str_list * slist, int display ) { field_s * fp; const char ** sptr; int c, ndiff = 0; sptr = slist->list; for( c = 0; c < slist->len; c++ ) { fp = get_hdr1_field(*sptr, 1); /* "not found" displayed in func */ if( fp && diff_field(fp, s0, s1, 1) ) { if( display ) disp_field(NULL, fp, s0, 1, ndiff == 0); if( display ) disp_field(NULL, fp, s1, 1, 0); ndiff++; } sptr++; } return ndiff; } /*---------------------------------------------------------------------- * return the number of fields that differ *----------------------------------------------------------------------*/ int diff_hdr2s_list( nifti_2_header * s0, nifti_2_header * s1, str_list * slist, int display ) { field_s * fp; const char ** sptr; int c, ndiff = 0; sptr = slist->list; for( c = 0; c < slist->len; c++ ) { fp = get_hdr2_field(*sptr, 1); /* "not found" displayed in func */ if( fp && diff_field(fp, s0, s1, 1) ) { if( display ) disp_field(NULL, fp, s0, 1, ndiff == 0); if( display ) disp_field(NULL, fp, s1, 1, 0); ndiff++; } sptr++; } return ndiff; } /*---------------------------------------------------------------------- * return the number of fields that differ *----------------------------------------------------------------------*/ int diff_nims_list( nifti_image * s0, nifti_image * s1, str_list * slist, int display ) { field_s * fp; const char ** sptr; int c, ndiff = 0; sptr = slist->list; for( c = 0; c < slist->len; c++ ) { fp = get_nim_field(*sptr, 1); /* "not found" displayed in func */ if( fp && diff_field(fp, s0, s1, 1) ) { if( display ) disp_field(NULL, fp, s0, 1, ndiff == 0); if( display ) disp_field(NULL, fp, s1, 1, 0); ndiff++; } sptr++; } return ndiff; } /*---------------------------------------------------------------------- * display data from collapsed_image *----------------------------------------------------------------------*/ int act_disp_ci( nt_opts * opts ) { nifti_image * nim; void * data = NULL; char space = ' '; /* use space or newline */ int filenum, err; int64_t len64; if( opts->dci_lines ) space = '\n'; /* then use newlines as separators */ if( g_debug > 2 && opts->dts ) { fprintf(stderr,"-d displaying time series at (i,j,k) = (" "%" PRId64 ",%" PRId64 ",%" PRId64 ")\n" " for %d nifti datasets...\n\n", opts->ci_dims[1], opts->ci_dims[2], opts->ci_dims[3], opts->infiles.len); } else if ( g_debug > 2 ) /* the general collapsed image form */ { fprintf(stderr,"-d displaying collapsed image for %d datasets...\n\n" " dims = ", opts->infiles.len); disp_raw_data(opts->ci_dims, DT_INT64, 8, ' ', 1); } for( filenum = 0; filenum < opts->infiles.len; filenum++ ) { err = 0; nim = nt_image_read(opts, opts->infiles.list[filenum], 0, 0); if( !nim ) continue; /* errors are printed from library */ if( opts->dts && nim->ndim != 4 ) { fprintf(stderr,"** error: dataset '%s' is not 4-dimensional\n", nim->fname); err++; } switch( nim->datatype ) { case DT_INT8: case DT_INT16: case DT_INT32: case DT_INT64: case DT_UINT8: case DT_UINT16: case DT_UINT32: case DT_FLOAT32: case DT_FLOAT64: if( g_debug > 1 ) fprintf(stderr,"-d datatype %d of size %d\n", nim->datatype, nim->nbyper); break; default: fprintf(stderr,"** dataset '%s' has unknown type %d\n", nim->fname, nim->datatype); err++; break; } if( err ) { nifti_image_free(nim); continue; } len64 = nifti_read_collapsed_image(nim, opts->ci_dims, &data); if( len64 < 0 || !data ) { fprintf(stderr,"** FAILURE for dataset '%s'\n", nim->fname); if( data ) { free(data); data = NULL; } err++; } else if ( len64/nim->nbyper > INT_MAX ) { fprintf(stderr,"** %" PRId64 " is too many values to display\n", len64/nim->nbyper); if( data ) { free(data); data = NULL; } err++; } /* remove check for length of time series 24 Apr 2006 */ if( err ){ nifti_image_free(nim); continue; } /* now just print the results */ if( g_debug > 0 ) { fprintf(stdout,"\ndataset '%s' @ (", nim->fname); if( opts->dts ) disp_raw_data(opts->ci_dims+1, DT_INT64, 3, ' ', 0); else disp_raw_data(opts->ci_dims+1, DT_INT64, 7, ' ', 0); fprintf(stdout,")\n"); } /* should we change disp_raw_data to allow for 64-bit nvalues? */ disp_raw_data(data, nim->datatype, len64 / nim->nbyper, space, 1); nifti_image_free(nim); } if( data ) free(data); return 0; } #define NT_LOC_MAX_FLOAT_BUF 32 int disp_raw_data( void * data, int type, int nvals, char space, int newline ) { char * dp, fbuf[NT_LOC_MAX_FLOAT_BUF]; int c, size, nchar; nifti_datatype_sizes( type, &size, NULL ); /* get nbyper */ for( c = 0, dp = (char *)data; c < nvals; c++, dp += size ) { switch( type ) { case DT_INT8: printf("%d", *(char *)dp); break; case DT_INT16: { short temp; memcpy(&temp, dp, sizeof(temp)); printf("%d", temp); break; } case DT_INT32: { int temp; memcpy(&temp, dp, sizeof(temp)); printf("%d", temp); break; } case DT_INT64: { int64_t temp; memcpy(&temp, dp, sizeof(temp)); printf("%"PRId64, temp); break; } case DT_UINT8: { unsigned char temp; memcpy(&temp, dp, sizeof(temp)); printf("%u", temp); break; } case DT_UINT16: { unsigned short temp; memcpy(&temp, dp, sizeof(temp)); printf("%u", temp); break; } case DT_UINT32: { unsigned int temp; memcpy(&temp, dp, sizeof(temp)); printf("%u", temp); break; } case DT_FLOAT32: { float temp; memcpy(&temp, dp, sizeof(temp)); nchar = snprintf(fbuf, NT_LOC_MAX_FLOAT_BUF, "%f", temp); /* if it is a large number for some reason, print as is */ if( nchar >= NT_LOC_MAX_FLOAT_BUF ) { printf("%f", temp); } else { clear_float_zeros(fbuf); printf("%s", fbuf); } break; } case DT_FLOAT64: { double temp; memcpy(&temp, dp, sizeof(temp)); nchar = snprintf(fbuf, NT_LOC_MAX_FLOAT_BUF, "%lf", temp); /* if it is a large number for some reason, print as is */ if( nchar >= NT_LOC_MAX_FLOAT_BUF ) { printf("%lf", temp); } else { clear_float_zeros(fbuf); printf("%s", fbuf); } break; } default: fprintf(stderr,"** disp_raw_data: unknown type %d\n", type); return 1; } if( c < nvals - 1 ) fputc(space,stdout); } if ( newline ) fputc('\n',stdout); return 0; } /*---------------------------------------------------------------------- * remove trailing zeros from string of printed float * (of a max NT_LOC_MAX_FLOAT_BUF (32) string) * return 1 if something was cleared * 0 if not *----------------------------------------------------------------------*/ int clear_float_zeros( char * str ) { char * dp = strchr(str, '.'), * valp; size_t len; if( !dp ) return 0; /* nothing to clear */ len = strlen(dp); /* never clear what is just to the right of '.' */ for( valp = dp+len-1; (valp > dp+1) && (*valp==' ' || *valp=='0'); valp-- ) *valp = '\0'; /* clear, so we don't worry about break conditions */ if( valp < dp + len - 1 ) return 1; return 0; } /* return the number of volumes in the nifti_image */ static int num_volumes(nifti_image * nim) { int ind, nvols = 1; if( nim->dim[0] < 1 ) return 0; for( ind = 4; ind <= nim->dim[0]; ind++ ) nvols *= nim->dim[ind]; return nvols; } /*---------------------------------------------------------------------- * run various tests *----------------------------------------------------------------------*/ int act_run_misc_tests( nt_opts * opts ) { nifti_image * nim; const char * fname; int fc; if( g_debug > 1 ) fprintf(stderr,"-d running misc. tests for %d files...\n", opts->infiles.len); for( fc = 0; fc < opts->infiles.len; fc++ ) { fname = opts->infiles.list[fc]; if( g_debug > 1 ) { fprintf(stderr,"-- testing file %s, type = %d\n", fname, is_nifti_file(fname)); } nim = nt_image_read(opts, fname, 0, 0); if( !nim ) return 1; /* errors are printed from library */ /* actually run the tests */ nt_run_misc_nim_tests(nim); nifti_image_free(nim); } return 0; } /*---------------------------------------------------------------------- * run some tests: * * - dmat44 -> mat44 -> dmat44 * - inv(inv([d]mat44)) == I? (check maxabs[i(i(m))-M-I] close to 0) * - [d]mat->quatern->mat * - display orientation given [d]mat44 *----------------------------------------------------------------------*/ int nt_run_misc_nim_tests(nifti_image * nim) { nifti_image * nim_copy; nifti_dmat44 dmat, dmat2, I; nifti_dmat33 d33, d33_2, I33; char mesg[80] = ""; int ival; if( !nim ) { fprintf(stderr,"** nt_run_misc_nim_tests: nim == NULL\n"); return 1; } fflush(stderr); /* clear any old text before stdout */ if( g_debug ) printf("------------------------------------------------------------\n" "testing : %s\n\n", nim->fname); snprintf(mesg, sizeof(mesg), "= qform_code = %d\n", nim->qform_code); nifti_disp_matrix_orient(mesg, nim->qto_xyz); snprintf(mesg, sizeof(mesg), "= sform_code = %d\n", nim->sform_code); nifti_disp_matrix_orient(mesg, nim->sto_xyz); /* actually display the sform */ printf("= sform: "); disp_raw_data((char *)(nim->sto_xyz.m), DT_FLOAT64, 16, ' ', 1); /* tests inverses */ dmat = nifti_dmat44_inverse(nim->sto_xyz); dmat2 = nifti_dmat44_mul(dmat, nim->sto_xyz); printf("= max_fabs(sform) = %lf\n", dmat44_max_fabs(dmat2)); /* compare dmat2 with I */ NT_MAT44_SET_TO_IDENTITY(I); /* dmat = dmat2 - I */ NT_MAT44_SUBTRACT(dmat, dmat2, I); printf("= max_fabs(Sinv*S - I) = %lf\n", dmat44_max_fabs(dmat)); /* do a similar comparison with 3x3 */ NT_MAT44_TO_MAT33(nim->sto_xyz, d33_2); d33 = nifti_dmat33_inverse(d33_2); d33_2 = nifti_dmat33_mul(d33, d33_2); NT_MAT33_SET_TO_IDENTITY(I33); /* d33 = d33_2 - I33 */ NT_MAT33_SUBTRACT(d33, d33_2, I33); NT_MAT33_TO_MAT44(d33, dmat); /* but do not fill as identity */ dmat.m[3][3] = 0; printf("= max_fabs(S33inv*S33 - I) = %lf\n", dmat44_max_fabs(dmat)); nt_test_dmat44_quatern(nim); nim_copy = nifti_copy_nim_info(nim); ival = diff_nims(nim, nim_copy, 1); nifti_image_free(nim_copy); printf("= diff in nim copy (hopefully 0): %d\n", ival); /* test nifti_read_subregion_image() - just get one voxel */ { int64_t start_ind[] = {0,0,0,0,0,0,0}; int64_t size[] = {2,1,1,1,1,1,1}; int64_t rval; float * dptr=NULL; rval = nifti_read_subregion_image(nim, start_ind, size, (void**)&dptr); printf("== subregion: rv=%" PRId64 ", dptr=%p, data=", rval, (void *)dptr); if( dptr ) disp_raw_data((char *)dptr, nim->datatype, 1, ' ', 1); if( dptr ) free(dptr); } /* test expansion of ints, as 32-bits, not usually used */ { int * ilist = NULL; const char * istr = "7,4,2..5,11..$"; ilist = nifti_get_intlist(15, istr); printf("= ilist = %p, %d\n", (void *)ilist, ilist?ilist[0]:-1); if( ilist ) free(ilist); } return 0; } static int nt_test_dmat44_quatern(nifti_image * nim) { nifti_dmat44 dmat, dmat2; mat44 mat, mat0, mat2, I; double qb, qc, qd, qx, qy, qz; double dx, dy, dz, qfac; float fb, fc, fd, fx, fy, fz; float x, y, z, fac; fputc('\n', stdout); /* and the orthogonalized form */ printf("= sform vs. orthog sform:\n"); dmat = nim->sto_xyz; dmat = nifti_make_orthog_dmat44( dmat.m[0][0], dmat.m[0][1], dmat.m[0][2], dmat.m[1][0], dmat.m[1][1], dmat.m[1][2], dmat.m[2][0], dmat.m[2][1], dmat.m[2][2]); disp_raw_data((char *)(nim->sto_xyz.m), DT_FLOAT64, 16, ' ', 1); disp_raw_data(dmat.m, DT_FLOAT64, 16, ' ', 1); /* go to quatern and back */ nifti_dmat44_to_quatern(nim->sto_xyz, &qb, &qc, &qd, &qx, &qy, &qz, &dx, &dy, &dz, &qfac); dmat = nifti_quatern_to_dmat44(qb, qc, qd, qx, qy, qz, dx, dy, dz, qfac); /* did this invert? */ NT_MAT44_SUBTRACT(dmat2, nim->sto_xyz, dmat); printf("= max_fabs(s->quatern->s') = %lf\n", dmat44_max_fabs(dmat2)); /* try for float mat44 */ nifti_dmat44_to_mat44(&nim->sto_xyz, &mat0); nifti_mat44_to_quatern(mat0, &fb, &fc, &fd, &fx, &fy, &fz, &x, &y, &z, &fac); mat = nifti_quatern_to_mat44(fb, fc, fd, fx, fy, fz, x, y, z, fac); NT_MAT44_SUBTRACT(mat2, mat0, mat); printf("= max_fabs_m44(s->quatern->s') = %f\n", mat44_max_fabs(mat2)); /* inverse check */ mat2 = nifti_mat44_inverse(mat); mat0 = nifti_mat44_mul(mat, mat2); NT_MAT44_SET_TO_IDENTITY(I); NT_MAT44_SUBTRACT(mat, mat0, I); /* use mat44 for orientation */ mat = nifti_quatern_to_mat44(fb, fc, fd, fx, fy, fz, x, y, z, fac); nt_disp_mat44_orient("= mat44 orient:\n", mat); mat = nifti_make_orthog_mat44( mat.m[0][0], mat.m[0][1], mat.m[0][2], mat.m[1][0], mat.m[1][1], mat.m[1][2], mat.m[2][0], mat.m[2][1], mat.m[2][2]); nt_disp_mat44_orient("= mat44 orthog orient:\n", mat); /* compare orthogonalization */ printf("= qform vs. orthog mat44 form:\n"); disp_raw_data((char *)(nim->qto_xyz.m), DT_FLOAT64, 16, ' ', 1); disp_raw_data(mat.m, DT_FLOAT32, 16, ' ', 1); return 0; } static int nt_disp_mat44_orient(const char * mesg, mat44 mat) { int i, j, k; if ( mesg ) fputs( mesg, stdout ); nifti_mat44_to_orientation( mat, &i,&j,&k ); if ( i <= 0 || j <= 0 || k <= 0 ) { printf("** bad orient\n"); return -1; } /* so we have good codes */ printf(" i orientation = '%s'\n" " j orientation = '%s'\n" " k orientation = '%s'\n", nifti_orientation_string(i), nifti_orientation_string(j), nifti_orientation_string(k) ); return 0; } /* return max abs of the matrix values */ static double dmat44_max_fabs(nifti_dmat44 m) { double max = 0.0; int i,j; for( i=0; i<4; i++ ) for( j=0; j<4; j++ ) if( fabs(m.m[i][j]) > max ) max = fabs(m.m[i][j]); return max; } /* return max abs of the matrix values */ static double mat44_max_fabs(mat44 m) { float max = 0.0; int i,j; for( i=0; i<4; i++ ) for( j=0; j<4; j++ ) if( fabs(m.m[i][j]) > max ) max = fabs(m.m[i][j]); return max; } /*---------------------------------------------------------------------- * create a new dataset using sub-brick selection *----------------------------------------------------------------------*/ int act_cbl( nt_opts * opts ) { nifti_brick_list NBL; nifti_image * nim; char * fname, * selstr, * cp; int64_t * blist; int err = 0; if( g_debug > 2 ) fprintf(stderr,"-d copying file info from '%s' to '%s'\n", opts->infiles.list[0], opts->prefix); /* sanity checks */ if( ! opts->prefix ) { fprintf(stderr,"** error: -prefix is required with -cbl function\n"); return 1; } else if( opts->infiles.len > 1 ) { fprintf(stderr,"** sorry, at the moment -cbl allows only 1 input\n"); return 1; } /* remove selector from fname, and copy selector string */ fname = nifti_strdup(opts->infiles.list[0]); cp = strchr(fname,'['); if( !cp ) cp = strchr(fname,'{'); if( !cp ) { if( g_debug > 1 ) fprintf(stderr,"-d using -cbl without brick list in '%s'\n",fname); selstr = nifti_strdup("[0..$]"); } else { selstr = nifti_strdup(cp); *cp = '\0'; /* remove selection string from fname */ } if( g_debug > 1 ) fprintf(stderr,"+d -cbl: using '%s' for selection string\n", selstr); nim = nt_image_read(opts, fname, 0, 0); /* get image */ if( !nim ) return 1; /* since nt can be zero now (sigh), check for it 02 Mar 2006 [rickr] */ blist = nifti_get_int64list(nim->nt > 0 ? num_volumes(nim) : 1, selstr); nifti_image_free(nim); /* throw away, will re-load */ if( !blist ) { fprintf(stderr,"** failed sub-brick selection using '%s'\n",selstr); free(fname); free(selstr); return 1; } nim = nt_read_bricks(opts, fname, blist[0], blist+1, &NBL); free(blist); /* with this */ if( !nim ){ free(fname); free(selstr); return 1; } if( g_debug > 1 ) fprintf(stderr,"+d sub-bricks loaded\n"); /* add command as COMMENT extension */ if( opts->keep_hist && nifti_add_extension(nim, opts->command, (int)strlen(opts->command), NIFTI_ECODE_COMMENT) ) fprintf(stderr,"** failed to add command to image as extension\n"); /* replace filenames using prefix */ if( nifti_set_filenames(nim, opts->prefix, 1, 1) ) { fprintf(stderr,"** failed to set names, prefix = '%s'\n",opts->prefix); err++; } if(g_debug>2) disp_field("new nim:\n",g_nim2_fields,nim,NT_NIM_NUM_FIELDS,1); /* and finally, write out results */ if( err == 0 && nifti_nim_is_valid(nim, g_debug) ) if( nifti_image_write_bricks_status(nim, &NBL) ) { err++; } nifti_image_free(nim); nifti_free_NBL(&NBL); free(fname); free(selstr); return err; } /*---------------------------------------------------------------------- * copy an image to a new file * * This is a straight NIFTI copy, without cbl (so upper dims are intact). * * Note: nt_image_read() allows for modificatons, e.g. to the datatype. *----------------------------------------------------------------------*/ int act_copy( nt_opts * opts ) { nifti_image * nim; const char * fname; /* sanity checks (allow no prefix, just for testing) */ if( opts->infiles.len > 1 ) { fprintf(stderr,"** error: -copy_image allows only 1 input\n"); return 1; } fname = opts->infiles.list[0]; if( g_debug > 2 ) fprintf(stderr,"-d copying image from '%s' to '%s'\n", fname, opts->prefix ? opts->prefix : "NO_PREFIX"); /* read image (nt_image_read() allows modification) */ nim = nt_image_read(opts, fname, 1, 0); if( !nim ) return 1; /* errors are printed from library */ /* write output, if requested */ if( opts->prefix ) { /* set output filename */ if( nifti_set_filenames(nim, opts->prefix, 1, 1) ) { fprintf(stderr,"** NT copy: failed to set names, prefix = '%s'\n", opts->prefix); nifti_image_free(nim); return 1; } /* and write out results */ if( nifti_nim_is_valid(nim, g_debug) ) { if( nifti_image_write_status(nim) ) { fprintf(stderr,"** failed to write image %s\n", nim->fname); nifti_image_free(nim); return 1; } } } nifti_image_free(nim); return 0; } /*---------------------------------------------------------------------- * create a new dataset using read_collapsed_image *----------------------------------------------------------------------*/ int act_cci( nt_opts * opts ) { nifti_image * nim; int c; if( g_debug > 2 ) fprintf(stderr,"-d collapsing file info from '%s' to '%s'\n", opts->infiles.list[0], opts->prefix); /* sanity checks */ if( ! opts->prefix ) { fprintf(stderr,"** error: -prefix is required with -cci function\n"); return 1; } else if( opts->infiles.len > 1 ) { fprintf(stderr,"** sorry, at the moment -cci allows only 1 input\n"); return 1; } nim = nt_image_read(opts, opts->infiles.list[0], 0, 0); if( !nim ) return 1; nim->data = NULL; /* just to be sure */ if( nifti_read_collapsed_image(nim, opts->ci_dims, &nim->data) < 0 ) { nifti_image_free(nim); return 1; } /* add command as COMMENT extension */ if( opts->keep_hist && nifti_add_extension(nim, opts->command, (int)strlen(opts->command), NIFTI_ECODE_COMMENT) ) fprintf(stderr,"** failed to add command to image as extension\n"); /* replace filenames using prefix */ if( nifti_set_filenames(nim, opts->prefix, 1, 1) ) { fprintf(stderr,"** failed to set names, prefix = '%s'\n",opts->prefix); nifti_image_free(nim); return 1; } for( c = 1; c < 8; c++ ) /* nuke any collapsed dimension */ if( opts->ci_dims[c] >= 0 ) nim->dim[c] = 1; nifti_update_dims_from_array(nim); if(g_debug>2) disp_field("new nim:\n",g_nim2_fields,nim,NT_NIM_NUM_FIELDS,1); /* and finally, write out results */ if( nifti_nim_is_valid(nim, g_debug) ) { if( nifti_image_write_status(nim) ) { fprintf(stderr,"** failed to write image %s\n", nim->fname); nifti_image_free(nim); return 1; } } nifti_image_free(nim); return 0; } /*---------------------------------------------------------------------- * free all of the lists in the struct * note: strings were not allocated *----------------------------------------------------------------------*/ static int free_opts_mem( nt_opts * nopt ) { if( !nopt ) return 1; if( nopt->elist.list ) free(nopt->elist.list); if( nopt->etypes.list ) free(nopt->etypes.list); if( nopt->flist.list ) free(nopt->flist.list); if( nopt->vlist.list ) free(nopt->vlist.list); if( nopt->infiles.list ) free(nopt->infiles.list); return 0; } /*---------------------------------------------------------------------- * wrapper for nifti_image_read * * this adds the option to generage an empty image, if the * filename starts with "MAKE_IM" * - in the case of MAKE_IM, use make_ver to specify the NIFTI version * (so possibly mod nifti_type and iname_offset) *----------------------------------------------------------------------*/ nifti_image * nt_image_read( nt_opts * opts, const char * fname, int read_data, int make_ver ) { nifti_image * nim; if( !opts || !fname ) { fprintf(stderr,"** nt_image_read: bad params (%p,%p)\n", (void *)opts, (const void *)fname); return NULL; } /* if the user does not want an empty image, do normal image_read */ if( strncmp(fname,NT_MAKE_IM_NAME,strlen(NT_MAKE_IM_NAME)) ) { if(g_debug > 1) fprintf(stderr,"-d calling nifti_image_read(%s,%d)\n", fname, read_data); /* normal image read */ nim = nifti_image_read(fname, read_data); /* if no data requested, just return */ if( !read_data ) return nim; /* possibly convert to a new datatype [24 Feb 2022 rickr] */ /* alters nim->data,datatype,nbyper */ if( opts->convert2dtype ) { if( convert_datatype(nim, NULL, opts->convert2dtype, opts->cnvt_verify, opts->cnvt_fail_choice) ) { nifti_image_free(nim); return NULL; } } return nim; } /* so generate an empty image */ if(g_debug > 1) { fprintf(stderr,"+d NT_IR: generating EMPTY IMAGE from %s...\n",fname); if(g_debug > 2) { printf(" new_dim[8] = "); disp_raw_data(opts->new_dim, DT_INT64, 8, ' ', 1); printf(" new_datatype = %d\n", opts->new_datatype); fflush(stdout); } } /* create a new nifti_image, with data depending on read_data */ /* (and possibly alter, if make_ver is not the default of 2) */ nim = nifti_make_new_nim(opts->new_dim, opts->new_datatype, read_data); /* if NIFTI-1 is requested, alter nim for it */ if( nim && make_ver == 1 ) { nim->nifti_type = NIFTI_FTYPE_NIFTI1_1; nim->iname_offset = -1; /* let it be reset */ } return nim; } /*---------------------------------------------------------------------- * wrapper for nifti_read_header * * this adds the option to generage an empty image, if the * filename starts with "MAKE_IM" *----------------------------------------------------------------------*/ void * nt_read_header(const char * fname, int * nver, int * swapped, int check, int new_datatype, int64_t new_dim[8]) { nifti_image * nim = NULL; void * nptr = NULL; char func[] = { "nt_read_header" }; int nv; /* swapped is not necessary */ if( !fname ) { fprintf(stderr,"** nt_read_header: missing fname\n"); return NULL; } /* if the user does not want an empty image, do normal image_read */ if( strncmp(fname,NT_MAKE_IM_NAME,strlen(NT_MAKE_IM_NAME)) ) { if(g_debug > 1) fprintf(stderr,"-d calling nifti_read_header(%s, %d...)\n", fname, nver ? *nver : -1); /* if not set or 0, return whatever is found */ if( ! nver || ! *nver ) return nifti_read_header(fname, nver, check); if( *nver < -2 || *nver > 2 ) { fprintf(stderr,"** nt_read_header, illegal nver = %d\n", *nver); return NULL; } /* 1 or 2 means try to return only that */ if( *nver == 1 ) return nifti_read_n1_hdr(fname, swapped, check); if( *nver == 2 ) return nifti_read_n2_hdr(fname, swapped, check); /* handle negatives, start by simply reading the header */ nptr = nifti_read_header(fname, &nv, check); if( !nptr ) return NULL; if( g_debug > 1 ) fprintf(stderr,"-d have NIFTI-%d header, %s\n", nv, fname); /* negative means convert, if necessary */ if( *nver == -1 ) { nifti_1_header * hdr=NULL; if( nv <= 1 ) return nptr; if(g_debug > 1) fprintf(stderr,"+d nifti_tool: convert n2hdr -> n1hdr\n"); /* else assume 2: convert headers via nim? */ hdr = (nifti_1_header *)malloc(sizeof(nifti_1_header)); if( !hdr ) { fprintf(stderr,"** %s: failed to alloc nifti_1_header\n", func); return NULL; } nim = nifti_convert_n2hdr2nim(*(nifti_2_header*)nptr, NULL); if( !nim ) { fprintf(stderr,"** %s: failed n2hdr2nim on %s\n", func, fname); free(nptr); free(hdr); return NULL; } if( nifti_convert_nim2n1hdr(nim, hdr) ) { fprintf(stderr,"** %s: failed convert_nim2n1hdr on %s\n", func, fname); free(nptr); free(hdr); free(nim); return NULL; } return hdr; } else { /* assume -2 */ nifti_2_header * hdr=NULL; if( nv == 2 ) return nptr; /* else assume 2: convert headers via nim? */ if(g_debug > 1) fprintf(stderr,"+d nifti_tool: convert n1hdr -> n2hdr\n"); hdr = (nifti_2_header *)malloc(sizeof(nifti_2_header)); if( !hdr ) { fprintf(stderr,"** %s: failed to alloc nifti_2_header\n", func); return NULL; } nim = nifti_convert_n1hdr2nim(*(nifti_1_header*)nptr, NULL); if( !nim ) { fprintf(stderr,"** %s: failed n1hdr2nim on %s\n", func, fname); return NULL; } if( nifti_convert_nim2n2hdr(nim, hdr) ) { fprintf(stderr,"** %s: failed convert_nim2n2hdr on %s\n", func, fname); return NULL; } return hdr; } } /* else "MAKE_IM", so generate an empty image */ if(g_debug > 1) { fprintf(stderr,"+d NT_RH: generating EMPTY IMAGE from %s...\n",fname); if(g_debug > 2) { printf(" new_dim[8] = "); disp_raw_data(new_dim, DT_INT64, 8, ' ', 1); printf(" new_datatype = %d\n", new_datatype); fflush(stdout); } } /* return creation of new header */ if( (nver && *nver == 1) || (nver && *nver == -1)) return nifti_make_new_n1_header(new_dim, new_datatype); else { if( nver ) *nver = 2; return nifti_make_new_n2_header(new_dim, new_datatype); } } /*---------------------------------------------------------------------- * wrapper for nifti_image_read_bricks * * Similar to nt_read_header(), this adds the option to generage an * empty image if the filename starts with "MAKE_IM". * * the returned object is a (max 4-D) nifti_image *----------------------------------------------------------------------*/ nifti_image * nt_read_bricks(nt_opts * opts, char * fname, int len, int64_t * list, nifti_brick_list * NBL) { nifti_image * nim; int c; /* swapped is not necessary */ if( !opts || !fname || !NBL ) { fprintf(stderr,"** nt_read_bricks: bad params (%p,%p,%p)\n", (void *)opts, (void *)fname, (void *)NBL); return NULL; } /* if the user does not want an empty image, do normal read_bricks */ if( strncmp(fname,NT_MAKE_IM_NAME,strlen(NT_MAKE_IM_NAME)) ) { if(g_debug > 1) fprintf(stderr,"-d calling nifti_image_read_bricks(%s,...)\n",fname); /* do normal read */ nim = nifti_image_read_bricks(fname, len, list, NBL); /* possibly convert to a new datatype [24 Feb 2022 rickr] */ /* would alter NBL,datatype,nbyper (save for later....) */ if( opts->convert2dtype ) { /* convert each brick */ if( convert_datatype(nim, NBL, opts->convert2dtype, opts->cnvt_verify, opts->cnvt_fail_choice) ) { nifti_image_free(nim); nifti_free_NBL(NBL); NBL->nbricks = 0; return NULL; } } return nim; } /* so generate an empty image */ if(g_debug > 1) { fprintf(stderr,"+d NT_RB: generating EMPTY IMAGE from %s...\n",fname); if(g_debug > 2) { printf(" new_dim[8] = "); disp_raw_data(opts->new_dim, DT_INT64, 8, ' ', 1); printf(" new_datatype = %d\n", opts->new_datatype); if( list && len > 0 ) { printf(" brick_list[%d] = ", len); disp_raw_data(list, DT_INT64, len, ' ', 1); } fflush(stdout); /* disp_raw_data uses stdout */ } } /* first, get nim struct without data */ nim = nifti_make_new_nim(opts->new_dim, opts->new_datatype, 0); if( !nim ) { fprintf(stderr,"** nt_read_bricks, nifti_make_new_nim failure\n"); return NULL; } /* now populate NBL (can be based only on len and nim) */ NBL->nbricks = len; NBL->bsize = nim->nbyper * nim->nx * nim->ny * nim->nz; NBL->bricks = (void **)calloc(NBL->nbricks, sizeof(void *)); if( !NBL->bricks ){ fprintf(stderr,"** NRB: failed to alloc %" PRId64 " pointers\n", NBL->nbricks); nifti_image_free(nim); return NULL; } if(g_debug > 1) fprintf(stderr,"+d NRB, allocating " "%" PRId64 " bricks of %" PRId64 " bytes...\n", NBL->nbricks, NBL->bsize); /* now allocate the data pointers */ for( c = 0; c < len; c++ ) { NBL->bricks[c] = calloc(1, NBL->bsize); if( !NBL->bricks[c] ){ fprintf(stderr, "** NRB: failed to alloc brick %d of %" PRId64 " bytes\n", c, NBL->bsize); nifti_free_NBL(NBL); nifti_image_free(nim); return NULL; } } return nim; }