pax_global_header00006660000000000000000000000064137132571360014522gustar00rootroot0000000000000052 comment=96b9954fafcf3bd69a4ee2091b0d707ed2077697 nifti_clib-3.0.1/000077500000000000000000000000001371325713600136255ustar00rootroot00000000000000nifti_clib-3.0.1/.gitignore000066400000000000000000000011651371325713600156200ustar00rootroot00000000000000# Do not add ExternalData module staging files .ExternalData* # back-up files *~ *.bak # vim swp files *.swp ## Ignore files that are used for auto_completion with clang *.clang_complete ## YouCompleteMe vim plugin configuration file .ycm_extra_conf.py # compiled python files *.pyc # Binary directory BUILD* build* # qtcreator CMakeLists.txt.user* # kdevelop *.kdev* .kdev* # back-up files when conflicts occur *.orig # Clion editor internal project information .idea # Mac System File .DS_Store # A common file writen from vim by accident :w # Files when cmake builds in the source tree CMakeCache.txt CMakeFiles/* nifti_clib-3.0.1/.travis.yml000066400000000000000000000143411371325713600157410ustar00rootroot00000000000000#Ubuntu bionic 18.04 #Ubuntu xenial 16.04 default #Ubuntu trusty 14.04 #Ubuntu precise 12.04 dist: bionic language: cpp # sets both CXX and CC envirionmental variables # Use the faster container-based infrastructure. #sudo: false # https://github.com/travis-ci/travis-ci/issues/9033 sudo: true env: global: - PROJECT_NAME=NIFTI_CLIB addons: apt: packages: - cmake - valgrind - help2man homebrew: packages: - cmake - sed - help2man # no poppler, openjpeg, uuid, json # no swig matrix: fast_finish: true include: - compiler: gcc os: linux env: - BLDPREFIX=coverage - PARALLEL_LEVEL=3 - AGENT_BUILDDIRECTORY=${TRAVIS_BUILD_DIR}/NIFTIworkspace - BUILD_SOURCESDIRECTORY=${TRAVIS_BUILD_DIR} - SYSTEM_PULLREQUEST_SOURCEBRANCH=${TRAVIS_PULL_REQUEST_BRANCH} - BUILD_SOURCEBRANCHNAME=${TRAVIS_PULL_REQUEST_BRANCH} - BUILD_BUILDID=${TRAVIS_BUILD_ID} - SYSTEM_PULLREQUEST_PULLREQUESTNUMBER=${TRAVIS_PULL_REQUEST} - CTEST_SCRIPT_DIRECTORY=${TRAVIS_BUILD_DIR}/cmake - CXXFLAGS="-g -O0 -Wall -Wextra -m64 -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Woverloaded-virtual -Wwrite-strings -fprofile-arcs -ftest-coverage" - CFLAGS="-g -O0 -Wall -Wextra -m64 -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Wwrite-strings -fprofile-arcs -ftest-coverage" - LDFLAGS="-fprofile-arcs -ftest-coverage -lgcov" - INTERPROCEDURAL_OPTIMIZATION="ON" - B_NAME=system_gcc - WITH_COVERAGE="ON" - WITH_MEMCHECK="OFF" - NIFTI_SHELL_SCRIPT_TESTS="ON" - SCANBUILD_EXE="" - compiler: gcc os: linux env: - BLDPREFIX=valgrind - PARALLEL_LEVEL=3 - AGENT_BUILDDIRECTORY=${TRAVIS_BUILD_DIR}/NIFTIworkspace - BUILD_SOURCESDIRECTORY=${TRAVIS_BUILD_DIR} - SYSTEM_PULLREQUEST_SOURCEBRANCH=${TRAVIS_PULL_REQUEST_BRANCH} - BUILD_SOURCEBRANCHNAME=${TRAVIS_PULL_REQUEST_BRANCH} - BUILD_BUILDID=${TRAVIS_BUILD_ID} - SYSTEM_PULLREQUEST_PULLREQUESTNUMBER=${TRAVIS_PULL_REQUEST} - CTEST_SCRIPT_DIRECTORY=${TRAVIS_BUILD_DIR}/cmake - CXXFLAGS="-g -O0 -Wall -Wextra -m64 -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Woverloaded-virtual -Wwrite-strings" - CFLAGS="-g -O0 -Wall -Wextra -m64 -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Wwrite-strings" - LDFLAGS="" - INTERPROCEDURAL_OPTIMIZATION="OFF" - B_NAME=system_gcc-valgrind - WITH_COVERAGE="OFF" - WITH_MEMCHECK="ON" - NIFTI_SHELL_SCRIPT_TESTS="OFF" - SCANBUILD_EXE="" - compiler: gcc os: linux env: - BLDPREFIX=use_prefix - PARALLEL_LEVEL=3 - AGENT_BUILDDIRECTORY=${TRAVIS_BUILD_DIR}/NIFTIworkspace - BUILD_SOURCESDIRECTORY=${TRAVIS_BUILD_DIR} - SYSTEM_PULLREQUEST_SOURCEBRANCH=${TRAVIS_PULL_REQUEST_BRANCH} - BUILD_SOURCEBRANCHNAME=${TRAVIS_PULL_REQUEST_BRANCH} - BUILD_BUILDID=${TRAVIS_BUILD_ID} - SYSTEM_PULLREQUEST_PULLREQUESTNUMBER=${TRAVIS_PULL_REQUEST} - CTEST_SCRIPT_DIRECTORY=${TRAVIS_BUILD_DIR}/cmake - INTERPROCEDURAL_OPTIMIZATION="ON" - B_NAME=system_gcc - WITH_MEMCHECK="OFF" - NIFTI_PACKAGE_PREFIX=test_ - SCANBUILD_EXE="" - compiler: clang os: linux env: - BLDPREFIX=sanitize - PARALLEL_LEVEL=3 - AGENT_BUILDDIRECTORY=${TRAVIS_BUILD_DIR}/NIFTIworkspace - BUILD_SOURCESDIRECTORY=${TRAVIS_BUILD_DIR} - SYSTEM_PULLREQUEST_SOURCEBRANCH=${TRAVIS_PULL_REQUEST_BRANCH} - BUILD_SOURCEBRANCHNAME=${TRAVIS_PULL_REQUEST_BRANCH} - BUILD_BUILDID=${TRAVIS_BUILD_ID} - SYSTEM_PULLREQUEST_PULLREQUESTNUMBER=${TRAVIS_PULL_REQUEST} - CTEST_SCRIPT_DIRECTORY=${TRAVIS_BUILD_DIR}/cmake - ASAN_OPTIONS=verbosity=1 - CFLAGS="-Wall -Wextra -m64 -W -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Wwrite-strings -fsanitize=address,undefined" - CXXFLAGS="-g -Wall -Wextra -m64 -fsanitize=address,undefined" - INTERPROCEDURAL_OPTIMIZATION="OFF" - B_NAME=fsanitize_clang - WITH_COVERAGE="OFF" - WITH_MEMCHECK="OFF" - NIFTI_SHELL_SCRIPT_TESTS="ON" - SCANBUILD_EXE="scan-build -v --status-bugs" - CCC_CC=clang - CCC_CXX=clang++ - compiler: clang os: osx osx_image: xcode11 env: - BLDPREFIX=rel - PARALLEL_LEVEL=3 - AGENT_BUILDDIRECTORY=${TRAVIS_BUILD_DIR}/NIFTIworkspace - BUILD_SOURCESDIRECTORY=${TRAVIS_BUILD_DIR} - BUILD_BUILDID=${TRAVIS_BUILD_ID} - SYSTEM_PULLREQUEST_SOURCEBRANCH=${TRAVIS_PULL_REQUEST_BRANCH} - BUILD_SOURCEBRANCHNAME=${TRAVIS_PULL_REQUEST_BRANCH} - SYSTEM_PULLREQUEST_PULLREQUESTNUMBER=${TRAVIS_PULL_REQUEST} - CTEST_SCRIPT_DIRECTORY=${TRAVIS_BUILD_DIR}/cmake # -m64 -fsanitize=address,undefined - CFLAGS="-O3 -Wall -Wextra -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Wwrite-strings" - CXXFLAGS="-O3 -Wall -Wextra -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Wwrite-strings" - INTERPROCEDURAL_OPTIMIZATION="ON" - B_NAME=osx_clang - WITH_COVERAGE="OFF" - WITH_MEMCHECK="OFF" - NIFTI_SHELL_SCRIPT_TESTS="ON" - SCANBUILD_EXE="" - CCC_CC=clang - CCC_CXX=clang++ before_install: #- env - cd ${TRAVIS_BUILD_DIR} install: true before_script: true script: - which $CXX && $CXX --version || true - which $CC && $CC --version || true - which scan-build || true - which gcov && gcov --version || true - which valgrind && valgrind --version || true - which cmake && cmake --version || true - ${SCANBUILD_EXE} ctest -S ${CTEST_SCRIPT_DIRECTORY}/travis_dashboard.cmake -V -j 4 after_success: true after_failure: true after_script: true nifti_clib-3.0.1/CMakeLists.txt000066400000000000000000000241171371325713600163720ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) set(NIFTI_MAX_VALIDATED_CMAKE_VERSION "3.13.1") if("${CMAKE_VERSION}" VERSION_LESS_EQUAL "${NIFTI_MAX_VALIDATED_CMAKE_VERSION}") # As of 2018-12-04 NIFTI has been validated to build with cmake version 3.13.1 new policies. # Set and use the newest cmake policies that are validated to work set(NIFTI_CMAKE_POLICY_VERSION "${CMAKE_VERSION}") else() set(NIFTI_CMAKE_POLICY_VERSION "${NIFTI_MAX_VALIDATED_CMAKE_VERSION}") endif() cmake_policy(VERSION ${NIFTI_CMAKE_POLICY_VERSION}) set(NIFTI_HOMEPAGE_URL "https://nifti-imaging.github.io") execute_process(COMMAND git "describe" "--tags" OUTPUT_VARIABLE GIT_REPO_VERSION_UNCLEANED WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) #Extract the GIT_REPO_VERSION as composed of non-negative integer components, # i.e. [.[.[.]]] string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+((beta.*)?(alpha.*)?\\.[0-9]+(\\.g[0-9a-f]+)?)?" GIT_REPO_VERSION "${GIT_REPO_VERSION_UNCLEANED}") if( NOT GIT_REPO_VERSION ) message(NOTE "Invalid git tag does not match required regular expression, " "can not extract version information from '${GIT_REPO_VERSION_UNCLEANED}'") # NOTE: cmake -DGIT_REPO_VERSION:STRING=[.[.[.]]] can be used # to set the repo string for non-git repos. set(GIT_REPO_VERSION "0.0.0.0") #Manually set the version string for testing purposes endif() project(NIFTI VERSION ${GIT_REPO_VERSION} DESCRIPTION "Niftilib is a set of i/o libraries for reading and writing files in the nifti-1 data format. nifti-1 is a binary file format for storing medical image data, e.g. magnetic resonance image (MRI) and functional MRI (fMRI) brain images." LANGUAGES C) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) include(nifti_macros) set_property(GLOBAL PROPERTY nifti_installed_targets) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) include(CMakeDependentOption) if("${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.13") set(CMAKE_VER_AT_LEAST_3_13 1 CACHE BOOL "Is set for cmake >=3.13") endif() # add option to build shared libraries. The default is OFF to maintain the # current build behavior option( BUILD_SHARED_LIBS "Toggle building shared libraries." OFF) # Include executables as part of the build option(NIFTI_BUILD_APPLICATIONS "Build various utility tools" ON) mark_as_advanced(NIFTI_BUILD_APPLICATIONS) #When including nifti as a subpackage, a prefix is often needed to avoid conflicts with sytem installed libraries. set_if_not_defined(NIFTI_PACKAGE_PREFIX "") set(PACKAGE_NAME ${NIFTI_PACKAGE_PREFIX}NIFTI) set_if_not_defined(NIFTI_INSTALL_EXPORT_NAME ${PACKAGE_NAME}Targets) # Set default shared library version # This library version will be applied to all libraries in the package # unless it is not explicitely for a certain lib. set(NIFTI_SHAREDLIB_VERSION ${GIT_REPO_VERSION} ) if(BUILD_SHARED_LIBS AND NOT NIFTI_LIBRARY_PROPERTIES) set(NIFTI_LIBRARY_PROPERTIES ${DEFAULT_SHARED_LIBS} BUILD_SHARED_LIBS TRUE POSITION_INDEPENDENT_CODE TRUE ) endif() set_if_not_defined(NIFTI_INSTALL_RUNTIME_DIR bin) set_if_not_defined(NIFTI_INSTALL_LIBRARY_DIR lib) set_if_not_defined(NIFTI_INSTALL_ARCHIVE_DIR ${NIFTI_INSTALL_LIBRARY_DIR}) set_if_not_defined(NIFTI_INSTALL_INCLUDE_DIR include/nifti) set_if_not_defined(NIFTI_INSTALL_MAN_DIR share/man/man1) set_if_not_defined(NIFTI_INSTALL_DOC_DIR share/doc/${PROJECT_NAME}) set_if_not_defined(NIFTI_ZLIB_LIBRARIES "") set_if_not_defined(ZNZ_COMPILE_DEF "") if(NOT NIFTI_ZLIB_LIBRARIES) # If using a custom zlib library, skip the find package ### USE AS STAND ALONE PACKAGE find_package(ZLIB REQUIRED) set(NIFTI_ZLIB_LIBRARIES ${ZLIB_LIBRARIES}) endif() #message(STATUS "---------------------ZLIB -${NIFTI_ZLIB_LIBRARIES}--") add_definitions(-DHAVE_ZLIB) set_if_not_defined(NIFTI_INSTALL_NO_DOCS TRUE) # Include test to verify linking in installed executables # The test should only be added when applications are built, and no prefix string is set. cmake_dependent_option( TEST_INSTALL "Add a test to check that linking to SO libraries occurs correctly during installation." ON "${NIFTI_PACKAGE_PREFIX};${NIFTI_BUILD_APPLICATIONS};${BUILD_SHARED_LIBS};${NIFTI_BUILD_TESTING}" OFF ) # Add a default attempt at setting the run path correctly for binaries if(NOT CMAKE_SKIP_INSTALL_RPATH) file( RELATIVE_PATH relDir ${CMAKE_INSTALL_PREFIX}/${NIFTI_INSTALL_RUNTIME_DIR} ${CMAKE_INSTALL_PREFIX}/${NIFTI_INSTALL_LIBRARY_DIR} ) if(APPLE) set_if_not_defined(CMAKE_INSTALL_RPATH "@loader_path/${relDir}") else() set_if_not_defined(CMAKE_INSTALL_RPATH "\$ORIGIN/${relDir}") endif() endif() if(NOT NIFTI_INSTALL_NO_DOCS) find_program(HELP2MAN help2man REQUIRED) set(MAN_DIR ${PROJECT_BINARY_DIR}/manpages) file(MAKE_DIRECTORY ${MAN_DIR}) endif() ####################################################################### set_if_not_defined(BUILD_TESTING ON) set_if_not_defined(NIFTI_BUILD_TESTING ${BUILD_TESTING}) if (NIFTI_BUILD_TESTING ) include(CTest) enable_testing() #Needs an if clause and more work before testing can take place. option( DOWNLOAD_TEST_DATA "Allow download of data used for some tests. Can be used in conjunction with ctest label filter '-LE NEEDS_DATA'" ON ) set_if_not_defined(NIFTI_SHELL_SCRIPT_TESTS "ON") if(DOWNLOAD_TEST_DATA) if ( CMAKE_VERSION VERSION_LESS 3.11.0 ) # CMAKE VERSION 3.11.0 needed for fetching data with cmake message(FATAL_ERROR "ERROR: The testing framework for nifti_clib requires CMake version 3.11.0 or greater") endif() include(FetchContent) # fetch data a configure time to simplify tests # If new or changed data is needed, add that data to the https://github.com/NIFTI-Imaging/nifti-test-data repo # make a new release, and then update the URL and hash (shasum -a 256 ). FetchContent_Declare( fetch_testing_data URL https://github.com/NIFTI-Imaging/nifti-test-data/archive/v3.0.2.tar.gz URL_HASH SHA256=5dafec078151018da7aaf3c941bd31f246f590bc34fa3fef29ce77a773db16a6 ) FetchContent_GetProperties(fetch_testing_data) if(NOT fetch_testing_data_POPULATED) set(FETCHCONTENT_QUIET OFF) FetchContent_Populate( fetch_testing_data ) endif() endif() endif() ####################################################################### # Find unix math libraries if(NOT WIN32) find_library(NIFTI_SYSTEM_MATH_LIB m) else() set(NIFTI_SYSTEM_MATH_LIB "") endif() ####################################################################### add_subdirectory(znzlib) add_subdirectory(niftilib) option(USE_NIFTICDF_CODE "Build nifticdf library and tools" ON) mark_as_advanced(USE_NIFTICDF_CODE) if(USE_NIFTICDF_CODE) add_subdirectory(nifticdf) endif() option(USE_NIFTI2_CODE "Build the nifti2 library and tools" ON) mark_as_advanced(USE_NIFTI2_CODE) cmake_dependent_option(USE_CIFTI_CODE "Build the cifti library and tools" OFF "USE_NIFTI2_CODE" OFF) mark_as_advanced(USE_CIFTI_CODE) if( USE_NIFTI2_CODE ) add_subdirectory(nifti2) if( USE_CIFTI_CODE ) add_subdirectory(cifti) endif() endif() option(USE_FSL_CODE "If OFF, The copyright of this code is questionable for inclusion with nifti." OFF) mark_as_advanced(USE_FSL_CODE) # the order of add_subdirectory is important! fsliolob has to preceed examples # as otherwise FSLIOLIB_SOURCE_DIR is undefined and hence the examples # will fail to compile if(USE_FSL_CODE) add_subdirectory(fsliolib) endif() # Allow an uninstall (with some risk of messiness) if(NOT TARGET uninstall) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY ) add_custom_target( uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake ) endif() # Report installed targets get_property(nifti_installed_targets GLOBAL PROPERTY nifti_installed_targets) message("nifti_installed_targets: ${nifti_installed_targets}") if(CMAKE_VER_AT_LEAST_3_13) # Target installation for CMake versions >=3.13 foreach(targ ${nifti_installed_targets}) install_nifti_target(${targ}) endforeach() endif() if(NOT NIFTI_INSTALL_NO_DOCS) install( DIRECTORY ${MAN_DIR}/ DESTINATION ${NIFTI_INSTALL_MAN_DIR} FILES_MATCHING REGEX ".*.1.gz" PERMISSIONS OWNER_READ WORLD_READ ) install( FILES ${PROJECT_SOURCE_DIR}/README.md DESTINATION ${NIFTI_INSTALL_DOC_DIR} ) install( DIRECTORY ${PROJECT_SOURCE_DIR}/real_easy/ DESTINATION ${NIFTI_INSTALL_DOC_DIR}/examples ) endif() if(NIFTI_INSTALL_EXPORT_NAME STREQUAL "NIFTITargets") ####################################################################### # CMake itself and can use some CMake facilities for creating the package files. # This allows for find_package(NIFTI 2.1.0 NO_MODULE) to work for pulling in # NIFTI libraries into an external project include(CMakePackageConfigHelpers) set(CONFIG_SETUP_DIR ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}) set(ConfigPackageLocation share/cmake/${PACKAGE_NAME}) write_basic_package_version_file( ${CONFIG_SETUP_DIR}/${PACKAGE_NAME}ConfigVersion.cmake VERSION ${GIT_REPO_VERSION} COMPATIBILITY AnyNewerVersion ) configure_file(cmake/NIFTIConfig.cmake ${CONFIG_SETUP_DIR}/${PACKAGE_NAME}Config.cmake COPYONLY ) install(EXPORT ${NIFTI_INSTALL_EXPORT_NAME} FILE NIFTITargets.cmake NAMESPACE ${PACKAGE_NAME}:: DESTINATION ${ConfigPackageLocation} COMPONENT Development ) install(FILES ${CONFIG_SETUP_DIR}/${PACKAGE_NAME}Config.cmake ${CONFIG_SETUP_DIR}/${PACKAGE_NAME}ConfigVersion.cmake COMPONENT Development DESTINATION ${ConfigPackageLocation} ) endif() ####################################################################### ## Add the cpack configuration settings last option(NIFTI_USE_PACKAGING "Configure the packaging options for NIFTI" OFF) mark_as_advanced(NIFTI_USE_PACKAGING) if(NIFTI_USE_PACKAGING) include(cmake/NIFTICPackConfig.cmake) endif() nifti_clib-3.0.1/CTestConfig.cmake000066400000000000000000000010261371325713600167760ustar00rootroot00000000000000## This file should be placed in the root directory of your project. ## Then modify the CMakeLists.txt file in the root directory of your ## project to incorporate the testing dashboard. ## ## # The following are required to submit to the CDash dashboard: ## enable_testing() ## include(CTest) set(CTEST_PROJECT_NAME "NIFTI") set(CTEST_NIGHTLY_START_TIME "00:00:00 EST") set(CTEST_DROP_METHOD "https") set(CTEST_DROP_SITE "my.cdash.org") set(CTEST_DROP_LOCATION "/submit.php?project=nifti_clib") set(CTEST_DROP_SITE_CDASH TRUE) nifti_clib-3.0.1/Dockerfile000066400000000000000000000030541371325713600156210ustar00rootroot00000000000000FROM ubuntu:bionic # FROM ubuntu:eoan RUN apt-get update && apt-get install -y -q eatmydata \ && eatmydata apt-get update && apt-get install -y -q \ cmake \ gcc \ git \ help2man \ libexpat1-dev \ make \ wget \ zlib1g-dev \ && rm -rf /var/lib/apt/lists/* # Install newer cmake version with globally scoped targets for convenience # (apt installed version is used by default though) ENV CMAKE_VER=3.13.3 RUN wget -P /opt/cmake https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/cmake-${CMAKE_VER}-Linux-x86_64.tar.gz \ ; cd /opt/cmake \ ; tar xzvf cmake-${CMAKE_VER}-Linux-x86_64.tar.gz \ ;rm -fr cmake-${CMAKE_VER}-Linux-x86_64.tar.gz RUN mkdir -p /opt/src/nifti_clib RUN mkdir /nifti_build COPY . /opt/src/nifti_clib/ WORKDIR /nifti_build # Test build and install with system-installed cmake RUN cmake \ -DBUILD_SHARED_LIBS=ON \ -DNIFTI_USE_PACKAGING=ON \ -DUSE_CIFTI_CODE=ON \ -DUSE_FSL_CODE=ON \ -DNIFTI_BUILD_APPLICATIONS=ON \ -DTEST_INSTALL=ON \ -DDOWNLOAD_TEST_DATA=OFF \ /opt/src/nifti_clib \ && make install \ && ctest --output-on-failure -LE NEEDS_DATA # For checking max-verified cmake version successfully builds: # ENV PATH="/opt/cmake/cmake-${CMAKE_VER}-Linux-x86_64/bin:$PATH" # RUN cmake \ # -DBUILD_SHARED_LIBS=OFF \ # -DUSE_CIFTI_CODE=ON \ # -DUSE_FSL_CODE=ON \ # -DNIFTI_BUILD_APPLICATIONS=ON \ # -DTEST_INSTALL=ON \ # /opt/src/nifti_clib \ # && make install \ # && ctest --output-on-failurenifti_clib-3.0.1/LICENSE000066400000000000000000000006041371325713600146320ustar00rootroot00000000000000Niftilib has been developed by members of the NIFTI DFWG and volunteers in the neuroimaging community and serves as a reference implementation of the nifti-1 file format. http://nifti.nimh.nih.gov/ Nifticlib code is released into the public domain, developers are encouraged to incorporate niftilib code into their applications, and, to contribute changes and enhancements to niftilib. nifti_clib-3.0.1/Makefile000066400000000000000000000136741371325713600153000ustar00rootroot00000000000000 SHELL = csh ## Projects NIFTI = niftilib NIFTICDF = nifticdf ZNZ = znzlib FSLIO = fsliolib TESTING = Testing UTILS_PROGS = nifti_stats nifti_tool nifti1_test THIS_DIR = `basename ${PWD}` ## Note the TARFILE_NAME embeds the release version number TARFILE_NAME = nifticlib-2.0.0 ## Compiler defines cc = gcc CC = gcc AR = ar RANLIB = ranlib DEPENDFLAGS = -MM GNU_ANSI_FLAGS = -Wall -ansi -pedantic ANSI_FLAGS = ${GNU_ANSI_FLAGS} CFLAGS = $(ANSI_FLAGS) ## Command defines ## gmake does not work on MacOSX or some versions of linux MAKE = gmake RM = rm MV = mv CP = cp TAR = /usr/local/pkg/gnu/bin/tar ## Installation INSTALL_BIN_DIR = bin INSTALL_LIB_DIR = lib INSTALL_INC_DIR = include ## Zlib defines ZLIB_INC = -I/usr/include ZLIB_PATH = -L/usr/lib ZLIB_LIBS = $(ZLIB_PATH) -lm -lz ############################################################## # platform specific redefines (to use, set ARCH appropriately) ##ARCH = X86_64 ifeq ($(ARCH),SGI) ## SGI 32bit ZLIB_INC = -I/usr/freeware/include ZLIB_PATH = -L/usr/freeware/lib32 RANLIB = echo "ranlib not needed" else ifeq ($(ARCH),I386) ## 32-bit Linux ZLIB_INC = -I/usr/include ZLIB_PATH = -L/usr/lib TAR = /bin/tar else ifeq ($(ARCH),X86_64) ## 64-bit Linux ZLIB_INC = ZLIB_PATH = ZLIB_LIBS = $(ZLIB_PATH) -lm -lz TAR = /bin/tar endif endif endif ################################################################# ## ZNZ defines ZNZ_INC = -I../$(ZNZ) ZNZ_PATH = -L../$(ZNZ) ZNZ_LIBS = $(ZNZ_PATH) -lznz USEZLIB = -DHAVE_ZLIB ## NIFTI defines NIFTI_INC = -I../$(NIFTI) NIFTI_PATH = -L../$(NIFTI) NIFTI_LIBS = $(NIFTI_PATH) -lniftiio ## NIFTICDF defines NIFTICDF_INC = -I../$(NIFTICDF) NIFTICDF_PATH = -L../$(NIFTICDF) NIFTICDF_LIBS = $(NIFTICDF_PATH) -lnifticdf ## FSLIO defines FSLIO_INC = -I../$(FSLIO) FSLIO_PATH = -L../$(FSLIO) FSLIO_LIBS = $(FSLIO_PATH) -lfslio ## Rules .SUFFIXES: .c .o .c.o: $(CC) -c $(CFLAGS) $(INCFLAGS) $< ## Targets all: znz nifti nifticdf fslio install mention_cmake install: znz_install nifti_install nifticdf_install fslio_install clean: znz_clean nifti_clean nifticdf_clean fslio_clean clean_all: clean install_clean doc_clean znz: echo "arch is $(ARCH)" (cd $(ZNZ); $(MAKE) depend; $(MAKE) lib;) @echo " ----------- $(ZNZ) build completed." @echo "" nifti: znz (cd $(NIFTI); $(MAKE) depend; $(MAKE) lib;) @echo " ----------- $(NIFTI) build completed." @echo "" nifticdf:nifti (cd $(NIFTICDF); $(MAKE) depend; $(MAKE) lib;) @echo " ----------- $(NIFTICDF) build completed." @echo "" fslio: nifti (cd $(FSLIO); $(MAKE) depend; $(MAKE) lib;) @echo " ---------- $(FSLIO) build completed." @echo "" example:nifti (cd $(EXAMPLES); $(MAKE) all;) @echo Example programs built. @echo "" doc: (cd docs; doxygen Doxy_nifti.txt;) @echo "doxygen doc rebuilt, run netscape docs/html/index.html to view." @echo "" $(INSTALL_BIN_DIR): mkdir -p $@ $(INSTALL_INC_DIR): mkdir -p $@ $(INSTALL_LIB_DIR): mkdir -p $@ znz_install: $(INSTALL_INC_DIR) $(INSTALL_LIB_DIR) ($(CP) $(ZNZ)/*.a $(INSTALL_LIB_DIR); $(CP) $(ZNZ)/*.h $(INSTALL_INC_DIR);) $(RANLIB) $(INSTALL_LIB_DIR)/*.a @echo " $(ZNZ) installed." @echo "" nifti_install: $(INSTALL_INC_DIR) $(INSTALL_LIB_DIR) ($(CP) $(NIFTI)/*.a $(INSTALL_LIB_DIR); $(CP) $(NIFTI)/*.h $(INSTALL_INC_DIR);) $(RANLIB) $(INSTALL_LIB_DIR)/*.a @echo " $(NIFTI) installed." @echo "" nifticdf_install: $(INSTALL_INC_DIR) $(INSTALL_LIB_DIR) ($(CP) $(NIFTICDF)/*.a $(INSTALL_LIB_DIR); $(CP) $(NIFTICDF)/*.h $(INSTALL_INC_DIR);) $(RANLIB) $(INSTALL_LIB_DIR)/*.a @echo " $(NIFTI) installed." @echo "" fslio_install: $(INSTALL_INC_DIR) $(INSTALL_LIB_DIR) ($(CP) $(FSLIO)/*.a $(INSTALL_LIB_DIR); $(CP) $(FSLIO)/*.h $(INSTALL_INC_DIR);) $(RANLIB) $(INSTALL_LIB_DIR)/*.a @echo " $(FSLIO) installed." @echo "" install_clean: ($(RM) -f $(INSTALL_INC_DIR)/* $(INSTALL_LIB_DIR)/* $(INSTALL_BIN_DIR)/*;) znz_clean: (cd $(ZNZ); $(RM) -f *.o *.a core; $(RM) -f depend.mk;) nifti_clean: (cd $(NIFTI); $(RM) -f *.o *.a core; $(RM) -f depend.mk;) nifticdf_clean: (cd $(NIFTICDF); $(RM) -f *.o *.a core; $(RM) -f depend.mk;) fslio_clean: (cd $(FSLIO); $(RM) -f *.o *.a core; $(RM) -f depend.mk;) doc_clean: ($(RM) -fr docs/html;) tar: (cd .. ; ln -s $(THIS_DIR) ${TARFILE_NAME} ; \ $(TAR) --exclude=CVS -cf ${TARFILE_NAME}.tar ${TARFILE_NAME}/*; \ rm -f ${TARFILE_NAME}); @echo '' @echo 'tar file ../${TARFILE_NAME}.tar has been created.' @echo '' mention_cmake: @echo "" @echo "---------------------------------------------------------" @echo "This packages has changed to rely more primarly on cmake," @echo "and the Makefile system needs a little love." @echo "" @echo "Consider the steps for cmake, if they would be helpful:" @echo "" @echo " mkdir cmake_build" @echo " cd cmake_build" @echo " cmake -DBUILD_SHARED_LIBS=ON .." @echo " make" @echo "" help: @echo "" @echo "all: build and install znz, nifti1 and fslio libraries" @echo "install: install znz, nifti1, and fslio libraries" @echo "doc: build the doxygen docs for this project." @echo " (Need doxygen installed, see" @echo " http://www.stack.nl/~dimitri/doxygen/index.html" @echo "tar: make a tar file of all nifti_io code, put in .." @echo "" @echo "clean: remove .o .a etc. files from source directories" @echo "clean_all: make clean and delete all installed files in bin," @echo " include and lib, and remove any autogenerated" @echo " docs (docs/html)" @echo "" @echo "znz: build the znz library" @echo "znz_install: install the znz library" @echo "nifti: build the nifti1 library" @echo "nifti_install: install the nifti1 library" @echo "nifticdf: build the nifti1 library" @echo "nifticdf_install: install the nifti1 library" @echo "fslio: build the fslio library" @echo "fslio_install: install the fslio library" @echo "example: make the example program(s)" @echo "" nifti_clib-3.0.1/Makefile.cross_mingw32000066400000000000000000000057041371325713600177710ustar00rootroot00000000000000#!/usr/bin/make -f # -*- Makefile -*- # # This makefile was initially created by Michael Hanke # to cross compile the nifticlibs for win32 on a # Debian system -- although it should work on most Linux systems with possibly # minor modifications. The whole process should become a lot easier once # CMake 2.6 with cross-compiler toolchain support is released. # # Like the other parts of this package, this code is placed into the public # domain. # # The 'devpak' target generates a DevPak suiteable for Dev-Cpp, see: # http://www.bloodshed.net/devcpp.html # # Requirements: # - cross-compiler environment (on Debian simply: apt-get install mingw32) # - recent CMake (tested with 2.4) # - cross-compiled zlib installed below $mingw_root_path. The easiest way to # achieve this is using the zlib package provided by the gnuwin32 project: # http://gnuwin32.sourceforge.net/ # # Usage: # Enter the root of the nifticlibs package and execute # # make -f Makefile.cross_mingw32 # # now the generated DevPak should be located in the toplevel directory. This # can be installed using the Package manager of Dev-Cpp under Windows. # # default settings build_dir = mingw32_cross devpak_dir = mingw32_devpak # where all the cross-compiled libs and binaries are installed mingw_root_path = /usr/local/mingw32 # where the cross-compiler itself is installed mingw_bin_path = /usr/bin # the common filename prefix of all cross-compiler binaries mingw_bin_prefix = i586-mingw32msvc # don't touch this one, unless you know what you are doing mingw_bin = $(mingw_bin_path)/$(mingw_bin_prefix) # extract the most recent version from the README file nifti_version = $$(grep Version README | head -n1 | awk '{ print $$2 }') # compile CMake flags. cmake_flags = -DCMAKE_SYSTEM_NAME=Windows \ -DCMAKE_AR=$(mingw_bin)-ar \ -DCMAKE_RANLIB=$(mingw_bin)-ranlib \ -DCMAKE_C_COMPILER=$(mingw_bin)-gcc \ -DCMAKE_CXX_COMPILER=$(mingw_bin)-g++ \ -DCMAKE_C_FLAGS="-I$(mingw_root_path)/include -L$(mingw_root_path)/lib -DWIN32" all: devpak clean: -rm -rf $(build_dir) -rm build-devpak configure-devpak distclean: clean -rm -rf $(devpak_dir) configure-devpak: if [ ! -d $(build_dir) ]; then mkdir $(build_dir); fi cd $(build_dir) && cmake .. $(cmake_flags) -DCMAKE_INSTALL_PREFIX=/$(devpak_dir) touch $@ build-devpak: configure-devpak cd $(build_dir) && make VERBOSE=1 touch $@ install-devpak: build-devpak if [ ! -d $(devpak_dir) ]; then mkdir $(devpak_dir); fi cd $(build_dir) && make install DESTDIR=../ devpak: install-devpak # nifti_tool header is unecessary rm $(devpak_dir)/include/nifti/nifti_tool.h # generate devpak info file sed -e s/__full_version__/$(nifti_version)/g \ -e s/__major_version__/$(nifti_version)/g \ < packaging/DevPackage.template > $(devpak_dir)/nifticlib.DevPackage # include license and readme cp LICENSE README $(devpak_dir) # compress cd $(devpak_dir) && tar cvjf ../nifticlib-$(nifti_version).DevPak * nifti_clib-3.0.1/README.md000066400000000000000000000073271371325713600151150ustar00rootroot00000000000000# NIFTI C Libraries `Nifti_clib` is a set of i/o libraries for reading and writing files in the nifti-1, nifti-2, and (to some degree) cifti file formats. These libraries provide api's for binary file format for storing medical image data, e.g. magnetic resonance image (MRI) and functional MRI (fMRI) brain images. This repository contains the C implementations. ( See other repositories at [github](https://github.com/NIFTI-Imaging) for Java, MATLAB, and Python libraries). `Nifti_clib` has been developed by members of the NIFTI DFWG and volunteers in the neuroimaging community and serves as a reference implementation of the nifti-1 and nifti-2 file formats. In addition to being a reference implementation, we hope it is also a useful i/o library. `Nifti_clib` code is released into the public domain, developers are encouraged to incorporate niftilib code into their applications, and, to contribute changes and enhancements to niftilib. Please contact us if you would like to contribute additonal functionality to the i/o library. The main webpage for this project is [hosted on github](https://nifti-imaging.github.io/). This web site provde historical information. Additional informaiton from the [NIFTI DFWG](http://nifti.nimh.nih.gov) The testing dashboard for monitoring the health of the libraries is at [my.cdash.org](https://my.cdash.org/index.php?project=nifti_clib). ## Nifti-2 C libraries coming soon. ## Cifti C libraries Introductory, coming soon. ## Nifti-1 C libraries * Version 2.0.0 beta release Jul 2010 * Version 1.1.0 beta release Aug 2008 * Version 1.0.0 beta release Dec 2007 * Version 0.6 beta release Aug 2007 * Version 0.5 beta release May 2007 * Version 0.4 beta release Sept. 2006 * Version 0.3 beta release April 2006 * Version 0.2 beta release August 12, 2005 * Version 0.1 beta release March 11, 2005 niftilib code is released into the public domain. ## Library directories directory | description ----------|------------- znzlib | low level library for handling read/write of compressed files. niftilib | core i/o routines for reading and writing nifti-1 format files. Primarily routines to read/write and manipulate the header field information, including orientation matrices. Volume-wise, timecourse-wise, access to image data. nifti2 | core i/o routines for reading and writing nifti-2 format files. nifticdf | functions to compute cumulative distributions and their inverses fsliolib | i/o routines for reading and writing nifti-1 format files, higher level than niftilib, includes routines for reading the data blob by volume, timecourse, etc., and, addresses image orientation issues. `work in progress, subject to significant revision.....` cifti | very basic routines for reading cifti format files ## Destination directories directory | description ----------|------------ bin | destination directory for installed programs include | destination directory for library header files lib | destination directory for compiled libraries docs | destination directory Doxygen html (created via "make doc") ## Example directories directory | description ------------|------------- `real_easy` | simple code snippets, some using ref. libs., some not ## Other directories directory | description ------------|------------ Testing | directory containing code to test the libraries packaging | spec file for building RPMs, and template package description for Dev-Cpp (http://www.bloodshed.net/devcpp.html) ## Instructions to build command | description ------------|------------- "make all" | results will be left in the directories: bin/ include/ lib/ "make help" | will show more build options ![NIFTI ICON](https://avatars0.githubusercontent.com/u/45666806?s=200&v=4) nifti_clib-3.0.1/Updates.txt000066400000000000000000000146121371325713600157770ustar00rootroot00000000000000 Updates to the niftilb C package ----------------------------------------------------------------- Updates in version 0.3 April 12, 2006 - added const in appropriate function parameter locations - shortened all string constants below 509 character limit - added nifti_is_complete_filename() - made minor memory fixes - fixed error in QSTR() definition - use nifti_set_filenames() in nifti_convert_nhdr2nim() - added new tests in Testing/niftilib/nifti_test.c - added skip blank extension option to keep 348 byte header - when reading, allow 0 or 1 in dim[] fields above dim[0] - added more tests to nifti_hdr_looks_good() - nifti_tool: added check_hdr and check_nim action options ----------------------------------------------------------------- Updates in version 0.4 September 6, 2006 - for testing, added Testing/Data, Testing/niftilib/nifti_test2.c and Testing/Data/ATestReferenceImageForReadingAndWriting.nii.gz - modified Testing/niftilib/nifti_test.c for better code coverage - added switch for not building unused funcs in nifti_stats.c - modified nifti1_io.c: free(hstr) and clear ext vars - fixed nt=0 case from 1.17 change in nifti_alloc_NBL_mem() - fixed nifti_findhdrname() logic for efirst - all fsliolib files: updated header to make public domain clear - added nifti_set_skip_blank_ext() ----------------------------------------------------------------- Updates in version 0.5 May 17, 2007 - fixed duplication of incuding utils directory for CMake - syncronized with developments in ITK to prepare for building and tar/rpm/dmg packaging with new versions of cmake - added more typecasting to remove compiler warnings - fslio.c: check for NULL return from nifti_image_read() - creation of nifticdf directory, to separate cdf library functions from utils/nifti_stats.c - make system update for nifticdf - modified CMakeBuild system to be compliant with new CPACK mechanism of generating binary distributions - modified CMake system to build shared libraries - modified Makefiles to use ARCH in more cases ----------------------------------------------------------------- Updated in version 0.6 August 27, 2007 - RR allowed for datasets with a single volume > 2^31 bytes - RR allowed for datasets with total size > 2^32 bytes - RR added regression testing under Testing/nifti_regress_test - KF added upper level packaging directory and put Andy Loenings's rpm spec file in it - HJ Changed default installation path of header files into include/nifti from CMakeLists.txt - HJ/KW Added exposing Analyze75 orientation codes - HJ/KW Added function to allow any sized subregion of the image to be read from disk - RR/KF znzlib/config.h incorporated into znzlib.h and removed ----------------------------------------------------------------- Updated in version 1.0 December 6, 2007 - MH added DevPak packaging template for Dev-Cpp IDE - MH added Makefile for cross-compiling for win32 on linux using mingw32 - Yaroslav/MH/RR fixed ARM struct alignment problem when byte-swapping - MH fixed short filename problem in FslFileType - RR added RGBA32 type nad NIFTI_ECODE_FREESURFER macros - RR added 5 NIFTI_INTENT codes for GIFTI - RR added nifti_datatype_to_string and similar functionality - MH Simplified CMake configuration to apply same shared library version to all libraries. ----------------------------------------------------------------- Updated in version 1.1.0 August 28, 2008 - RR allowed ANALYZE headers in nifti_hdr_looks_good - RR added nifti_compiled_with_zlib() - RR added nifti_tool ability to add extensions via 'file:FILENAME' - RR added new tests to nifti_regress_test/commands - RR added ANALYZE 7.5 support for swapping - HJ addressed CMake bug listed by ITK at http://www.itk.org/Bug/view.php?id=7530 having to do with ITK version numbers for znzlib. ----------------------------------------------------------------- Updated in version 2.0.0 July 20, 2010 - RR added nifti_NBL_matches_nim() check for write_bricks() - HJ added casts to suppress compiler warnings - RR added NIFTI_ECODE_PYPICKLE - RR added NIFTI_ECODEs 18-28 for the LONI MiND group - RR added examples/clib_01_read_write.c as a simple library example - RR allow uppercase extension - RR added 4 checks of alloc() returns - RR added NIFTI_ECODE_VOXBO for Dan Kimberg of VoxBo - RR added NIFTI_ECODE_CARET for John Harwell of Caret - RR fixed znzread/write for large files - RR changed nifti_swap_* routines/calls to take size_t - RR fixed nifti_tool.c:nt_read_bricks bsize for large files - MH updated CMakeLists.txt to version 2.0 ----------------------------------------------------------------- Updated in version 3.0.0 July 16, 2020 - HJ Merged ITK and official nifti branch for code compatibility across many compilers by removing compiler warnings - HJ added a few free() calls in failure cases - HJ const modifications and casting - RR NIFTI-1: minor updates when testing new build - RR (2015) invalid ecodes are no longer fatal - RR (2015) NIFTI-2: - added nifti2 tree, for NIFTI-2 version of I/O library - header and matrix types went to 64-bit : NOT backwards compatible - have nifti1_image for old version and nifti_image for new - depends on nifti1.h, but nothing else from NIFTI-1 - HJ: duped nifti1.h under nifti2 tree, so it is standalone - includes new nifti_tool.[ch] - some functions/args were changed to 64-bit/NIFTI-2, some 64-bit/NIFTI-2 versions were added - added modest processing for CIFTI images - RR added NIFTI_ECODE_CIFTI, VF_TIMIING, EVAL, MATLAB, QUANTIPHYSE - HJ safeguard potential memory leaks and NULL dereferences - effigies: added FSL intent codes - JL/HJ: re-wrote Cmake build system - JL/HJ: created new automated testing system under cmake - JL/HJ/RR: added more tests - PT/DRG: added xform code NIFTI_XFORM_TEMPLATE_OTHER - RR added c21 test scripts Updated in version 3.0.1 Aug 07, 2020 - JL made fix for cmake config add example usage and a test for it - JL changed default behavior to not build manpages - RR made a fix for the make build and added a suggestion to use the cmakenifti_clib-3.0.1/cifti/000077500000000000000000000000001371325713600147235ustar00rootroot00000000000000nifti_clib-3.0.1/cifti/CMakeLists.txt000066400000000000000000000021161371325713600174630ustar00rootroot00000000000000include(FindEXPAT) set(NIFTI_CIFTILIB_NAME ${NIFTI_PACKAGE_PREFIX}cifti) add_nifti_library(${NIFTI_CIFTILIB_NAME} afni_xml.c afni_xml_io.c ) set_target_properties( ${NIFTI_CIFTILIB_NAME} PROPERTIES PRIVATE_HEADER "${CMAKE_CURRENT_LIST_DIR}/afni_xml.h;${CMAKE_CURRENT_LIST_DIR}/afni_xml_io.h" ) target_link_libraries( ${NIFTI_CIFTILIB_NAME} PUBLIC EXPAT::EXPAT ${NIFTI_PACKAGE_PREFIX}nifti2) # Set lib version when buildung shared libs. if(BUILD_SHARED_LIBS) set_target_properties(${NIFTI_CIFTILIB_NAME} PROPERTIES ${NIFTI_LIBRARY_PROPERTIES}) endif() install_nifti_target(${NIFTI_CIFTILIB_NAME}) if(NIFTI_BUILD_APPLICATIONS) add_nifti_executable(${NIFTI_PACKAGE_PREFIX}afni_xml_tool afni_xml_tool.c) target_link_libraries(${NIFTI_PACKAGE_PREFIX}afni_xml_tool PUBLIC ${NIFTI_CIFTILIB_NAME}) add_nifti_executable(${NIFTI_PACKAGE_PREFIX}cifti_tool cifti_tool.c) target_link_libraries(${NIFTI_PACKAGE_PREFIX}cifti_tool PUBLIC ${NIFTI_CIFTILIB_NAME}) install_nifti_target(${NIFTI_PACKAGE_PREFIX}afni_xml_tool) install_nifti_target(${NIFTI_PACKAGE_PREFIX}cifti_tool) endif() nifti_clib-3.0.1/cifti/Makefile000066400000000000000000000026111371325713600163630ustar00rootroot00000000000000 # note the TARFILE_NAME embeds the release version number TARFILE_NAME = nifti2clib-0.0.1 USEZLIB = -DHAVE_ZLIB N2DIR = ../nifti2 ## Compiler defines CC = gcc -g IFLAGS = -I. CFLAGS = -Wall -std=gnu99 -pedantic NIFLAGS = $(IFLAGS) -I$(N2DIR) -I../niftilib -I../znzlib $(USEZLIB) LLIBS = -lz -lm OBJS = afni_xml.o afni_xml_io.o NOBJS = nifti2_io.o nifticdf.o znzlib.o # -------------------------------------------------- # default compile for C files %.o : %.c %.h $(CC) -c $(CFLAGS) $(NIFLAGS) $< -o $@ # -------------------------------------------------- # main targets (primary is nifti_tool, for now) afni_xml_tool: afni_xml_tool.c $(OBJS) $(CC) -o $@ $(CFLAGS) $(IFLAGS) $< $(OBJS) -lexpat $(LLIBS) clean: $(RM) *.o afni_xml_tool cifti_tool #afni_xml.o: afni_xml.c afni_xml.h # $(CC) -c $(CFLAGS) -I. $< cifti_tool.o: cifti_tool.c $(CC) -c $(CFLAGS) $(NIFLAGS) $< cifti_tool: $(OBJS) $(NOBJS) cifti_tool.o $(CC) -o $@ $(CFLAGS) $(NIFLAGS) \ cifti_tool.o $(OBJS) $(NOBJS) -lexpat $(LLIBS) # -------------------------------------------------- # targets from source residing elsewhere nifti2_io.o: $(CC) -c -DHAVE_ZLIB $(CFLAGS) $(NIFLAGS) $(N2DIR)/nifti2_io.c nifticdf.o: $(CC) -c -DHAVE_ZLIB $(CFLAGS) $(NIFLAGS) ../nifticdf/nifticdf.c znzlib.o: $(CC) -c -DHAVE_ZLIB $(CFLAGS) $(NIFLAGS) ../znzlib/znzlib.c nifti_clib-3.0.1/cifti/afni_xml.c000066400000000000000000000713041371325713600166710ustar00rootroot00000000000000#include #include #include #include #include #include #include "afni_xml.h" #define AXML_MIN_BSIZE 2048 #define AXML_DEF_BSIZE 32768 /* local prototypes */ #ifndef XMLCALL /* XMLCALL was added to expat in version 1.95.7 to define a calling convention, * as cdecl */ #if defined(XML_USE_MSC_EXTENSIONS) #define XMLCALL __cdecl #elif defined(__GNUC__) && defined(__i386) #define XMLCALL __attribute__((cdecl)) #else #define XMLCALL #endif #endif /* not defined XMLCALL */ #ifndef XML_STATUS_ERROR #define XML_STATUS_ERROR 0 #endif #ifndef XML_STATUS_OK #define XML_STATUS_OK 1 #endif /* * realloc does not clear memory of ptr on failure. * This wrapper function checks the return status, * and deletes ptr if reallocation fails. */ static void * safe_realloc(void * ptr , size_t size) { void * ptr_realloc = realloc( ptr, size ); if(!ptr_realloc) { free(ptr); } return ptr_realloc; } /* ---------------------------------------------------------------------- */ /* XML global struct and access functions */ static afni_xml_control gAXD = { 1, /* verb, default to 1 (0 means quiet) */ 1, /* dstore, flag whether to store data */ 3, /* indent, spaces per indent level */ AXML_DEF_BSIZE, /* buf_size, allocated for XML parsing */ NULL, /* wstream */ 0, /* depth, current stack depth */ 0, /* dskip depth (at positive depth, 0 is clear)*/ 0, /* errors, number of encountered errors */ 0, /* wkeep, keep white until pop */ {NULL}, /* stack, of afni_xml_t * */ NULL, /* afni_xml_list * xroot */ }; /*---------- accessor functions for user-controllable variables ----------*/ /*---------- (one can pass -1 to set the default value) ----------*/ /*! verb is the verbose level, with 0 meaning "only report errors" (up to 7) */ int axml_get_verb( void ){ return gAXD.verb; } int axml_set_verb( int val ) { if ( val == -1 ) gAXD.verb = 1; else if( val >= 0 ) gAXD.verb = val; return 0; } /*! the dstore flag controls whether data is read from a GIFTI file */ int axml_get_dstore( void ){ return gAXD.dstore; } int axml_set_dstore( int val ) { if( val ) gAXD.dstore = 1; /* includes -1 as applying the default */ else gAXD.dstore = 0; return 0; } /*! indent is the number of spaces per indent level written to a GIFTI file */ int axml_get_indent( void ){ return gAXD.indent; } int axml_set_indent( int val ) { if ( val == -1 ) gAXD.indent = 3; else if ( val >= 0 ) gAXD.indent = val; else return 1; /* failure - no action */ return 0; } /*! buf_size is the size of the XML I/O buffer given to expat */ int axml_get_buf_size( void ){ return gAXD.buf_size; } int axml_set_buf_size( int val ) { if ( val == -1 ) gAXD.buf_size = AXML_DEF_BSIZE; else if ( val > 0 ) gAXD.buf_size = val; else return 1; /* failure - no action */ return 0; } /*! wstream is the write stream, should be valid or NULL */ FILE * axml_get_wstream( void ) { return gAXD.wstream; } int axml_set_wstream( FILE * fp ) { gAXD.wstream = fp; return 0; } /*----------------------- local prototypes -----------------------------*/ static XML_Parser init_xml_parser (void *); static void XMLCALL cb_char (void *, const char *, int); static void XMLCALL cb_default (void *, const char *, int); static void XMLCALL cb_start_ele(void *, const char *, const char **); static void XMLCALL cb_stop_ele (void *, const char *); static int epush(afni_xml_control *, const char *, const char **); static int epop (afni_xml_control *, const char *); static int add_to_xchild_list(afni_xml_t * parent, afni_xml_t * child); static int add_to_xroot_list (afni_xml_control * xd, afni_xml_t * newp); static int append_to_string(char **, int *, const char *, int); static int disp_axml_ctrl ( const char *mesg, afni_xml_control * dp, int show_all ); static int disp_gen_text(afni_xml_control *, const char *, const char *, int); static void free_whitespace(void); static int init_axml_ctrl (afni_xml_control *xd, int doall); static int process_popped_element(afni_xml_control * xd, const char * ename); static int reset_xml_buf (afni_xml_control * xd, char ** buf, int * bsize); static int white_first (const char * str, int len); static int white_last (const char * str, int len); static int show_depth (afni_xml_control *, int show); static int show_attrs (afni_xml_control *, const char **, int); static int64_t loc_strnlen (const char * str, int64_t maxlen); static afni_xml_t * make_afni_xml (const char * ename, const char ** attr); static char * strip_whitespace(const char * str, int slen); /*----------------------- main I/O functions ---------------------------*/ /* note: the buffer needs to be large enough to contain any contiguous piece of (CDATA?) text, o.w. it will require parsing in pieces */ afni_xml_list axml_read_file(const char * fname, int read_data) { afni_xml_control * xd = &gAXD; /* point to global struct */ afni_xml_list xlist = {0, NULL}; XML_Parser parser; unsigned blen; FILE * fp; char * buf = NULL; int64_t bshort; int bsize; /* be sure it doesn't change at some point */ int done = 0, pcount = 1; if( init_axml_ctrl(xd, 0) ) /* reset non-user variables */ return xlist; xd->xroot = &xlist; /* return struct */ xd->dstore = read_data; /* store for global access */ if( !fname ) { fprintf(stderr,"** axml_read_image: missing filename\n"); xd->xroot = NULL; return xlist; } fp = fopen(fname, "r"); if( !fp ) { fprintf(stderr,"** failed to open XML file '%s'\n", fname); xd->xroot = NULL; return xlist; } /* create a new buffer */ bsize = 0; if( reset_xml_buf(xd, &buf, &bsize) ) { fclose(fp); xd->xroot = NULL; return xlist; } if(xd->verb > 1) fprintf(stderr,"-- reading xml file '%s'\n", fname); /* create parser, init handlers */ parser = init_xml_parser((void *)xd); while( !done ) { if( reset_xml_buf(xd, &buf, &bsize) ) break; blen = fread(buf, 1, bsize, fp); /* check for early termination */ bshort = loc_strnlen(buf, blen); if( bshort < blen ) { if( xd->verb > 1 ) fprintf(stderr,"-- AXML: truncating fbuffer from %u to %" PRId64 "\n", blen, bshort); blen = (int)bshort; } done = blen < (unsigned) bsize; if(xd->verb > 4) fprintf(stderr,"-- XML_Parse # %d\n", pcount); pcount++; if( XML_Parse(parser, buf, blen, done) == XML_STATUS_ERROR) { fprintf(stderr,"** %s at line %u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser)); break; } } fclose(fp); if( buf ) free(buf); /* parser buffer */ XML_ParserFree(parser); if(xd->verb > 1) fprintf(stderr,"++ done parsing XML file %s\n", fname); xd->xroot = NULL; /* Stop pointing to xlist */ return xlist; } /* parse a complete buffer as XML */ afni_xml_list axml_read_buf(const char * buf_in, int64_t bin_len) { afni_xml_control * xd = &gAXD; /* point to global struct */ afni_xml_list xlist = {0, NULL}; XML_Parser parser; unsigned blen; int64_t bin_remain; const char * bin_ptr = buf_in; /* current buffer location */ char * buf = NULL; int bsize; /* be sure it doesn't change at some point */ int done = 0, pcount = 1; if( init_axml_ctrl(xd, 0) ) /* reset non-user variables */ return xlist; xd->xroot = &xlist; /* return struct */ xd->dstore = 1; /* store for global access */ if( ! buf_in || bin_len < 0L ) { fprintf(stderr,"** axml_read_buf: missing buffer\n"); xd->xroot=NULL; return xlist; } /* check for early termination */ bin_remain = loc_strnlen(buf_in, bin_len); if( bin_remain < bin_len && xd->verb > 1 ) fprintf(stderr,"-- AXML: truncating buffer from %" PRId64 " to %" PRId64 "\n", bin_len, bin_remain); /* create a new buffer */ bsize = 0; if( reset_xml_buf(xd, &buf, &bsize) ) { xd->xroot = NULL; /* Stop pointing to xlist */ return xlist; } if(xd->verb > 1) fprintf(stderr,"-- reading xml from length %" PRId64 " buffer\n", bin_remain); /* create parser, init handlers */ parser = init_xml_parser((void *)xd); while( !done ) { if( reset_xml_buf(xd, &buf, &bsize) ) break; /*--- replace fread with buffer copy ---*/ /* decide how much to copy and copy */ if( bin_remain >= bsize ) blen = bsize; else blen = bin_remain; if(blen > 0 && blen <= (unsigned)bsize) { memcpy(buf, bin_ptr, blen); buf[blen] = '\0'; } /* update bytes remaining to process and decide if done */ bin_remain -= blen; bin_ptr += blen; done = bin_remain <= 0; if(xd->verb > 4) fprintf(stderr,"-- XML_Parse # %d\n", pcount); pcount++; if( XML_Parse(parser, buf, blen, done) == XML_STATUS_ERROR) { fprintf(stderr,"** %s at line %u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser)); break; } } if( buf ) free(buf); /* parser buffer */ XML_ParserFree(parser); if(xd->verb > 1) fprintf(stderr,"++ done parsing XML buffer\n"); xd->xroot = NULL; /* Stop pointing to xlist */ return xlist; } /* display the list of afni_xml_t structs */ int axml_disp_xlist( const char *mesg, afni_xml_list * axlist, int verb) { FILE * fp = stderr; int ind; if( gAXD.wstream != NULL ) fp = gAXD.wstream; if( mesg ) fputs(mesg, fp); if( ! axlist || ! axlist->xlist ) { fprintf(fp, "afni_xml_list is EMPTY\n"); return 0; } fprintf(fp, "afni_xml_list, len = %d\n", axlist->len); for(ind = 0; ind < axlist->len; ind++ ) { fprintf(fp, " afni_xml_t root %d of %d:\n", ind+1, axlist->len); axml_disp_xml_t(NULL, axlist->xlist[ind], gAXD.indent, verb); } return 0; } /* recursive function to display an afni_xml_t struct */ int axml_disp_xml_t( const char *mesg, afni_xml_t * ax, int indent, int verb) { FILE * fp = stderr; int ind; if( gAXD.wstream != NULL ) fp = gAXD.wstream; if( mesg ) fprintf(fp, "%*s%s", indent, "", mesg); /* bail on no struct */ if( ! ax ) { fprintf(fp, "%*sNULL\n", indent, ""); return 1; } if( verb > 1 ) { fprintf(fp, "%*s - name : %s\n", indent-gAXD.indent, "", ax->name); if( verb > 2 ) { if(ax->xtext) { if(verb>3) fprintf(fp, "%*sxtext : %s\n",indent,"",ax->xtext); else fprintf(fp, "%*sxtext : %.30s...\n",indent,"", ax->xtext); } else fprintf(fp, "%*sxtext : NULL\n", indent, ""); fprintf(fp, "%*sxlen : %d\n", indent, "", ax->xlen); fprintf(fp, "%*scdata : %d\n", indent, "", ax->cdata); fprintf(fp, "%*sencode : %d\n", indent, "", ax->encode); /* only display binary information if there is something there */ if( ax->bdata || ax->blen > 0 ) { fprintf(fp, "%*sbdata : %s\n", indent, "", ax->bdata ? "SET" : "CLEAR"); fprintf(fp, "%*sblen : %" PRId64 "\n", indent, "", ax->blen); fprintf(fp, "%*sbtype : %d\n", indent, "", ax->btype); } } fprintf(fp, "%*snattrs : %d\n", indent, "", ax->attrs.length); if( verb > 2 ) { for(ind=0; ind < ax->attrs.length; ind++) fprintf(fp, "%*s '%s' = '%s'\n", indent, "", ax->attrs.name[ind], ax->attrs.value[ind]); } fprintf(fp, "%*snchild : %d\n", indent, "", ax->nchild); if(verb>3) fprintf(fp, "%*sxparent : %s\n",indent,"", ax->xparent ? "SET" : "NONE" ); } else /* just show the name */ fprintf(fp, "%*s%s\n", indent, "", ax->name); /* recursively display the child structures */ for(ind=0; ind < ax->nchild; ind++) axml_disp_xml_t(NULL, ax->xchild[ind], indent+gAXD.indent, verb); return 0; } /* allocate a new afni_xml_t struct, and possibly copy the name */ afni_xml_t * new_afni_xml(const char * name) { afni_xml_t * newp; newp = (afni_xml_t *)calloc(1, sizeof(afni_xml_t)); if( ! newp ) { fprintf(stderr,"** failed to alloc afni_xml_t struct\n"); return NULL; } /* be picky with pointers */ newp->name = NULL; newp->xtext = NULL; newp->bdata = NULL; newp->xparent = NULL; newp->xchild = NULL; if( name ) newp->name = strdup(name); return newp; } int axml_add_attrs(afni_xml_t * ax, const char ** attr) { int c, aind, natr; if( ! ax ) return 1; if( ! attr ) return 0; if( ax->attrs.name || ax->attrs.value ) fprintf(stderr,"** axml_add_attrs: have non-NULL at input\n"); for(c=0, natr=0; attr[c]; c += 2, natr++) ; /* just count */ ax->attrs.length = natr; if( natr == 0 ) { /* we are done */ ax->attrs.name = NULL; ax->attrs.value = NULL; return 0; } ax->attrs.name = (char **)malloc(natr*sizeof(char *)); ax->attrs.value = (char **)malloc(natr*sizeof(char *)); /* failure? */ if( ! ax->attrs.name || ! ax->attrs.value ) { fprintf(stderr,"** NAX: failed to alloc 2 sets of %d char*\n", natr); ax->attrs.length = 0; if( ax->attrs.name ) free(ax->attrs.name); if( ax->attrs.value ) free(ax->attrs.value); ax->attrs.name = ax->attrs.value = NULL; return 1; } /* and get the attributes */ for(c = 0, aind = 0; attr[c]; c += 2, aind++) { ax->attrs.name[aind] = strdup(strip_whitespace(attr[c],0)); ax->attrs.value[aind] = strdup(strip_whitespace(attr[c+1],0)); } return 0; } /* free the list of afni_xml_t structs */ int axml_free_xlist(afni_xml_list * axlist) { int ind; /* check for quick returns */ if( ! axlist ) return 0; if( ! axlist->xlist ) { axlist->len = 0; return 0; } for( ind = 0; ind < axlist->len; ind++ ) axml_free_xml_t(axlist->xlist[ind]); free(axlist->xlist); axlist->xlist = NULL; axlist->len = 0; free_whitespace(); /* this frees static string in strip_whitespace */ return 0; } /* recursive free */ int axml_free_xml_t(afni_xml_t * ax) { int ind; if( !ax ) return 0; if( ax->name ) { free(ax->name); ax->name = NULL; } if( ax->xtext ) { free(ax->xtext); ax->xtext = NULL; } if( ax->bdata ) { free(ax->bdata); ax->bdata = NULL; } ax->xlen = 0; /* free all attributes */ for(ind = 0; ind < ax->attrs.length; ind++ ) { if( ax->attrs.name && ax->attrs.name[ind] ) free(ax->attrs.name[ind]); if( ax->attrs.value && ax->attrs.value[ind] ) free(ax->attrs.value[ind]); } if( ax->attrs.name ) { free(ax->attrs.name); ax->attrs.name = NULL; } if( ax->attrs.value ) { free(ax->attrs.value); ax->attrs.value = NULL; } ax->attrs.length = 0; /* and free children */ if( ax->nchild > 0 && ax->xchild ) for( ind=0; ind < ax->nchild; ind++ ) axml_free_xml_t(ax->xchild[ind]); ax->nchild = 0; if( ax->xchild ) { free(ax->xchild); ax->xchild = NULL; } ax->xparent = NULL; free(ax); return 0; } /* generic recursive function that processes an afni_xml_t tree */ int axml_recur(int(*func)(FILE * fp, afni_xml_t *, int), afni_xml_t * ax) { static int depth = 1; int ind; if( !func || !ax ) return 1; /* call on current struct and recur over kids */ func(gAXD.wstream, ax, depth); depth++; if( ax->nchild > 0 && ax->xchild ) for( ind=0; ind < ax->nchild; ind++ ) axml_recur(func, ax->xchild[ind]); depth--; return 0; } /* generic recursive function to find something in an xml tree (using a depth-first search) func : function to determine whether a struct is the desired one ax : root of the search tree depth : current depth max_depth : if > 0, limit the search to this depth */ afni_xml_t * axml_recur_find_xml(int(*func)(afni_xml_t *, int), afni_xml_t * ax, int depth, int max_depth) { afni_xml_t * rv = NULL; int ind; if( !func || !ax ) return NULL; /* if we are looking at the correct struct, return it */ if( func(ax, depth) ) return ax; /* if we are at the maximum depth and have not found it, fail */ if( max_depth > 0 && depth >= max_depth ) return NULL; /* search deeper */ if( ax->nchild > 0 && ax->xchild ) for( ind=0; ind < ax->nchild; ind++ ) { rv = axml_recur_find_xml(func, ax, depth+1, max_depth); if( rv ) return rv; } return NULL; /* failure - not in this tree */ } /* return corresponding value pointer for attribute */ char * axml_attr_value(afni_xml_t * ax, const char * name) { int ind; if( !ax ) return NULL; for( ind = 0; ind < ax->attrs.length; ind++ ) if( ! strcmp(ax->attrs.name[ind], name) ) return ax->attrs.value[ind]; return NULL; /* not found */ } /*----------------------- end main I/O functions -----------------------*/ static int init_axml_ctrl(afni_xml_control *xd, int doall) { if( doall ) { /* user modifiable - init all to defaults */ xd->verb = 1; xd->dstore = 1; xd->indent = 3; xd->buf_size = AXML_DEF_BSIZE; xd->wstream = stderr; /* rcr - ponder accessor (might need close) */ } xd->depth = 0; xd->dskip = 0; xd->errors = 0; xd->wkeep = 0; memset(xd->stack, 0, sizeof(xd->stack)); xd->xroot = NULL; /* maybe show the user */ if( xd->verb > 2 ) disp_axml_ctrl("-- user opts: ", xd, xd->verb > 3); return 0; } static int disp_axml_ctrl( const char *mesg, afni_xml_control * dp, int show_all ) { if( mesg ) fputs(mesg, stderr); if( !dp ) return 1; fprintf(stderr,"afni_xml_control :\n" " verb : %d\n" " dstore : %d\n" " indent : %d\n" " buf_size : %d\n" , dp->verb, dp->dstore, dp->indent, dp->buf_size); if( show_all ) fprintf(stderr, " depth : %d\n" " dskip : %d\n" " errors : %d\n" " wkeep : %d\n" , dp->depth, dp->dskip, dp->errors, dp->wkeep); return 0; } /* if bsize is no longer correct, update it and safe_realloc the buffer */ static int reset_xml_buf(afni_xml_control * xd, char ** buf, int * bsize) { if( *bsize == xd->buf_size ) { if( xd->verb > 3 ) fprintf(stderr,"-- buffer kept at %d bytes\n", *bsize); return 0; } if( xd->verb > 2 ) fprintf(stderr,"++ update buf, %d to %d bytes\n",*bsize,xd->buf_size); *bsize = xd->buf_size; *buf = (char *)safe_realloc(*buf, (*bsize+1) * sizeof(char)); if( ! *buf ) { fprintf(stderr,"** failed to alloc %d bytes of xml buf!\n", *bsize); *bsize = 0; return 1; } return 0; } static XML_Parser init_xml_parser(void * user_data) { XML_Parser parser = XML_ParserCreate(NULL); XML_SetUserData(parser, user_data); XML_SetStartElementHandler(parser, cb_start_ele); XML_SetEndElementHandler (parser, cb_stop_ele); XML_SetCharacterDataHandler(parser, cb_char); XML_SetDefaultHandler (parser, cb_default); if( gAXD.verb > 3 ) fprintf(stderr,"-- parser initialized\n"); return parser; } static void XMLCALL cb_start_ele(void *udata, const char *ename, const char **attr) { afni_xml_control * xd = (afni_xml_control *)udata; if( xd->wkeep ) xd->wkeep = 0; /* clear storage continuation */ (void)epush(xd, ename, attr); } static void XMLCALL cb_stop_ele(void *udata, const char *ename) { afni_xml_control * xd = (afni_xml_control *)udata; if( xd->wkeep ) xd->wkeep = 0; /* clear storage continuation */ (void)epop(xd, ename); } static int epush(afni_xml_control * xd, const char * ename, const char ** attr) { afni_xml_t * acur = NULL; int errs = 0; if( xd->wkeep ) xd->wkeep = 0; /* clear storage continuation */ xd->depth++; if( xd->depth <= 0 || xd->depth > AXML_MAX_DEPTH ) { fprintf(stderr,"** push: stack depth %d out of [0,%d] range\n", xd->depth, AXML_MAX_DEPTH); xd->errors++; errs = 1; } if( xd->verb > 2 ) { /* maybe we want to print something */ show_depth(xd, 1); fprintf(stderr,"++ push '%s'\n", ename); if( xd->verb > 3 ) show_attrs(xd, attr, 1); } /* determine whether we should go into a skip block */ if( errs ) xd->dskip = xd->depth; /* if we are in a skip block, do nothing but monitor stack */ if( xd->dskip ) { if( xd->verb > 3 ) fprintf(stderr,"-- skip=%d, depth=%d, skipping push element '%s'\n", xd->dskip, xd->depth, ename); } else { /* --- control depth and corresponding vars --- */ acur = make_afni_xml(ename, attr); if( ! acur ) { xd->dskip = xd->depth; return 1; } xd->stack[xd->depth-1] = acur; /* we have either a root element or a child */ if( xd->depth == 1 ) { if( add_to_xroot_list(xd, acur) ) { xd->dskip = xd->depth; return 1; } } else { if( add_to_xchild_list(xd->stack[xd->depth-2], acur) ) { xd->dskip = xd->depth; return 1; } } } return 0; } static int epop(afni_xml_control * xd, const char * ename) { if( xd->wkeep ) xd->wkeep = 0; /* clear storage continuation */ if( xd->dskip ) { if( xd->dskip == xd->depth ) xd->dskip = 0; /* clear */ if( xd->verb > 3 ) fprintf(stderr,"-- skip=%d, depth=%d, skipping pop element '%s'\n", xd->dskip, xd->depth, ename); } else { process_popped_element(xd, ename); } if( ! xd->dskip ) { xd->stack[xd->depth-1] = NULL; /* should be irrelevant */ if( xd->verb > 4 ) { show_depth(xd, 1); fprintf(stderr,"++ pop '%s'\n", ename); } } xd->depth--; return 0; } static int process_popped_element(afni_xml_control * xd, const char * ename) { afni_xml_t * ax; ax = xd->stack[xd->depth-1]; if( strcmp(ename, ax->name) ) { if( gAXD.verb ) fprintf(stderr,"** pop mismatch!\n"); return 1; } return 0; } static int add_to_xroot_list(afni_xml_control * xd, afni_xml_t * newp) { /* init */ if( xd->xroot->len <= 0 ) { xd->xroot->len = 0; xd->xroot->xlist = NULL; } xd->xroot->len++; xd->xroot->xlist = (afni_xml_t **)safe_realloc(xd->xroot->xlist, xd->xroot->len * sizeof(afni_xml_t *)); if( ! xd->xroot->xlist ) { fprintf(stderr,"** failed to alloc %d AXMLT pointers\n", xd->xroot->len); return 1; } xd->xroot->xlist[xd->xroot->len-1] = newp; return 0; } static int add_to_xchild_list(afni_xml_t * parent, afni_xml_t * child) { /* init */ if( parent->nchild <= 0 ) { parent->nchild = 0; parent->xchild = NULL; } parent->nchild++; parent->xchild = (afni_xml_t **)safe_realloc(parent->xchild, parent->nchild * sizeof(afni_xml_t *)); if( ! parent->xchild ) { fprintf(stderr,"** failed to alloc %d AXML pointers\n", parent->nchild); return 1; } parent->xchild[parent->nchild-1] = child; /* and note the child's parent */ child->xparent = parent; return 0; } static afni_xml_t * make_afni_xml(const char * ename, const char ** attr) { afni_xml_t * newp; newp = new_afni_xml(ename); if( ! newp ) return NULL; axml_add_attrs(newp, attr); return newp; } static int show_attrs(afni_xml_control * xd, const char ** attr, int showd) { int count; for( count = 0; attr[count]; count += 2 ){ if( showd ) show_depth(xd, 0); fprintf(stderr," attr: %s='%s'\n", attr[count], attr[count+1]); } return 0; } static void free_whitespace(void) { strip_whitespace(NULL,-2); } /* if slen == 0, use entire length */ static char * strip_whitespace(const char * str, int slen) { static char * buf = NULL; static int blen = 0; int len, ifirst, ilast; /* first non-white char and AFTER last */ /* backdoor to free this memory, e.g. on call to free list */ if(!str && slen == -2){if(buf) { free(buf); buf=NULL; } blen=0; return 0; } /* if string is long, forget it */ if( !str || slen > 1024 ) return (char *)str; len = strlen(str); if( slen > 0 && slen < len ) len = slen; if( len <= 0 ) return (char *)str; /* make sure we have local space */ if( len > blen ) { /* allocate a bigger buffer */ buf = (char *)safe_realloc(buf, (len+1) * sizeof(char)); if( !buf ) { fprintf(stderr,"** failed to alloc wspace buf of len %d\n", len+1); return (char *)str; } blen = len; } ifirst = white_first(str, len); ilast = white_last(str, len); if( ifirst == len ) *buf = '\0'; else { strncpy(buf, str+ifirst, len-ifirst-ilast); buf[len-ifirst-ilast] = '\0'; } return buf; } static void XMLCALL cb_char(void *udata, const char * cdata, int length) { afni_xml_control * xd = (afni_xml_control *)udata; afni_xml_t * parent; int wlen = white_first(cdata,length); /* wkeep: set once non-white chars are found, clear on push/pop */ /* once set: even white chars are appended to current xtext */ if( !xd->wkeep && wlen == length ) { if(xd->verb > 4) fprintf(stderr,"-- skipping white char [%d]\n",length); return; } if( xd->dskip ) { if(xd->verb > 3) fprintf(stderr,"-- skipping char [%d]\n",length); return; } if( ! xd->wkeep ) xd->wkeep = 1; /* store everything at this point */ if( xd->verb > 4 ) disp_gen_text(xd, "char", cdata, length); parent = xd->stack[xd->depth-1]; if( !parent ) { fprintf(stderr,"** no parent to store char data under\n"); return; } if( gAXD.dstore ) append_to_string(&parent->xtext, &parent->xlen, cdata, length); } /* append new string (of given length) to old string and length */ static int append_to_string(char ** ostr, int * olen, const char * istr, int ilen) { int newlen; /* be safe; also init old length to 1 */ if( !*ostr || *olen <= 0 ) { *ostr = NULL; *olen = 1; } newlen = *olen + ilen; *ostr = (char *)safe_realloc(*ostr, newlen * sizeof(char)); if( !*ostr ) { fprintf(stderr,"** AX.A2S: failed to alloc %d chars\n", newlen); return 1; } /* copy, starting at old nul char (if any), and terminate */ strncpy((*ostr)+*olen-1, istr, ilen); (*ostr)[newlen-1] = '\0'; *olen = newlen; return 0; } static int disp_gen_text(afni_xml_control * xd, const char * header, const char * cdata, int length) { const char * str = cdata; int wlen = white_first(cdata,length); int len = length; if( len == wlen ) { str = "whitespace"; /* just note the whitespace */ len = strlen(str); } show_depth(xd, 1); fprintf(stderr, "%s [len %d]: '%s'\n", header, length, strip_whitespace(str, len)); return 0; } static void XMLCALL cb_default(void * udata, const char * cdata, int length) { afni_xml_control * xd = (afni_xml_control *)udata; if( xd->wkeep ) xd->wkeep = 0; /* clear storage continuation */ if( xd->verb > 5 ) disp_gen_text(xd, "default XML", cdata, length); } static int show_depth(afni_xml_control * xd, int show) { FILE * fp = stderr; if( xd->wstream ) fp = xd->wstream; if( show ) fprintf(fp, "%*s %02d ", xd->indent*xd->depth, "", xd->depth); else fprintf(fp, "%*s ", xd->indent*xd->depth, ""); return 0; } static int white_first(const char * str, int len) { int c; if( !str || !*str || len < 1 ) return 0; for( c = 0; c < len; c++ ) if( !isspace(str[c]) ) return c; return len; } static int white_last(const char * str, int len) { int c; if( !str || !*str || len < 1 ) return 0; for( c = len-1; c >= 0; c-- ) if( !isspace(str[c]) ) return (len-1-c); return len; } /* like strlen(), but do not look or return past maxlen */ /* note: strnlen() is probably too new to assume */ static int64_t loc_strnlen(const char * str, int64_t maxlen) { const char * sptr; int64_t len; for( sptr=str, len=0; *sptr && len #include /* ---------------------------------------------------------------------- This code is for generic reading of xml into structures. Basically, everything is read in (data is optional) and can be evaluated for structural integrity (the default). Control options are provided by the afni_xml_control struct, via accessor functions. Much of afni_xml will be left as static. * ----------------------------------------------------------------------*/ /* --------------------------- structures --------------------------------- */ typedef struct { char ** name; char ** value; int length; } nvpairs; /* all memory implied by this structure is self contained */ typedef struct afni_xml_s { char * name; /* name of element */ char * xtext; /* XML data, still in text */ int xlen; /* length of (nul-terminated) XML data */ int cdata; /* flag: is data stored as CDATA */ int encode; /* encoding type (e.g. b64 binary) */ /* these fields are not for use by afni_xml, and are left clear */ void * bdata; /* decoded binary data */ int64_t blen; /* number of elements of btype */ int btype; /* probably a NIFTI data type */ nvpairs attrs; /* attributes */ int nchild; /* number of child elements */ struct afni_xml_s ** xchild; /* child elements */ struct afni_xml_s * xparent; /* parent element */ } afni_xml_t; typedef struct { int len; afni_xml_t ** xlist; } afni_xml_list; typedef struct { /* general control */ int verb; /* verbose level (0=quiet, 1=default) */ int dstore; /* flag: store data on read? */ int indent; /* spaces to indent when writing */ int buf_size; /* size of xml reading buffer */ FILE * wstream; /* show stream, maybe stderr */ /* active control and information */ int depth; /* current depth */ int dskip; /* stack depth to skip */ int errors; /* reading errors */ int wkeep; /* flag: keep found whitespace char */ /* (keep once non-white is seen, until any pop) */ afni_xml_t * stack[AXML_MAX_DEPTH]; /* xml stack of pointers */ afni_xml_list * xroot; /* list of root XML tree pointers */ } afni_xml_control; /* --------------------------- prototypes --------------------------------- */ /* main interface */ afni_xml_list axml_read_buf (const char * buf_in, int64_t bin_len); afni_xml_list axml_read_file(const char * fname, int read_data); int axml_disp_xlist( const char *mesg, afni_xml_list * axlist, int verb); int axml_disp_xml_t( const char *mesg, afni_xml_t * ax, int indent, int verb); /* create/free */ afni_xml_t * new_afni_xml (const char * name); int axml_add_attrs (afni_xml_t * ax, const char ** attr); int axml_free_xml_t(afni_xml_t * ax); int axml_free_xlist(afni_xml_list * axlist); char * axml_attr_value(afni_xml_t * ax, const char * name); int axml_recur(int(*func)(FILE*,afni_xml_t*,int), afni_xml_t * root); /* control API */ int axml_set_verb ( int val ); int axml_get_verb ( void ); int axml_set_dstore ( int val ); int axml_get_dstore ( void ); int axml_set_indent ( int val ); int axml_get_indent ( void ); int axml_set_buf_size ( int val ); int axml_get_buf_size ( void ); int axml_set_wstream ( FILE *fp ); FILE * axml_get_wstream ( void ); #endif /* AFNI_XML_H */ nifti_clib-3.0.1/cifti/afni_xml_io.c000066400000000000000000000371361371325713600173650ustar00rootroot00000000000000 /* This library depends on: afni_xml.c NIFTI-2 */ #include #include #include #include #include #include #include "afni_xml_io.h" /* local protos */ static afni_xml_t * xlist_to_ax1(afni_xml_list * xlist); static int axio_alloc_known_data(FILE * fp, afni_xml_t * ax, int depth); static int can_process_dtype(int dtype); static int dalloc_as_nifti_type(FILE * fp, afni_xml_t * ax, int64_t nvals,int); static void disp_name_n_desc(FILE * fp, afni_xml_t * ax, int indent, int verb); static void disp_brainmodel_child(FILE * fp, afni_xml_t * ax, int verb); static void disp_namedmap_child(FILE * fp, afni_xml_t * ax, int verb); static void disp_parcel_child(FILE * fp, afni_xml_t * ax, int verb); static void disp_surface_child(FILE * fp, afni_xml_t * ax, int verb); static void disp_volume_child(FILE * fp, afni_xml_t * ax, int verb); static int64_t text_to_i64(int64_t *result, const char * text, int64_t nvals); static int64_t text_to_f64(double * result, const char * text, int64_t nvals); /* read a complete CIFTI dataset, returning nifti and and xml pieces text data is converted to binary, when known */ int axio_read_cifti_file(const char * fname, int get_ndata, nifti_image ** nim_out, afni_xml_t ** ax_out) { nifti_image * nim = NULL; afni_xml_t * ax = NULL; if( !fname || !nim_out || !ax_out ) { fprintf(stderr,"** axio_CIFTI: NULL inputs %p, %p, %p\n", fname, (void *)nim_out, (void *)ax_out); return 1; } /* init */ *ax_out = NULL; /* set nim_out */ nim = nifti_image_read(fname, get_ndata); *nim_out = nim; if( ! nim ) { fprintf(stderr,"** axio: failed to read NIFTI part of %s\n", fname); return 1; } /* set ax_out */ ax = axio_cifti_from_ext(nim); *ax_out = ax; if( ! ax ) { fprintf(stderr,"** axio: no CIFTI extension found in %s\n", fname); return 1; } /* convert known data from text to binary */ return axml_recur(axio_alloc_known_data, ax); } /* read file into a single, allocated afni_xml_t struct */ afni_xml_t * axio_read_buf(const char * buf, int64_t blen) { afni_xml_list xlist; /* try to read file */ xlist = axml_read_buf(buf, blen); if( xlist.len <= 0 || ! xlist.xlist ) return NULL; /* return the first afni_xml_t tree */ return xlist_to_ax1(&xlist); } /* read file into a single, allocated afni_xml_t struct */ afni_xml_t * axio_read_file(const char * fname) { afni_xml_list xlist; /* try to read file */ xlist = axml_read_file(fname, 1); if( xlist.len <= 0 || ! xlist.xlist ) return NULL; /* return the first afni_xml_t tree */ return xlist_to_ax1(&xlist); } /* convert any known text to binary */ int axio_text_to_binary(afni_xml_t * ax) { if( ! ax ) return 0; return axml_recur(axio_alloc_known_data, ax); } int axio_num_tokens(const char * str, int64_t maxlen) { char * sp = (char *)str; int64_t ind, len, ntok; int intok; /* flag: are we inside a token? */ if( maxlen == 0 ) return 0; if( ! str || ! * str ) return 0; if( maxlen > 0 ) len = maxlen; else len = strlen(str); ntok = 0; intok = 0; for( ind = 0, sp = (char *)str; ind < len; ind++, sp++ ) { /* just look for state switches */ if( intok ) { if( isspace(*sp) || (*sp == ',') ) intok = 0; /* no longer within token */ } else { if( ! (isspace(*sp) || (*sp == ',')) ) { intok = 1; /* have new token */ ntok++; } } } return ntok; } afni_xml_t * axio_cifti_from_ext(nifti_image * nim) { nifti1_extension * ext; int ind; if( !nim ) return NULL; /* just read until we have a CIFTI extension to process */ ext = nim->ext_list; for( ind = 0; ind < nim->num_ext; ind++, ext++ ) { if( ext->ecode != NIFTI_ECODE_CIFTI ) continue; return axio_read_buf(ext->edata, ext->esize-8); } return NULL; } int axio_show_attrs(FILE * fp, afni_xml_t * ax, int indent) { FILE * ofp = fp ? fp : stderr; int ind, maxl, slen; if( !ax ) return 1; for( ind = 0, maxl = 1; ind < ax->attrs.length; ind++ ) { slen = strlen(ax->attrs.name[ind]); if( slen > maxl ) maxl = slen; } for( ind = 0; ind < ax->attrs.length; ind++ ) fprintf(ofp, "%*s%-*s = %s\n", indent, "", maxl, ax->attrs.name[ind], ax->attrs.value[ind]); return 0; } /* assume single Matrix for now */ int axio_show_cifti_summary(FILE * fp, char * mesg, afni_xml_t * ax, int verb) { FILE * ofp = fp ? fp : stderr; afni_xml_t * ac, * am; int ind; if( ! ax ) { fprintf(stderr,"** AX_SCS: missing ax pointer\n"); return 1; } if( mesg ) fputs(mesg, ofp); if( strcmp(ax->name, "CIFTI") ) { fprintf(ofp, "** missing CIFTI element, have %s\n", ax->name); return 1; } ac = axio_find_map_name(ax, "Matrix", 2); if( !ac ) { fprintf(ofp, "** missing CIFTI Matrix element\n"); return 1; } if( verb > 1 ) fprintf(ofp, "-- have %d MIMap/MD elements\n", ac->nchild); for( ind = 0; ind < ac->nchild; ind++ ) { am = ac->xchild[ind]; if( strcmp(am->name, "MatrixIndicesMap") ) continue; axio_show_mim_summary(ofp, NULL, am, verb); } return 0; } typedef void(*gen_disp_func_t)(FILE *, afni_xml_t *, int); #define AXIO_NMIM_KIDS 5 static const char * MIM_kids[AXIO_NMIM_KIDS+1] = { "NamedMap", "Surface", "Parcel", "Volume", "BrainModel", "INVALID" }; static gen_disp_func_t MIM_disp_funcs[AXIO_NMIM_KIDS] = { disp_namedmap_child, disp_surface_child, disp_parcel_child, disp_volume_child, disp_brainmodel_child }; static int get_map_index(afni_xml_t * ax) { int kid; if( ! ax->name || ! *ax->name ) return -1; for( kid=0; kidname, MIM_kids[kid]) ) return kid; return -1; } int axio_show_mim_summary(FILE * fp, const char * mesg, afni_xml_t * ax, int verb) { afni_xml_t * xm, * xt; FILE * ofp = fp ? fp : stderr; int kid, matkid, mind; if( ! ax ) { fprintf(stderr,"** AX_SMS: missing struct pointer\n"); return 1; } if( mesg ) fputs(mesg, ofp); xm = axio_find_map_name(ax, "Matrix", 2); if( !xm || strcmp(xm->name, "Matrix") ) { fprintf(ofp, "** missing Matrix element under %s\n", ax->name); return 1; } if( verb > 1 ) fprintf(ofp, "-- have %d Matrix children\n", xm->nchild); for( matkid = 0; matkid < xm->nchild; matkid++ ) { xt = xm->xchild[matkid]; if( strcmp(xt->name, "MatrixIndicesMap") ) continue; if( verb > 1 ) fprintf(ofp, "-- have %d MIMap children\n", xt->nchild); for( kid=0; kidnchild; kid++ ) { mind = get_map_index(xt->xchild[kid]); if( kid >= 0 ) MIM_disp_funcs[mind](ofp, xt->xchild[kid], verb); } } return 0; } /* depth first search for struct with given name if maxd >= 0, impose depth restriction */ afni_xml_t * axio_find_map_name(afni_xml_t * ax, const char * name, int maxd) { afni_xml_t * rv; int ind; if( !ax || !name || !*name ) return NULL; /* are we looking at it? */ if( ax->name && !strcmp(ax->name, name) ) return ax; /* are we done looking? */ if( maxd == 0 ) return NULL; for( ind=0; ind < ax->nchild; ind++ ) { rv = axio_find_map_name(ax->xchild[ind], name, maxd-1); if( rv ) return rv; } return NULL; } /* ====================================================================== */ /* ==== local functions, not for export ==== */ /* ====================================================================== */ static void disp_name_n_desc(FILE * fp, afni_xml_t * ax, int indent, int verb) { int max=50; if( !fp || !ax ) return; fprintf(fp, "%*s%s : ", indent, "", ax->name); if( ax && ax->xtext && ax->xlen > 0 ) { if( ax->xlen <= max ) fprintf(fp, "%.*s\n", ax->xlen, ax->xtext); else fprintf(fp, "\n%*s: %.*s ...\n", indent+3, "", max, ax->xtext); if( verb > 1 && ax->blen > 0 ) fprintf(fp, "%*s: %" PRId64 " values of type %s\n", indent+3, "", ax->blen, nifti_datatype_string(ax->btype)); } else fputc('\n', fp); if( verb > 1 )axio_show_attrs(fp, ax, indent+6); } static void disp_namedmap_child(FILE * fp, afni_xml_t * ax, int verb) { afni_xml_t * xt = axio_find_map_name(ax, "NamedMap", 1); afni_xml_t * xc = axio_find_map_name(ax, "MapName", 2); afni_xml_t * xl = axio_find_map_name(ax, "LabelTable", 2); /* NamedMap */ disp_name_n_desc(fp, xt, 6, verb); if( !xt ) return; if( xl ) fprintf(fp, " with length %d LabelTable\n", xl->nchild); disp_name_n_desc(fp, xc, 9, verb); disp_name_n_desc(fp, xl, 9, verb); fputc('\n', fp); } static void disp_surface_child(FILE * fp, afni_xml_t * ax, int verb) { afni_xml_t * xc = axio_find_map_name(ax, "Surface", 1); if( !xc ) return; disp_name_n_desc(fp, xc, 6, verb); fputc('\n', fp); } static void disp_parcel_child(FILE * fp, afni_xml_t * ax, int verb) { afni_xml_t * xc = axio_find_map_name(ax, "Parcel", 1); afni_xml_t * xc1, * xc2; if( !xc ) return; xc1 = axio_find_map_name(xc, "Vertices", 1); xc2 = axio_find_map_name(xc, "VoxelIndicesIJK", 1); disp_name_n_desc(fp, xc, 6, verb); disp_name_n_desc(fp, xc1, 9, verb); disp_name_n_desc(fp, xc2, 9, verb); fputc('\n', fp); } static void disp_volume_child(FILE * fp, afni_xml_t * ax, int verb) { afni_xml_t * xc = axio_find_map_name(ax, "Volume", 1); afni_xml_t * xc1; if( !xc ) return; xc1 = axio_find_map_name(xc, "TransformationMatrixVoxelIndicesIJKtoXYZ", 1); disp_name_n_desc(fp, xc, 6, verb); disp_name_n_desc(fp, xc1, 9, verb); fputc('\n', fp); } static void disp_brainmodel_child(FILE * fp, afni_xml_t * ax, int verb) { afni_xml_t * xc = axio_find_map_name(ax, "BrainModel", 1); afni_xml_t * xc1, * xc2; if( !xc ) return; xc1 = axio_find_map_name(xc, "VoxelIndicesIJK", 1); xc2 = axio_find_map_name(xc, "VertexIndices", 1); disp_name_n_desc(fp, xc, 6, verb); disp_name_n_desc(fp, xc1, 9, verb); disp_name_n_desc(fp, xc2, 9, verb); fputc('\n', fp); } /* allocate data for afni_xml_t struct, for known types (prototype matches first argument of axml_recur) */ static int axio_alloc_known_data(FILE * fp, afni_xml_t * ax, int depth) { int64_t ival = 0 ; char * cp; (void)(depth); /* avoid warnings, depth is not used for this variant */ if( ! ax ) return 1; if( ! ax->xtext || ax->xlen <= 0 ) return 0; /* nothing to allocate */ if( ax->bdata ) return 0; /* already allocated? */ if( ! ax->name ) { fprintf(stderr,"** missing ax name for data alloc\n"); return 1; } /* Vertices, TransformationMatrixVoxelIndicesIJKtoXYZ, VertexIndices, VoxelIndicesIJK (convert to straight index?) */ if( ! strcmp(ax->name, "TransformationMatrixVoxelIndicesIJKtoXYZ") ) return dalloc_as_nifti_type(fp, ax, 16, NIFTI_TYPE_FLOAT64); if( ! strcmp(ax->name, "Vertices") ) /* we do not know how many there will be, grrrr */ return dalloc_as_nifti_type(fp, ax, -1, NIFTI_TYPE_INT64); if( ! strcmp(ax->name, "VertexIndices") ) { cp = axml_attr_value(ax->xparent, "IndexCount"); if( ! cp ) { fprintf(fp, "** axAKD: no IndexCount\n"); return 1; } text_to_i64(&ival, cp, 1); return dalloc_as_nifti_type(fp, ax, ival, NIFTI_TYPE_INT64); } if( ! strcmp(ax->name, "VoxelIndicesIJK") ) { cp = axml_attr_value(ax->xparent, "IndexCount"); if( ! cp ) { fprintf(fp, "** axAKD: no ijk IndexCount\n"); return 1; } text_to_i64(&ival, cp, 1); /* allocate for this many IJK triples */ return dalloc_as_nifti_type(fp, ax, 3*ival, NIFTI_TYPE_INT64); } return 0; } static int dalloc_as_nifti_type(FILE * fp, afni_xml_t * ax, int64_t nvals, int dtype) { int nbyper = 0; int64_t nread, ntok; if( ! ax->xtext || ax->xlen <= 0 ) return 0; /* nothing to allocate */ if( ! can_process_dtype(dtype) ) { fprintf(stderr,"** DaNT, cannot process dtype %d\n", dtype); return 1; } /* if nvals is not known, count tokens */ if( nvals >= 0 ) ntok = nvals; else ntok = axio_num_tokens(ax->xtext, ax->xlen); if( ntok == 0 ) return 0; /* nothing to do */ /* -- we know what to do, get to work -- */ ax->blen = ntok; ax->btype = dtype; /* note number of bytes per value and number of values to allocate */ nifti_datatype_sizes(ax->btype, &nbyper, NULL); ax->bdata = malloc(nbyper * ntok); if( ! ax->bdata ) { fprintf(fp, "** axio_alloc: failed to allocate %" PRId64 " vals of size %d\n", ntok, nbyper); ax->blen = 0; return 1; } /* handle all types here */ if ( ax->btype == NIFTI_TYPE_FLOAT64 ) nread = text_to_f64((double *)ax->bdata, ax->xtext, ntok); else if ( ax->btype == NIFTI_TYPE_INT64 ) nread = text_to_i64((int64_t *)ax->bdata, ax->xtext, ntok); else { fprintf(stderr,"** DaNT: rcr - check bad dtype %d\n", ax->btype); nread = 0; } if( nread < ntok ) { if( nread == 0 ) { free(ax->bdata); ax->bdata = NULL; } ax->blen = nread; fprintf(fp, "** axio_alloc: read only %" PRId64 " of %" PRId64 " f64\n", nread, ntok); return 1; } return 0; } /* list all cases for which text_to_CASE is written */ static int can_process_dtype(int dtype) { if( dtype == NIFTI_TYPE_INT64 ) return 1; if( dtype == NIFTI_TYPE_FLOAT64 ) return 1; /* warn if type is not even nifti */ if( ! is_valid_nifti_type(dtype) ) fprintf(stderr,"** DNT, %d is invalid as NIFTI type\n", dtype); return 0; } /* this is currently processed as "long long", the meaning of which * varies, unfortunately */ static int64_t text_to_i64(int64_t * result, const char * text, int64_t nvals) { char * eptr, * sptr; int64_t * rptr, val; int64_t nread; *result = 0; /* Initialize to zero incase of failure */ if( ! text || ! result) return 1; if( nvals <= 0 ) return 0; sptr = (char *)text; nread = 0; rptr = result; while( sptr ) { val = (int64_t)strtoll(sptr, &eptr, 10); if( sptr == eptr) break; /* nothing to read */ /* get data and increment pointer and counter */ *rptr = val; rptr++; nread++; if( nread == nvals ) break; sptr = eptr; } return nread; } static int64_t text_to_f64(double * result, const char * text, int64_t nvals) { char * eptr, * sptr; double * rptr, val; int64_t nread; if( ! text || ! result) return 1; if( nvals <= 0 ) return 0; sptr = (char *)text; nread = 0; rptr = result; while( sptr ) { val = strtod(sptr, &eptr); if( sptr == eptr) break; /* nothing to read */ /* get data and increment pointer and counter */ *rptr = val; rptr++; nread++; if( nread == nvals ) break; sptr = eptr; } return nread; } /* convert xlist to single tree (so destroy xlist) */ static afni_xml_t * xlist_to_ax1(afni_xml_list * xlist) { afni_xml_t * newax; int c; /* steal first struct pointer */ newax = xlist->xlist[0]; xlist->xlist[0] = NULL; /* whine if we get too many structures */ if( xlist->len > 1 ) { fprintf(stderr,"** axio_read_file: not ready for multiple afni_xml_t\n"); for(c = 0; c < xlist->len; c++) axml_free_xml_t(xlist->xlist[c]); } /* and free pointer array */ free(xlist->xlist); return newax; } nifti_clib-3.0.1/cifti/afni_xml_io.h000066400000000000000000000056041371325713600173650ustar00rootroot00000000000000#ifndef AFNI_XML_IO_H #define AFNI_XML_IO_H #include #include "afni_xml.h" /* ---------------------------------------------------------------------- CIFTI XML structure: CIFTI attr = Version Matrix MetaData MD Name [text] Value [text] MatrixIndicesMap attr = ApliesToMatrixDimension, IndicesMapToDataType [int = intent code], NumberOfSeriesPoints, SeriesExponenet, SeriesStart, SeriesStep, SeriesUnit [string??] NamedMap MetaData LabelTable Label [text - name of label] attr = Key[int], Red, Green, Blue, Alpha [f 0..1] MapName [text - name of map] Surface attr = BrainStructure, SurfaceNumberOfVertices [int64_t] Parcel attr = Name [text] Vertices [int64_t (of unknown length?)] attr = BrainStructure VoxelIndicesIJK Volume attr = VolumeDimensions [int64_t,int64_t,int64_t] TransformationMatrixVoxelIndicesIJKtoXYZ [text - 16 x double xform matrix (row major)] attr = MeterExponent [int - power of 10] BrainModel attr = IndexOffset [int], IndexCount [int64_t], ModelType[??], BrainStructure[??], SurfaceNumberOfVertices VoxelIndicesIJK [int64_t triples (see IndexCount)] * might convert IJK to just Indices via VolumeDimensions (this is only for volume, Surface gives just indices) VertexIndices [int64_t (see IndexCount)] - convert as in SUMA_Create_Fake_CIFTI() * ----------------------------------------------------------------------*/ /* --------------------------- structures --------------------------------- */ /* --------------------------- prototypes --------------------------------- */ int axio_read_cifti_file(const char * fname, int get_ndata, nifti_image ** nim_out, afni_xml_t ** ax_out); afni_xml_t * axio_cifti_from_ext(nifti_image * nim); afni_xml_t * axio_read_buf (const char * buf, int64_t blen); afni_xml_t * axio_read_file(const char * fname); afni_xml_t * axio_find_map_name(afni_xml_t * ax, const char * name, int maxd); int axio_text_to_binary (afni_xml_t * ax); int axio_num_tokens (const char * str, int64_t maxlen); int axio_show_cifti_summary(FILE * fp, char * mesg, afni_xml_t * ax, int verb); int axio_show_mim_summary(FILE * fp, const char * mesg, afni_xml_t * ax, int verb); int axio_show_attrs(FILE * fp, afni_xml_t * ax, int indent); #endif /* AFNI_XML_IO_H */ nifti_clib-3.0.1/cifti/afni_xml_tool.c000066400000000000000000000074771371325713600177400ustar00rootroot00000000000000/* ---------------------------------------------------------------------- * A basic example to read/write an XML file via afni_xml. * * R Reynolds 24 Jun 2015 *---------------------------------------------------------------------- */ #include #include #include #include "afni_xml.h" /* ----------------------------------------------------------------- */ /* define and declare main option struct */ typedef struct { char * fin; char * fout; int disp_xlist; int verb; int xverb; } opts_t; opts_t gopt; /* ----------------------------------------------------------------- */ /* protos */ int process_args (int argc, char * argv[], opts_t * opts); int process (opts_t * opts); int show_help (void); /* ----------------------------------------------------------------- */ int main(int argc, char * argv[]) { int rv; memset(&gopt, 0, sizeof(gopt)); gopt.xverb = 1; rv = process_args(argc, argv, &gopt); if( rv < 0 ) return 1; /* error */ if( rv > 0 ) return 0; /* non-error termination */ /* rv == 0, continue... */ return process(&gopt); } /* ----------------------------------------------------------------- */ int process_args(int argc, char * argv[], opts_t * opts) { int ac; if( argc < 2 ) return show_help(); /* typing '-help' is sooo much work */ /* process user options: 4 are valid presently */ for( ac = 1; ac < argc; ac++ ) { if( ! strncmp(argv[ac], "-h", 2) ) { return show_help(); } else if( ! strcmp(argv[ac], "-disp_xml") ) { opts->disp_xlist = 1; } else if( ! strcmp(argv[ac], "-input") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -input\n"); return 1; } opts->fin = argv[ac]; /* no string copy, just pointer assignment */ } else if( ! strcmp(argv[ac], "-output") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -output\n"); return 2; } opts->fout = argv[ac]; } else if( ! strcmp(argv[ac], "-verb") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -verb\n"); return 2; } opts->verb = atoi(argv[ac]); } else if( ! strcmp(argv[ac], "-verb_lib") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -verb_lib\n"); return 2; } opts->xverb = atoi(argv[ac]); axml_set_verb(opts->xverb); } else { fprintf(stderr,"** invalid option, '%s'\n", argv[ac]); return 1; } } return 0; } /* ----------------------------------------------------------------- */ int process(opts_t * opts) { afni_xml_list xlist; if( !opts->fin ){ fprintf(stderr, "** missing option '-input'\n"); return 1;} /* read input dataset, including data */ xlist = axml_read_file(opts->fin, 1); if( ! xlist.len || ! xlist.xlist ) { fprintf(stderr,"** failed to read XML data from '%s'\n", opts->fin); return 1; } /* maybe display the results */ if( opts->disp_xlist ) axml_disp_xlist(NULL, &xlist, opts->verb); else if ( opts->verb > 1 ) printf("xlist read, nothing to do (but free it)\n"); /* free everything when we are done */ axml_free_xlist(&xlist); return 0; } int show_help( void ) { printf( "ct : short exmample of reading/writing XML files via afni_xml\n" "\n" " basic usage: \n" "\n" " options:\n" "\n" " -help : show this help\n" " -input INFILE : specify input dataset\n" " -verb LEVEL : set the verbose level to LEVEL\n" " -verb_lib LEVEL : set the library verbose level to LEVEL\n" "\n"); return 1; } nifti_clib-3.0.1/cifti/cifti_tool.c000066400000000000000000000354331371325713600172320ustar00rootroot00000000000000/* ---------------------------------------------------------------------- * A basic example to read/write a cifti dataset (e.g. cp command). * * compile example (consider -pedantic or -Wall): * * gcc -o clib_02_nifti2 clib_02.nifti2.c \ * -I../include -L../lib -lniftiio -lznz -lz -lm * * OR * * gcc -o clib_02_nifti2 clib_02.nifti2.c -I ../niftilib \ * -I ../znzlib ../niftilib/nifti2_io.o ../znzlib/znzlib.o -lz -lm * * R Reynolds 19 Jun 2015 *---------------------------------------------------------------------- */ #include #include #define USE_NIFTI2 #include #include "afni_xml_io.h" static const char * g_history[] = { "----------------------------------------------------------------------\n" "cifti_tool modification history:\n", "0.0 16 Jun 2015 [rickr]\n" " (Rick Reynolds of the National Institutes of Health, SSCC/DIRP/NIMH)\n" " - initial version\n" "0.1 8 Jul 2015 [rickr]\n" " - recur and up through axio_read_cifti_file\n" "0.2 17 Aug 2015 [rickr]\n" " - new eval_type: 'show_summary'\n" "0.3 21 Aug 2015 [rickr]\n" " - add more help and -hist\n" "----------------------------------------------------------------------\n" }; static char g_version[] = "cifti_tool version 0.3, 21 August, 2015"; /* ----------------------------------------------------------------- */ /* define and declare main option struct */ typedef struct { char * fin; char * fout; char * eval_type; int verb; int vread; int as_cext; int eval_cext; int disp_cext; } opts_t; opts_t gopt; /* ----------------------------------------------------------------- */ /* protos */ /* processing */ int disp_cifti_extension(nifti_image * nim, opts_t * opts); int disp_hex_data (const char *mesg, const void *data, int len, FILE *fp); int eval_cifti_extension(afni_xml_t * ax, opts_t * opts); int show_cifti_summary (FILE * fp, afni_xml_t * ax, int verb); /* main */ int process_args (int argc, char * argv[], opts_t * opts); int process (opts_t * opts); int show_help (void); int show_hist (void); int write_extension (FILE * fp, nifti1_extension * ext, int maxlen); /* recur */ int ax_has_data (FILE * fp, afni_xml_t * ax, int depth); int ax_has_bdata (FILE * fp, afni_xml_t * ax, int depth); int ax_num_tokens (FILE * fp, afni_xml_t * ax, int depth); int ax_show_text_data (FILE * fp, afni_xml_t * ax, int depth); int ax_show_names (FILE * fp, afni_xml_t * ax, int depth); /* stream */ int close_stream (FILE * fp); FILE * open_write_stream (char * fname); /* ----------------------------------------------------------------- */ int main(int argc, char * argv[]) { int rv; memset(&gopt, 0, sizeof(gopt)); gopt.verb = 1; gopt.vread = 1; rv = process_args(argc, argv, &gopt); if( rv < 0 ) return 1; /* error */ if( rv > 0 ) return 0; /* non-error termination */ /* rv == 0, continue... */ return process(&gopt); } /* ----------------------------------------------------------------- */ int process_args(int argc, char * argv[], opts_t * opts) { int ac; if( argc < 2 ) return show_help(); /* typing '-help' is sooo much work */ /* process user options */ for( ac = 1; ac < argc; ac++ ) { if( ! strcmp(argv[ac], "-h") || ! strcmp(argv[ac], "-help") ) { return show_help(); } else if( ! strcmp(argv[ac], "-hist") ){ show_hist(); return 1; } else if( ! strcmp(argv[ac], "-as_cext") || ! strcmp(argv[ac], "-as_cifti_ext") ) { opts->as_cext = 1; } else if( ! strcmp(argv[ac], "-disp_cext") ) { opts->disp_cext = 1; } else if( ! strcmp(argv[ac], "-eval_cext") ) { opts->eval_cext = 1; } else if( ! strcmp(argv[ac], "-eval_type") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -eval_type\n"); return -1; } opts->eval_type = argv[ac]; } else if( ! strcmp(argv[ac], "-input") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -input\n"); return -1; } opts->fin = argv[ac]; /* no string copy, just pointer assignment */ } else if( ! strcmp(argv[ac], "-output") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -output\n"); return -1; } opts->fout = argv[ac]; } else if( ! strcmp(argv[ac], "-verb") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -verb\n"); return -1; } opts->verb = atoi(argv[ac]); } else if( ! strcmp(argv[ac], "-verb_read") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -verb\n"); return -1; } opts->vread = atoi(argv[ac]); } else if( ! strcmp(argv[ac], "-vboth") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -verb\n"); return -1; } opts->verb = atoi(argv[ac]); opts->vread = atoi(argv[ac]); } else if( ! strcmp(argv[ac], "-ver") ) { puts(g_version); return 1; } else { fprintf(stderr,"** invalid option, '%s'\n", argv[ac]); return -1; } } return 0; } /* ----------------------------------------------------------------- */ int process(opts_t * opts) { nifti_image * nim = NULL; afni_xml_t * ax; if( !opts->fin ){ fprintf(stderr, "** missing option '-input'\n"); return 1;} axml_set_verb(opts->vread); nifti_set_debug_level(opts->vread); /* get xml pointer from file or extension */ if( opts->as_cext ) ax = axio_read_file(opts->fin); else axio_read_cifti_file(opts->fin, 0, &nim, &ax); if( ! ax ) { fprintf(stderr,"** failed to read CIFTI ext from %s\n", opts->fin); return 1; } if( opts->disp_cext ) disp_cifti_extension(nim, opts); if( opts->eval_cext ) eval_cifti_extension(ax, opts); return 0; } int disp_cifti_extension(nifti_image * nim, opts_t * opts) { nifti1_extension * ext; FILE * fp; int ind; if(gopt.verb > 1) fprintf(stderr,"-- displaying CIFTI extension to %s\n", opts->fout ? opts->fout : "DEFAULT" ); if( !nim ) return 1; ext = nim->ext_list; for( ind = 0; ind < nim->num_ext; ind++ ) if( ext->ecode == NIFTI_ECODE_CIFTI ) break; fp = open_write_stream(opts->fout); if( ext && ext->ecode != NIFTI_ECODE_CIFTI ) { fprintf(fp, "** no CIFTI extension in %s\n",nim->fname?nim->fname:"NULL"); return 1; } if(ext) { fprintf(fp, "%.*s\n", ext->esize-8, ext->edata); } /* possibly close file */ close_stream(fp); return 0; } int eval_cifti_extension(afni_xml_t * ax, opts_t * opts) { FILE * fp; if(gopt.verb > 1) fprintf(stderr,"-- evaluating CIFTI extension to %s\n", opts->fout ? opts->fout : "DEFAULT" ); fp = open_write_stream(opts->fout); axml_set_wstream(fp); if( opts->verb > 1 ) fprintf(stderr, "-- recursive eval from %s\n", opts->eval_type ? opts->eval_type : "NULL"); axml_set_verb(opts->verb); if( axio_text_to_binary(ax) ) fprintf(stderr,"** errors converting text to data\n"); if( ! opts->eval_type ) axml_recur(ax_show_names, ax); else if( ! strcmp(opts->eval_type, "has_data" ) ) axml_recur(ax_has_data, ax); else if( ! strcmp(opts->eval_type, "has_bdata" ) ) axml_recur(ax_has_bdata, ax); else if( ! strcmp(opts->eval_type, "num_tokens" ) ) axml_recur(ax_num_tokens, ax); else if( ! strcmp(opts->eval_type, "show" ) ) axml_disp_xml_t("CIFTI extension ", ax, 0, opts->verb); else if( ! strcmp(opts->eval_type, "show_summary" ) ) show_cifti_summary(fp, ax, opts->verb); else if( ! strcmp(opts->eval_type, "show_text_data" ) ) axml_recur(ax_show_text_data, ax); else /* show_names is default */ axml_recur(ax_show_names, ax); /* possibly close file */ close_stream(fp); return 0; } /* look for stdin/stdout */ FILE * open_write_stream(char * fname) { FILE * fp = NULL; if ( ! fname ) fp = stdout; else if ( ! strcmp(fname, "stdout") ) fp = stdout; else if ( ! strcmp(fname, "-") ) fp = stdout; else if ( ! strcmp(fname, "stderr") ) fp = stderr; else { fp = fopen(fname, "w"); if( !fp ) fprintf(stderr,"** failed to open '%s' for writing\n", fname); } return fp; } /* look for stdin/stdout (do not close them) */ int close_stream(FILE * fp) { if( !fp ) return 1; if( fp == stdin || fp == stdout || fp == stderr ) return 0; fclose(fp); return 0; } int show_cifti_summary(FILE * fp, afni_xml_t * ax, int verb) { if( !ax || !fp ) return 1; return axio_show_mim_summary(fp, "CIFTI extension summary\n", ax, verb); } int ax_has_data(FILE * fp, afni_xml_t * ax, int depth) { if( !ax ) return 1; /* if no data (xtext or bdata), blow out of here */ if( !ax->xtext && ax->xlen <= 0 && !ax->bdata && ax->blen <= 0 ) return 0; if( gopt.verb > 2 ) { fprintf(fp,"%*sdata in depth %d %s : ", depth*3, "", depth, ax->name); fprintf(fp,"xtext[%d], bdata[%" PRId64 "]\n", ax->xlen, ax->blen); } else if( gopt.verb > 1 ) fprintf(fp,"%*sdata in depth %d %s\n", depth*3, "", depth, ax->name); else fprintf(fp,"%s\n", ax->name); return 0; } int ax_has_bdata(FILE * fp, afni_xml_t * ax, int depth) { if( !ax ) return 1; /* if no bdata blow out of here */ if( ! ax->bdata && ax->blen <= 0 ) return 0; if( gopt.verb > 1 ) fprintf(fp,"%*sdata in depth %d ", depth*3, "", depth); fprintf(fp, "%s : bdata[%" PRId64 "]", ax->name, ax->blen); if( gopt.verb > 2 && ax->blen > 1 ) { if( ax->btype == NIFTI_TYPE_FLOAT64 ) { double * dp = (double *)ax->bdata; if(dp) { /* repetetive checks to appease compilers */ fprintf(fp, " = %lf %lf ...\n", dp[0], dp[1]); } } else if( ax->btype == NIFTI_TYPE_INT64 ) { int64_t * dp = (int64_t *)ax->bdata; if(dp) { fprintf(fp, " = %" PRId64 " %" PRId64 " ...\n", dp[0], dp[1]); } } } else fputc('\n', fp); return 0; } int ax_num_tokens(FILE * fp, afni_xml_t * ax, int depth) { int64_t nt; if( !ax ) return 1; /* if no data, blow out of here */ if( gopt.verb < 3 ) { if( !ax->xtext || ax->xlen <= 0 ) return 0; } nt = axio_num_tokens(ax->xtext, ax->xlen); if( gopt.verb > 1 ) fprintf(fp,"%*stokens in depth %d %s: %" PRId64 "\n", depth*3, "", depth, ax->name, nt); else fprintf(fp,"%s %" PRId64 "\n", ax->name, nt); return 0; } int ax_show_text_data(FILE * fp, afni_xml_t * ax, int depth) { int len; if( !ax ) return 1; /* if no data, blow out of here */ if( !ax->xtext || ax->xlen <= 0 ) return 0; if( gopt.verb > 1 ) fprintf(fp,"%*sdata in depth %d %s : ", depth*3, "", depth, ax->name); else fprintf(fp,"%s : ", ax->name); /* first choose max length to display */ if( gopt.verb > 2 ) len = 128; else if ( gopt.verb > 1 ) len = 64; else len = 32; /* restrict to actual length */ if( len > ax->xlen ) len = ax->xlen; /* display */ fprintf(fp, "%.*s\n", len, ax->xtext); return 0; } int ax_show_names(FILE * fp, afni_xml_t * ax, int depth) { if( !ax ) return 1; if( gopt.verb > 1 ) fprintf(fp,"%*s%s\n", depth*3, "", ax->name); else fprintf(fp,"%s\n", ax->name); return 0; } /*---------------------------------------------------------------------- *! display data in hexidecimal, on one line * * if mesg is set, print the message first * if fp is not set, print to stdout *//*-------------------------------------------------------------------*/ int disp_hex_data(const char *mesg, const void *data, int len, FILE *fp) { const char * dp = (const char *)data; FILE * stream; int c; stream = fp ? fp : stdout; if( !data || len < 1 ) return -1; if( mesg ) fputs(mesg, stream); for( c = 0; c < len; c++ ) fprintf(stream, " %02x", dp[c]); return 0; } int show_hist( void ) { int c, len = sizeof(g_history)/sizeof(char *); for( c = 0; c < len; c++) fputs(g_history[c], stdout); putchar('\n'); return 0; } int show_help( void ) { printf( "ct : short example of reading/writing CIFTI-2 datasets\n" "\n" " This program is to demonstrate how to read a CIFTI-2 dataset.\n" "\n" " basic usage: cifti_tool -input FILE [other options]\n" "\n" " examples:\n" "\n" " cifti_tool -input FILE -disp_cext\n" " cifti_tool -input FILE -disp_cext -as_cext\n" " cifti_tool -input FILE -disp_cext -output cifti.txt\n" "\n" " cifti_tool -input FILE -eval_cext\n" " cifti_tool -input FILE -eval_cext -verb 2\n" " cifti_tool -input FILE -eval_cext -eval_type show_summary\n" "\n" " cifti_tool -input FILE -eval_cext -eval_type show_name\n" " cifti_tool -input FILE -eval_cext -eval_type has_data\n" " cifti_tool -input FILE -eval_cext -eval_type show_text_data\n" "\n" " get a list of unique element types with attached data\n" "\n" " cifti_tool -input FILE -eval_cext -eval_type has_data \\\n" " | sort | uniq\n" "\n" " options:\n" "\n" " -help : show this help\n" "\n" " -input INFILE : specify input dataset\n" " -output OUTFILE : where to write output\n" "\n" " -as_cext : process the input as just an extension\n" " -disp_cext : display the CIFTI extension\n" " -eval_cext : evaluate the CIFTI extension\n" " -eval_type ETYPE : method for evaluation of axml elements\n" "\n" " valid ETYPES:\n" " has_data - show elements with attached text data\n" " has_bdata - show elements with attached binary data\n" " num_tokens - show the number of tokens in such text\n" " show - like -disp_cext\n" " show_names - show element names, maybe depth indented\n" " show_summary - summarize contents of dataset\n" " show_text_data - show the actual text data\n" "\n" " -verb LEVEL : set the verbose level to LEVEL\n" " -verb_read LEVEL : set verbose level when reading\n" " -vboth LEVEL : apply both -verb options\n" "\n"); return 1; } nifti_clib-3.0.1/cmake/000077500000000000000000000000001371325713600147055ustar00rootroot00000000000000nifti_clib-3.0.1/cmake/NIFTICPackConfig.cmake000066400000000000000000000041651371325713600206160ustar00rootroot00000000000000#################################### ### Define information necessary for packaging with CPACK (https://gitlab.kitware.com/cmake/community/wikis/home#cpack) ### The last section is concerned with installing the binaries and making distributions. set_if_not_defined(CPACK_SOURCE_GENERATOR "TGZ;TZ;STGZ;TBZ2;ZIP") include(InstallRequiredSystemLibraries) set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${NIFTI_PROJECT_DESCRIPTION}") set(CPACK_PACKAGE_VENDOR "NIFTI DFWG") set(CPACK_PACKAGE_DESCRIPTION_FILE "${NIFTI_SOURCE_DIR}/README.md") set(CPACK_RESOURCE_FILE_LICENSE "${NIFTI_SOURCE_DIR}/README.md") set(CPACK_PACKAGE_NAME "${PROJECT_NAME}") set(CPACK_PACKAGE_VERSION_MAJOR "${NIFTI_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${NIFTI_VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${NIFTI_VERSION_PATCH}") set(CPACK_PACKAGE_INSTALL_DIRECTORY "NIFTI_${NIFTI_VERSION_MAJOR}.${NIFTI_VERSION_MINOR}.${NIFTI_VERSION_PATCH}") if(WIN32 AND NOT UNIX) set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") # There is a bug in NSI that does not handle full unix paths properly. Make # sure there is at least one set of four (4) backlasshes. set(CPACK_PACKAGE_ICON "${CMake_SOURCE_DIR}/Utilities/Release\\\\InstallIcon.bmp") set(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\MyExecutable.exe") set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} NIFTI Project") set(CPACK_NSIS_HELP_LINK "https:\\\\\\\\www.nitrc.org") set(CPACK_NSIS_URL_INFO_ABOUT "https:\\\\\\\\www.nitrc.org") set(CPACK_NSIS_CONTACT "xyz@domain.edu") set(CPACK_NSIS_MODIFY_PATH ON) else() set(CPACK_STRIP_FILES OFF) set(CPACK_SOURCE_STRIP_FILES OFF) endif() set(CPACK_PACKAGE_EXECUTABLES "nifti_tool;NIFTI") set(CPACK_PACKAGING_INSTALL_PREFIX ".") set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-dev") set(CPACK_PACKAGE_DEFAULT_LOCATION "/opt/${CPACK_PACKAGE_NAME}") set(CPACK_SET_DESTDIR ON) set(CPACK_SOURCE_IGNORE_FILES "/.git/" ".gitignore$" ".*.swp$" ".*~" "Makefile\\\\.in$" ) include(CPack) nifti_clib-3.0.1/cmake/NIFTIConfig.cmake000066400000000000000000000000701371325713600177030ustar00rootroot00000000000000include("${CMAKE_CURRENT_LIST_DIR}/NIFTITargets.cmake") nifti_clib-3.0.1/cmake/cmake_uninstall.cmake.in000066400000000000000000000020511371325713600214630ustar00rootroot00000000000000if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message( FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" ) endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") exec_program( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif(NOT "${rm_retval}" STREQUAL 0) else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") endforeach(file) nifti_clib-3.0.1/cmake/local_dashboard.cmake000066400000000000000000000075721371325713600210230ustar00rootroot00000000000000## ## Intended to be run from a local build with set(DUMMY_VARIABLE_FOR_EASY_COMMANDLINE_PARSING """ export AGENT_BUILDDIRECTORY=/tmp/NIFTIworkspace export BUILD_SOURCESDIRECTORY=${AGENT_BUILDDIRECTORY}/nifti_clib export BUILD_SOURCEBRANCHNAME=master export CTEST_SCRIPT_DIRECTORY=$(pwd) ctest -S ${CTEST_SCRIPT_DIRECTORY}/local_dashboard.cmake -V -j 4 """ ) ## # set_from_env # ------------ # # Sets a CMake variable from an environment variable. If the # environment variable is not defined then the CMake variable is not # modified. If DEFAULT is specified then if the environment variable # is not defined the default value is used. Alternatively, if REQUIRED # is specified then a FATAL_ERROR is generated. # # set_from_env( [REQUIRED|DEFAULT value] ) function(set_from_env var env_var) if(NOT DEFINED ENV{${env_var}}) if (ARGV2 STREQUAL "REQUIRED") message(FATAL_ERROR "Required environment variable \"${env_var}\" not defined.") elseif (ARGV2 STREQUAL "DEFAULT") set(${var} ${ARGV3} PARENT_SCOPE) endif() else() set(${var} $ENV{${env_var}} PARENT_SCOPE) endif() endfunction() #set_from_env(CTEST_SITE "TRAVIS_APP_HOST" REQUIRED) cmake_host_system_information(RESULT CTEST_SITE QUERY HOSTNAME) set(CTEST_SITE "travis.${CTEST_SITE}") set(CTEST_UPDATE_VERSION_ONLY 1) set_from_env(PARALLEL_LEVEL "PARALLEL_LEVEL" DEFAULT 8) set(CTEST_TEST_ARGS ${CTEST_TEST_ARGS} PARALLEL_LEVEL ${PARALLEL_LEVEL}) # The absolute path to the directory where the repository being built has been copied on the worker. set_from_env(workspace "AGENT_BUILDDIRECTORY" REQUIRED) file(TO_CMAKE_PATH "${workspace}" CTEST_DASHBOARD_ROOT) file(RELATIVE_PATH dashboard_source_name "${workspace}" "$ENV{BUILD_SOURCESDIRECTORY}") # Make environment variables to CMake variables for CTest #set_from_env(CTEST_CMAKE_GENERATOR "CTEST_CMAKE_GENERATOR" DEFAULT "Ninja") set_from_env(CTEST_CMAKE_GENERATOR "CTEST_CMAKE_GENERATOR" DEFAULT "Unix Makefiles") set_from_env(CTEST_BUILD_CONFIGURATION "CTEST_BUILD_CONFIGURATION" DEFAULT "Debug") set_from_env(BUILD_SHARED_LIBS "BUILD_SHARED_LIBS" DEFAULT "ON") set_from_env(BUILD_EXAMPLES "BUILD_EXAMPLES" DEFAULT "ON") set_from_env(INTERPROCEDURAL_OPTIMIZATION "INTERPROCEDURAL_OPTIMIZATION" DEFAULT "ON") if(NOT CTEST_BUILD_NAME) if(DEFINED ENV{SYSTEM_PULLREQUEST_SOURCEBRANCH}) set(branch "-$ENV{SYSTEM_PULLREQUEST_SOURCEBRANCH}") set(dashboard_git_branch "$ENV{SYSTEM_PULLREQUEST_SOURCEBRANCH}") set(dashboard_model "Experimental") elseif(ENV{BUILD_SOURCEBRANCHNAME} STREQUAL "master") set(branch "-master") set(dashboard_git_branch "$ENV{BUILD_SOURCEBRANCHNAME}") set(dashboard_model "Continuous") elseif(ENV{BUILD_SOURCEBRANCHNAME} STREQUAL "nightly-master") set(branch "-nightly-master") set(dashboard_git_branch "$ENV{BUILD_SOURCEBRANCHNAME}") set(dashboard_model "Nightly") else() set(branch "-$ENV{BUILD_SOURCEBRANCHNAME}") set(dashboard_git_branch "$ENV{BUILD_SOURCEBRANCHNAME}") set(dashboard_model "Experimental") endif() if(DEFINED ENV{SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}) set(pr "-PR$ENV{SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}") else() set(pr "") endif() set(CTEST_BUILD_NAME "$ENV{TRAVIS_OS_NAME}-$ENV{BUILD_BUILDID}${pr}${branch}") endif() set(dashboard_cache " CMAKE_BUILD_TYPE:STRING=None BUILD_TESTING:BOOL=ON BUILD_EXAMPLES:BOOL=${BUILD_EXAMPLES} BUILD_SHARED_LIBS:BOOL=${BUILD_SHARED_LIBS} CMAKE_INTERPROCEDURAL_OPTIMIZATION:BOOL=${INTERPROCEDURAL_OPTIMIZATION} NIFTI_BUILD_APPLICATIONS:BOOL=ON USE_FSL_CODE:BOOL=ON USE_CIFTI_CODE:BOOL=ON USE_NIFTI2_CODE:BOOL=ON " ) # Eventually USE_NIFTI1_CODE:BOOL=ON must be added. string(TIMESTAMP build_date "%Y-%m-%d") message("CDash Build Identifier: ${build_date} ${CTEST_BUILD_NAME}") message("CTEST_SITE = ${CTEST_SITE}") include("${CTEST_SCRIPT_DIRECTORY}/nifti_common.cmake") nifti_clib-3.0.1/cmake/nifti_common.cmake000066400000000000000000000372101371325713600203730ustar00rootroot00000000000000# NIFTI Common Dashboard Script # # This script contains basic dashboard driver code common to all # clients. # # Put this script in a directory such as "~/Dashboards/Scripts" or # "c:/Dashboards/Scripts". Create a file next to this script, say # 'my_dashboard.cmake', with code of the following form: # # # Client maintainer: me@mydomain.net # set(CTEST_SITE "machine.site") # set(CTEST_BUILD_NAME "Platform-Compiler") # set(CTEST_BUILD_CONFIGURATION Debug) # set(CTEST_CMAKE_GENERATOR "Unix Makefiles") # include(${CTEST_SCRIPT_DIRECTORY}/itk_common.cmake) # # Then run a scheduled task (cron job) with a command line such as # # ctest -S ~/Dashboards/Scripts/my_dashboard.cmake -V # # By default the source and build trees will be placed in the path # "../MyTests/" relative to your script location. # # The following variables may be set before including this script # to configure it: # # dashboard_model = Nightly | Experimental | Continuous # dashboard_track = Optional track to submit dashboard to # dashboard_loop = Repeat until N seconds have elapsed # dashboard_root_name = Change name of "MyTests" directory # dashboard_source_name = Name of source directory (NIFTI) # dashboard_binary_name = Name of binary directory (NIFTI-build) # dashboard_data_name = Name of ExternalData store (ExternalData) # dashboard_cache = Initial CMakeCache.txt file content # dashboard_do_cache = Always write CMakeCache.txt # dashboard_do_coverage = True to enable coverage (ex: gcov) # dashboard_do_memcheck = True to enable memcheck (ex: valgrind) # dashboard_no_clean = True to skip build tree wipeout # dashboard_no_update = True to skip source tree update # CTEST_UPDATE_COMMAND = path to git command-line client # CTEST_BUILD_FLAGS = build tool arguments (ex: -j2) # CTEST_BUILD_TARGET = A specific target to be built (instead of all) # CTEST_DASHBOARD_ROOT = Where to put source and build trees # CTEST_TEST_CTEST = Whether to run long CTestTest* tests # CTEST_TEST_TIMEOUT = Per-test timeout length # CTEST_COVERAGE_ARGS = ctest_coverage command args # CTEST_TEST_ARGS = ctest_test args (ex: PARALLEL_LEVEL 4) # CTEST_MEMCHECK_ARGS = ctest_memcheck args (defaults to CTEST_TEST_ARGS) # CMAKE_MAKE_PROGRAM = Path to "make" tool to use # # Options to configure builds from experimental git repository: # dashboard_git_url = Custom git clone url # dashboard_git_branch = Custom remote branch to track # dashboard_git_crlf = Value of core.autocrlf for repository # # The following macros will be invoked before the corresponding # step if they are defined: # # dashboard_hook_init = End of initialization, before loop # dashboard_hook_start = Start of loop body, before ctest_start # dashboard_hook_started = After ctest_start # dashboard_hook_build = Before ctest_build # dashboard_hook_test = Before ctest_test # dashboard_hook_coverage = Before ctest_coverage # dashboard_hook_memcheck = Before ctest_memcheck # dashboard_hook_submit = Before ctest_submit # dashboard_hook_end = End of loop body, after ctest_submit # # For Makefile generators the script may be executed from an # environment already configured to use the desired compilers. # Alternatively the environment may be set at the top of the script: # # set(ENV{CC} /path/to/cc) # C compiler # set(ENV{CXX} /path/to/cxx) # C++ compiler # set(ENV{FC} /path/to/fc) # Fortran compiler (optional) # set(ENV{LD_LIBRARY_PATH} /path/to/vendor/lib) # (if necessary) #========================================================================== # # Copyright Insight Software Consortium # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0.txt # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #==========================================================================*/ cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) set(dashboard_user_home "$ENV{HOME}") get_filename_component(dashboard_self_dir ${CMAKE_CURRENT_LIST_FILE} PATH) # Select the top dashboard directory. if(NOT DEFINED dashboard_root_name) set(dashboard_root_name "MyTests") endif() if(NOT DEFINED CTEST_DASHBOARD_ROOT) get_filename_component(CTEST_DASHBOARD_ROOT "${CTEST_SCRIPT_DIRECTORY}/../${dashboard_root_name}" ABSOLUTE) endif() # Select the model (Nightly, Experimental, Continuous). if(NOT DEFINED dashboard_model) set(dashboard_model Nightly) endif() if(NOT "${dashboard_model}" MATCHES "^(Nightly|Experimental|Continuous)$") message(FATAL_ERROR "dashboard_model must be Nightly, Experimental, or Continuous") endif() # Default to a Debug build. if(NOT DEFINED CTEST_CONFIGURATION_TYPE AND DEFINED CTEST_BUILD_CONFIGURATION) set(CTEST_CONFIGURATION_TYPE ${CTEST_BUILD_CONFIGURATION}) endif() if(NOT DEFINED CTEST_CONFIGURATION_TYPE) set(CTEST_CONFIGURATION_TYPE Debug) endif() # Choose CTest reporting mode. if(NOT DEFINED CTEST_USE_LAUNCHERS) if(NOT "${CTEST_CMAKE_GENERATOR}" MATCHES "Make") # Launchers work only with Makefile generators. set(CTEST_USE_LAUNCHERS 0) elseif(NOT DEFINED CTEST_USE_LAUNCHERS) # The setting is ignored by CTest < 2.8 so we need no version test. set(CTEST_USE_LAUNCHERS 1) endif() endif() # Configure testing. if(NOT DEFINED CTEST_TEST_CTEST) set(CTEST_TEST_CTEST 1) endif() if(NOT CTEST_TEST_TIMEOUT) set(CTEST_TEST_TIMEOUT 1500) endif() # Select Git source to use. if(NOT DEFINED dashboard_git_url) set(dashboard_git_url "https://github.com/NIFTI-Imaging/nifti_clib.git") endif() if(NOT DEFINED dashboard_git_branch) if("${dashboard_model}" STREQUAL "Nightly") set(dashboard_git_branch nightly-master) else() set(dashboard_git_branch master) endif() endif() if(NOT DEFINED dashboard_git_crlf) if(UNIX) set(dashboard_git_crlf false) else(UNIX) set(dashboard_git_crlf true) endif(UNIX) endif() # Look for a GIT command-line client. if(NOT DEFINED CTEST_GIT_COMMAND) find_program(CTEST_GIT_COMMAND NAMES git git.cmd) endif() if(NOT DEFINED CTEST_GIT_COMMAND) message(FATAL_ERROR "No Git Found.") endif() # Explicitly specify the remote as "origin". This ensure we are pulling from # the correct remote and prevents command failures when the git tracking # branch has not been configured. set(CTEST_GIT_UPDATE_CUSTOM "${CTEST_GIT_COMMAND}" pull origin ${dashboard_git_branch}) # Select a source directory name. if(NOT DEFINED CTEST_SOURCE_DIRECTORY) if(DEFINED dashboard_source_name) set(CTEST_SOURCE_DIRECTORY ${CTEST_DASHBOARD_ROOT}/${dashboard_source_name}) else() set(CTEST_SOURCE_DIRECTORY ${CTEST_DASHBOARD_ROOT}/nifti_clib) endif() endif() # Select a build directory name. if(NOT DEFINED CTEST_BINARY_DIRECTORY) if(DEFINED dashboard_binary_name) set(CTEST_BINARY_DIRECTORY ${CTEST_DASHBOARD_ROOT}/${dashboard_binary_name}) else() set(CTEST_BINARY_DIRECTORY ${CTEST_SOURCE_DIRECTORY}-build) endif() endif() # Select a data store. if(NOT DEFINED ExternalData_OBJECT_STORES) if(DEFINED "ENV{ExternalData_OBJECT_STORES}") file(TO_CMAKE_PATH "$ENV{ExternalData_OBJECT_STORES}" ExternalData_OBJECT_STORES) else() if(DEFINED dashboard_data_name) set(ExternalData_OBJECT_STORES ${CTEST_DASHBOARD_ROOT}/${dashboard_data_name}) else() set(ExternalData_OBJECT_STORES ${CTEST_DASHBOARD_ROOT}/ExternalData) endif() endif() endif() if(NOT DEFINED CTEST_MEMCHECK_ARGS) set(CTEST_MEMCHECK_ARGS ${CTEST_TEST_ARGS}) endif() # Delete source tree if it is incompatible with current VCS. if(EXISTS ${CTEST_SOURCE_DIRECTORY}) if(NOT EXISTS "${CTEST_SOURCE_DIRECTORY}/.git") set(vcs_refresh "because it is not managed by git.") endif() if(vcs_refresh AND "${CTEST_SOURCE_DIRECTORY}" MATCHES "/(NIFTI|nifti_clib)[^/]*") message("Deleting source tree\n ${CTEST_SOURCE_DIRECTORY}\n${vcs_refresh}") file(REMOVE_RECURSE "${CTEST_SOURCE_DIRECTORY}") endif() endif() # Support initial checkout if necessary. if(NOT EXISTS "${CTEST_SOURCE_DIRECTORY}" )# AND NOT DEFINED CTEST_CHECKOUT_COMMAND) get_filename_component(_name "${CTEST_SOURCE_DIRECTORY}" NAME) execute_process(COMMAND ${CTEST_GIT_COMMAND} --version OUTPUT_VARIABLE output) string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+(\\.[0-9]+(\\.g[0-9a-f]+)?)?" GIT_VERSION "${output}") if(NOT "${GIT_VERSION}" VERSION_LESS "1.6.5") # Have "git clone -b " option. set(git_branch_new "-b ${dashboard_git_branch}") set(git_branch_old) else() # No "git clone -b " option. set(git_branch_new) set(git_branch_old "-b ${dashboard_git_branch} origin/${dashboard_git_branch}") endif() # Generate an initial checkout script. set(ctest_checkout_script ${CTEST_DASHBOARD_ROOT}/${_name}-init.cmake) file(WRITE ${ctest_checkout_script} "# git repo init script for ${_name} execute_process( COMMAND \"${CTEST_GIT_COMMAND}\" clone -n ${git_branch_new} -- \"${dashboard_git_url}\" \"${CTEST_SOURCE_DIRECTORY}\" ) if(EXISTS \"${CTEST_SOURCE_DIRECTORY}/.git\") execute_process( COMMAND \"${CTEST_GIT_COMMAND}\" config core.autocrlf ${dashboard_git_crlf} WORKING_DIRECTORY \"${CTEST_SOURCE_DIRECTORY}\" ) execute_process( COMMAND \"${CTEST_GIT_COMMAND}\" checkout ${git_branch_old} WORKING_DIRECTORY \"${CTEST_SOURCE_DIRECTORY}\" ) execute_process( COMMAND \"${CTEST_GIT_COMMAND}\" submodule init WORKING_DIRECTORY \"${CTEST_SOURCE_DIRECTORY}\" ) execute_process( COMMAND \"${CTEST_GIT_COMMAND}\" submodule update -- WORKING_DIRECTORY \"${CTEST_SOURCE_DIRECTORY}\" ) endif() ") set(CTEST_CHECKOUT_COMMAND "\"${CMAKE_COMMAND}\" -P \"${ctest_checkout_script}\"") # CTest delayed initialization is broken, so we put the # CTestConfig.cmake info here. set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC") set(CTEST_DROP_METHOD "http") set(CTEST_DROP_SITE "my.cdash.org") set(CTEST_DROP_LOCATION "/submit.php?project=nifti_clib") set(CTEST_DROP_SITE_CDASH TRUE) endif() #----------------------------------------------------------------------------- # Send the main script as a note. list(APPEND CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}" "${CMAKE_CURRENT_LIST_FILE}" ) # Check for required variables. foreach(req CTEST_CMAKE_GENERATOR CTEST_SITE CTEST_BUILD_NAME ) if(NOT DEFINED ${req}) message(FATAL_ERROR "The containing script must set ${req}") endif() endforeach(req) # Print summary information. foreach(v CTEST_SITE CTEST_BUILD_NAME CTEST_SOURCE_DIRECTORY CTEST_BINARY_DIRECTORY ExternalData_OBJECT_STORES CTEST_CMAKE_GENERATOR CTEST_BUILD_CONFIGURATION CTEST_BUILD_FLAGS CTEST_GIT_COMMAND CTEST_CHECKOUT_COMMAND CTEST_SCRIPT_DIRECTORY CTEST_USE_LAUNCHERS CTEST_TEST_TIMEOUT CTEST_COVERAGE_ARGS CTEST_TEST_ARGS CTEST_MEMCHECK_ARGS ) set(vars "${vars} ${v}=[${${v}}]\n") endforeach(v) message("Dashboard script configuration:\n${vars}\n") # Avoid non-ascii characters in tool output. set(ENV{LC_ALL} C) # Helper macro to write the initial cache. macro(write_cache) set(cache_build_type "") set(cache_make_program "") if(CTEST_CMAKE_GENERATOR MATCHES "Make") set(cache_build_type CMAKE_BUILD_TYPE:STRING=${CTEST_BUILD_CONFIGURATION}) if(CMAKE_MAKE_PROGRAM) set(cache_make_program CMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}) endif() endif() file(WRITE ${CTEST_BINARY_DIRECTORY}/CMakeCache.txt " SITE:STRING=${CTEST_SITE} BUILDNAME:STRING=${CTEST_BUILD_NAME} CTEST_USE_LAUNCHERS:BOOL=${CTEST_USE_LAUNCHERS} DART_TESTING_TIMEOUT:STRING=${CTEST_TEST_TIMEOUT} ExternalData_OBJECT_STORES:STRING=${ExternalData_OBJECT_STORES} ${cache_build_type} ${cache_make_program} ${dashboard_cache} ") file(REMOVE_RECURSE "${CTEST_BINARY_DIRECTORY}/CMakeFiles") endmacro() # Start with a fresh build tree. if(NOT EXISTS "${CTEST_BINARY_DIRECTORY}") file(MAKE_DIRECTORY "${CTEST_BINARY_DIRECTORY}") elseif(NOT "${CTEST_SOURCE_DIRECTORY}" STREQUAL "${CTEST_BINARY_DIRECTORY}" AND NOT dashboard_no_clean) message("Clearing build tree...") ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY}) endif() set(dashboard_continuous 0) if("${dashboard_model}" STREQUAL "Continuous") set(dashboard_continuous 1) endif() if(NOT DEFINED dashboard_loop) if(dashboard_continuous) set(dashboard_loop 43200) else() set(dashboard_loop 0) endif() endif() # CTest 2.6 crashes with message() after ctest_test. macro(safe_message) if(safe_message_skip) message(STATUS ${ARGN}) endif() endmacro() if(COMMAND dashboard_hook_init) dashboard_hook_init() endif() set(dashboard_done 0) while(NOT dashboard_done) if(dashboard_loop) set(START_TIME ${CTEST_ELAPSED_TIME}) endif() set(ENV{HOME} "${dashboard_user_home}") # Start a new submission. if(COMMAND dashboard_hook_start) dashboard_hook_start() endif() if(dashboard_track) ctest_start(${dashboard_model} TRACK ${dashboard_track}) else() ctest_start(${dashboard_model}) endif() if(COMMAND dashboard_hook_started) dashboard_hook_started() endif() # Always build if the tree is fresh. set(dashboard_fresh 0) if(NOT EXISTS "${CTEST_BINARY_DIRECTORY}/CMakeCache.txt" OR "${dashboard_do_cache}") set(dashboard_fresh 1) safe_message("Writing initial dashboard cache...") write_cache() endif() # Look for updates. if(NOT dashboard_no_update) ctest_update(RETURN_VALUE count) endif() set(CTEST_CHECKOUT_COMMAND) # checkout on first iteration only safe_message("Found ${count} changed files") if(dashboard_fresh OR NOT dashboard_continuous OR count GREATER 0) ctest_configure(RETURN_VALUE configure_return) ctest_read_custom_files(${CTEST_BINARY_DIRECTORY}) if(COMMAND dashboard_hook_build) dashboard_hook_build() endif() ctest_build(RETURN_VALUE build_return NUMBER_ERRORS build_errors NUMBER_WARNINGS build_warnings) if(COMMAND dashboard_hook_test) dashboard_hook_test() endif() ctest_test(${CTEST_TEST_ARGS} RETURN_VALUE test_return) set(safe_message_skip 1) # Block furhter messages if(dashboard_do_coverage) if(COMMAND dashboard_hook_coverage) dashboard_hook_coverage() endif() ctest_coverage(${CTEST_COVERAGE_ARGS}) endif() if(dashboard_do_memcheck) if(COMMAND dashboard_hook_memcheck) dashboard_hook_memcheck() endif() ctest_memcheck(${CTEST_MEMCHECK_ARGS}) endif() if(COMMAND dashboard_hook_submit) dashboard_hook_submit() endif() if(NOT dashboard_no_submit) ctest_submit() endif() if(COMMAND dashboard_hook_end) dashboard_hook_end() endif() endif() if(dashboard_loop) # Delay until at least 5 minutes past START_TIME ctest_sleep(${START_TIME} 300 ${CTEST_ELAPSED_TIME}) if(${CTEST_ELAPSED_TIME} GREATER ${dashboard_loop}) set(dashboard_done 1) endif() else() # Not continuous, so we are done. set(dashboard_done 1) endif() endwhile() if(NOT ${configure_return} EQUAL 0 OR NOT ${build_return} EQUAL 0 OR NOT ${build_errors} EQUAL 0 OR NOT ${build_warnings} EQUAL 0 OR NOT ${test_return} EQUAL 0) message(FATAL_ERROR "Build did not complete without warnings, errors, or failures.") endif() nifti_clib-3.0.1/cmake/nifti_macros.cmake000066400000000000000000000144421371325713600203710ustar00rootroot00000000000000macro(set_if_not_defined var defaultvalue) # Macro allowing to set a variable to its default value if not already defined. # The default value is set with: # (1) if set, the value environment variable . # (2) if set, the value of local variable variable . # (3) if none of the above, the value passed as a parameter. # Setting the optional parameter 'OBFUSCATE' will display 'OBFUSCATED' instead of the real value. set(_obfuscate FALSE) foreach(arg ${ARGN}) if(arg STREQUAL "OBFUSCATE") set(_obfuscate TRUE) endif() endforeach() if(DEFINED ENV{${var}} AND NOT DEFINED ${var}) set(_value "$ENV{${var}}") if(_obfuscate) set(_value "OBFUSCATED") endif() message(STATUS "Setting '${var}' variable with environment variable value '${_value}'") set(${var} $ENV{${var}}) endif() if(NOT DEFINED ${var}) set(_value "${defaultvalue}") if(_obfuscate) set(_value "OBFUSCATED") endif() message(STATUS "Setting '${var}' variable with default value '${_value}'") set(${var} "${defaultvalue}") endif() endmacro() function(add_nifti_library target_in) add_library(${ARGV}) add_library(NIFTI::${target_in} ALIAS ${target_in}) get_property(tmp GLOBAL PROPERTY nifti_installed_targets) list(APPEND tmp "${target_in}") set_property(GLOBAL PROPERTY nifti_installed_targets "${tmp}") endfunction() function(add_nifti_executable target_in) add_executable(${ARGV}) get_property(tmp GLOBAL PROPERTY nifti_installed_targets) list(APPEND tmp "${target_in}") set_property(GLOBAL PROPERTY nifti_installed_targets "${tmp}") endfunction() function(install_man_page target) # uses help2man to generate manpages for an executable sections can be added # to the man page by populating the OPTIONS_FOR_SECTIONS argument. For # example setting this to "-see_also" will include the output of the # "executable -see_also" in a "see_also" section of the final manpage. # Additional arguments to the help2man call can be provided in the OPTS # argument set(MAN_DEPENDS "") set(INCLUDE_STRING "") if(NIFTI_INSTALL_NO_DOCS) return() endif() # Parse args cmake_parse_arguments(ARG "" "" "OPTIONS_FOR_SECTIONS;OPTS" ${ARGN} ) #message(FATAL_ERROR "${ARG_OPTS}:::::::: ${ARG_OPTIONS_FOR_SECTIONS}:::::: ${ARGN}") # generate additional sections for inclusion in manpage foreach(section ${ARG_OPTIONS_FOR_SECTIONS}) string(REGEX REPLACE "-" "" SECTION_NAME ${section}) set(SECTION_FILE ${MAN_DIR}/${SECTION_NAME}.h2m) add_custom_command( OUTPUT ${SECTION_FILE} COMMAND ${CMAKE_COMMAND} -E echo \"[ ${SECTION_NAME} ]\" > ${SECTION_FILE} COMMAND $ ${section} >> ${SECTION_FILE} USES_TERMINAL COMMENT Generating ${SECTION_NAME} for ${target} ) list(APPEND MAN_DEPENDS ${SECTION_FILE}) list(APPEND INCLUDE_STRING "--include=${SECTION_FILE} ") endforeach() # Generate the man-page set(MAN_PAGE ${MAN_DIR}/${target}_manpage.1) add_custom_command( OUTPUT ${MAN_PAGE} DEPENDS ${MAN_DEPENDS} WORKING_DIRECTORY ${MAN_DIR} COMMAND ${HELP2MAN} $ ${ARG_OPTS} ${INCLUDE_STRING} -o ${MAN_PAGE} COMMAND gzip -f ${MAN_PAGE} USES_TERMINAL COMMENT Generating man page for ${target} ) add_custom_target(${target}_man ALL DEPENDS ${MAN_PAGE} ) endfunction() function(install_nifti_target target_name) # Check if the current directory is the base directory of the project if("${PROJECT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_LIST_DIR}") set(IS_PROJECT_DIR 1) else() set(IS_PROJECT_DIR 0) endif() if(NOT CMAKE_VER_AT_LEAST_3_13 AND IS_PROJECT_DIR) # Early version of CMake so installation must happen in the directory in # which the target is defined. No installation occurs from the project # directory return() elseif(CMAKE_VER_AT_LEAST_3_13 AND NOT IS_PROJECT_DIR) # CMake >=3.13 has support for referencing targets in parent scopes of the # one in which the target is defined. This enables a central management of # the installation process, along with installating an target export set. # No installation occurs from the directory in which the target is defined return() endif() # Install the targets now that the appropriate directory is confirmed. install(TARGETS ${target_name} EXPORT ${NIFTI_INSTALL_EXPORT_NAME} RUNTIME COMPONENT RuntimeBinaries DESTINATION ${NIFTI_INSTALL_RUNTIME_DIR} ARCHIVE DESTINATION ${NIFTI_INSTALL_LIBRARY_DIR} COMPONENT RuntimeLibraries LIBRARY DESTINATION ${NIFTI_INSTALL_LIBRARY_DIR} COMPONENT RuntimeLibraries COMPONENT Development PUBLIC_HEADER DESTINATION ${NIFTI_INSTALL_INCLUDE_DIR} COMPONENT Development INCLUDES DESTINATION ${NIFTI_INSTALL_INCLUDE_DIR} ) endfunction() function(get_lib_version_var ver_header_text ver_type version_out) # Gets version for MAJOR/MINOR or PATCH from version header file string(REGEX MATCH "_${ver_type} [0-9]*" MATCHED "${ver_header_text}") string(REGEX REPLACE "_${ver_type} " "" OUTPUT "${MATCHED}") set(${version_out} ${OUTPUT} PARENT_SCOPE) endfunction() function(get_lib_version_vars version_header libver libver_major) # Function reads a file containing the lib version and sets the # approprioate variables in the parent scope file(READ ${version_header} VER_FILE) get_lib_version_var(${VER_FILE} "MAJOR" LIB_MAJOR_VERSION ) get_lib_version_var(${VER_FILE} "MINOR" LIB_MINOR_VERSION ) get_lib_version_var(${VER_FILE} "PATCH" LIB_PATCH_VERSION ) set(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_PATCH_VERSION}") # Check that a valid version has been specified (of the form XX.XX.XX) string(REGEX MATCH "^[0-9]*\.[0-9]*\.[0-9]*$" VER_MATCHED "${LIB_VERSION}" ) if("" STREQUAL "${VER_MATCHED}") message("matched ${VER_MATCHED}") message(FATAL_ERROR "Cannot find a valid version in the version header file ${version_header} (Found: '${LIB_VERSION}')") endif() # Set outputs in calling scope set(${libver} "${LIB_VERSION}" PARENT_SCOPE) set(${libver_major} "${LIB_MAJOR_VERSION}" PARENT_SCOPE) endfunction() nifti_clib-3.0.1/cmake/travis_dashboard.cmake000066400000000000000000000102351371325713600212270ustar00rootroot00000000000000 # set_from_env # ------------ # # Sets a CMake variable from an environment variable. If the # environment variable is not defined then the CMake variable is not # modified. If DEFAULT is specified then if the environment variable # is not defined the default value is used. Alternatively, if REQUIRED # is specified then a FATAL_ERROR is generated. # # set_from_env( [REQUIRED|DEFAULT value] ) function(set_from_env var env_var) if(NOT DEFINED ENV{${env_var}}) if (ARGV2 STREQUAL "REQUIRED") message(FATAL_ERROR "Required environment variable \"${env_var}\" not defined.") elseif (ARGV2 STREQUAL "DEFAULT") set(${var} ${ARGV3} PARENT_SCOPE) endif() else() set(${var} $ENV{${env_var}} PARENT_SCOPE) endif() endfunction() set_from_env(CTEST_SITE "TRAVIS_APP_HOST" REQUIRED) set(CTEST_SITE "travis.${CTEST_SITE}") set(CTEST_UPDATE_VERSION_ONLY 1) # https://gitlab.kitware.com/cmake/community/wikis/doc/ctest/Scripting-Of-CTest find_program(CTEST_GIT_COMMAND NAMES git) find_program(CTEST_COVERAGE_COMMAND NAMES gcov) find_program(CTEST_MEMORYCHECK_COMMAND NAMES valgrind) set_from_env(PARALLEL_LEVEL "PARALLEL_LEVEL" DEFAULT 3) set(CTEST_TEST_ARGS ${CTEST_TEST_ARGS} PARALLEL_LEVEL ${PARALLEL_LEVEL}) # The absolute path to the directory where the repository being built has been copied on the worker. set_from_env(workspace "AGENT_BUILDDIRECTORY" REQUIRED) file(TO_CMAKE_PATH "${workspace}" CTEST_DASHBOARD_ROOT) file(RELATIVE_PATH dashboard_source_name "${workspace}" "$ENV{BUILD_SOURCESDIRECTORY}") # Make environment variables to CMake variables for CTest #set_from_env(CTEST_CMAKE_GENERATOR "CTEST_CMAKE_GENERATOR" DEFAULT "Ninja") set_from_env(CTEST_CMAKE_GENERATOR "CTEST_CMAKE_GENERATOR" DEFAULT "Unix Makefiles") set_from_env(CTEST_BUILD_CONFIGURATION "CTEST_BUILD_CONFIGURATION" DEFAULT "Debug") set_from_env(BUILD_SHARED_LIBS "BUILD_SHARED_LIBS" DEFAULT "ON") set_from_env(BUILD_EXAMPLES "BUILD_EXAMPLES" DEFAULT "ON") set_from_env(INTERPROCEDURAL_OPTIMIZATION "INTERPROCEDURAL_OPTIMIZATION" DEFAULT "ON") set_from_env(NIFTI_SHELL_SCRIPT_TESTS "NIFTI_SHELL_SCRIPT_TESTS" DEFAULT "ON") set_from_env(dashboard_do_coverage "WITH_COVERAGE" DEFAULT "OFF") set_from_env(dashboard_do_memcheck "WITH_MEMCHECK" DEFAULT "OFF") if(NOT CTEST_BUILD_NAME) if(DEFINED ENV{SYSTEM_PULLREQUEST_SOURCEBRANCH}) set(branch "-$ENV{SYSTEM_PULLREQUEST_SOURCEBRANCH}") set(dashboard_git_branch "$ENV{SYSTEM_PULLREQUEST_SOURCEBRANCH}") set(dashboard_model "Experimental") elseif(ENV{BUILD_SOURCEBRANCHNAME} STREQUAL "master") set(branch "-master") set(dashboard_git_branch "$ENV{BUILD_SOURCEBRANCHNAME}") set(dashboard_model "Continuous") elseif(ENV{BUILD_SOURCEBRANCHNAME} STREQUAL "nightly-master") set(branch "-nightly-master") set(dashboard_git_branch "$ENV{BUILD_SOURCEBRANCHNAME}") set(dashboard_model "Nightly") else() set(branch "-master") set(dashboard_git_branch "master") set(dashboard_model "Experimental") endif() if(DEFINED ENV{SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}) set(pr "-PR$ENV{SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}") else() set(pr "") endif() set(CTEST_BUILD_NAME "$ENV{BLDPREFIX}_$ENV{TRAVIS_OS_NAME}-$ENV{BUILD_BUILDID}_${pr}_${branch}") endif() set(dashboard_cache " CMAKE_BUILD_TYPE:STRING=None BUILD_TESTING:BOOL=ON BUILD_EXAMPLES:BOOL=${BUILD_EXAMPLES} BUILD_SHARED_LIBS:BOOL=${BUILD_SHARED_LIBS} CMAKE_INTERPROCEDURAL_OPTIMIZATION:BOOL=${INTERPROCEDURAL_OPTIMIZATION} NIFTI_BUILD_APPLICATIONS:BOOL=ON NIFTI_SHELL_SCRIPT_TESTS:BOOL=${NIFTI_SHELL_SCRIPT_TESTS} USE_FSL_CODE:BOOL=ON USE_CIFTI_CODE:BOOL=ON USE_NIFTI2_CODE:BOOL=ON CMAKE_C_COMPILER:STRING=$ENV{CC} CMAKE_C_FLAGS:STRING=$ENV{CFLAGS} CMAKE_CXX_COMPILER:STRING=$ENV{CXX} CMAKE_CXX_FLAGS:STRING=$ENV{CXXFLAGS} CMAKE_EXE_LINKER_FLAGS:STRING=$ENV{LDFLAGS} CMAKE_MODULE_LINKER_FLAGS:STRING=$ENV{LDFLAGS} " ) # Eventually USE_NIFTI1_CODE:BOOL=ON must be added. string(TIMESTAMP build_date "%Y-%m-%d") message("CDash Build Identifier: ${build_date} ${CTEST_BUILD_NAME}") message("CTEST_SITE = ${CTEST_SITE}") include("${CTEST_SCRIPT_DIRECTORY}/nifti_common.cmake") nifti_clib-3.0.1/conda.build/000077500000000000000000000000001371325713600160075ustar00rootroot00000000000000nifti_clib-3.0.1/conda.build/build.sh000066400000000000000000000003041371325713600174370ustar00rootroot00000000000000#!/bin/sh mkdir ../build && cd ../build cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=ON -DUSE_CIFTI_CODE=ON -DUSE_NIFTI2_CODE=ON $SRC_DIR make install nifti_clib-3.0.1/conda.build/meta.yaml000066400000000000000000000007271371325713600176270ustar00rootroot00000000000000package: name: nifti_clib version: {{ GIT_DESCRIBE_TAG }} source: rev: {{ GIT_DESCRIBE_TAG }} git_url: ../ requirements: build: - cmake run: - expat - zlib build: number: 1 skip: True # [win] test: commands: about: home: https://github.com/NIFTI-Imaging/nifti_clib license: See github repository summary: 'C library for IO with the nifti file format.' extra: recipe-maintainers: - leej3 nifti_clib-3.0.1/docs/000077500000000000000000000000001371325713600145555ustar00rootroot00000000000000nifti_clib-3.0.1/docs/Doxy_nifti.txt000066400000000000000000000110331371325713600174300ustar00rootroot00000000000000# Doxyfile 1.2.4 # This file describes the settings to be used by doxygen for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # General configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = nifti1_io # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../fsliolib ../niftilib ../znzlib # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. FILE_PATTERNS = *.c *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = testprog.c nifti1_test.c mjtest.c # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimised for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. Warning: This feature # is still experimental and very incomplete. GENERATE_XML = NO nifti_clib-3.0.1/docs/Doxyfile.ORIG000066400000000000000000000706221371325713600170310ustar00rootroot00000000000000# Doxyfile 1.2.4 # This file describes the settings to be used by doxygen for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # General configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, # Korean, Hungarian, Norwegian, Spanish, Romanian, Russian, Croatian, # Polish, Portuguese and Slovene. OUTPUT_LANGUAGE = English # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these class will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. It is allowed to use relative paths in the argument list. STRIP_FROM_PATH = # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a class diagram (in Html and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. CLASS_DIAGRAMS = YES # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower case letters. If set to YES upper case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # users are adviced to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explict @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # reimplements. INHERIT_DOCS = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # The ENABLE_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. INPUT_FILTER = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse. FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side pannel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript and frames is required (for instance Netscape 4.0+ # or Internet explorer 4.0+). GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimised for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = YES # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using a WORD or other. # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assigments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = YES # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. Warning: This feature # is still experimental and very incomplete. GENERATE_XML = NO #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = #--------------------------------------------------------------------------- # Configuration::addtions related to external references #--------------------------------------------------------------------------- # The TAGFILES tag can be used to specify one or more tagfiles. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to # YES then doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other # documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to # YES then doxygen will generate a graph for each documented header file showing # the documented files that directly or indirectly include this file INCLUDED_BY_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES #--------------------------------------------------------------------------- # Configuration::addtions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO # The CGI_NAME tag should be the name of the CGI script that # starts the search engine (doxysearch) with the correct parameters. # A script with this name will be generated by doxygen. CGI_NAME = search.cgi # The CGI_URL tag should be the absolute URL to the directory where the # cgi binaries are located. See the documentation of your http daemon for # details. CGI_URL = # The DOC_URL tag should be the absolute URL to the directory where the # documentation is located. If left blank the absolute path to the # documentation, with file:// prepended to it, will be used. DOC_URL = # The DOC_ABSPATH tag should be the absolute path to the directory where the # documentation is located. If left blank the directory on the local machine # will be used. DOC_ABSPATH = # The BIN_ABSPATH tag must point to the directory where the doxysearch binary # is installed. BIN_ABSPATH = /usr/local/bin/ # The EXT_DOC_PATHS tag can be used to specify one or more paths to # documentation generated for other projects. This allows doxysearch to search # the documentation for these projects as well. EXT_DOC_PATHS = nifti_clib-3.0.1/fsliolib/000077500000000000000000000000001371325713600154305ustar00rootroot00000000000000nifti_clib-3.0.1/fsliolib/CMakeLists.txt000066400000000000000000000011211371325713600201630ustar00rootroot00000000000000# Michael Hanke 2004-04-25: # Restructure the file to match those of niftilib and znzlib set(NIFTI_FSLIOLIB_NAME ${NIFTI_PACKAGE_PREFIX}fslio) add_nifti_library(${NIFTI_FSLIOLIB_NAME} fslio.c ) set_target_properties( ${NIFTI_FSLIOLIB_NAME} PROPERTIES PRIVATE_HEADER "${CMAKE_CURRENT_LIST_DIR}/fslio.h;${CMAKE_CURRENT_LIST_DIR}/dbh.h" ) target_link_libraries( ${NIFTI_FSLIOLIB_NAME} PUBLIC ${NIFTI_PACKAGE_PREFIX}niftiio) # Set lib version when buildung shared libs. if(BUILD_SHARED_LIBS) set_target_properties(${NIFTI_FSLIOLIB_NAME} PROPERTIES ${NIFTI_LIBRARY_PROPERTIES}) endif() nifti_clib-3.0.1/fsliolib/Makefile000066400000000000000000000006761371325713600171010ustar00rootroot00000000000000include ../Makefile PROJNAME = fslio INCFLAGS = $(ZLIB_INC) $(ZNZ_INC) $(NIFTI_INC) LIBS = $(ZLIB_LIBS) $(ZNZ_LIBS) $(NIFTI_LIBS) $(FSL_LIBS) SRCS=fslio.c OBJS=fslio.o SCRIPTS = remove_ext fsloutputtype imtest imglob imcp imln imrm immv depend: $(RM) -f depend.mk $(MAKE) depend.mk depend.mk: $(CC) $(DEPENDFLAGS) $(INCFLAGS) $(SRCS) >> depend.mk lib: libfslio.a libfslio.a: ${OBJS} ${AR} -r libfslio.a ${OBJS} include depend.mk nifti_clib-3.0.1/fsliolib/dbh.h000066400000000000000000000110731371325713600163400ustar00rootroot00000000000000#ifndef _DBH_H_ #define _DBH_H_ /* * * (c) Copyright, 1986-1994 * Biomedical Imaging Resource * Mayo Foundation * * dbh.h * * * database sub-definitions */ struct header_key /* header_key */ { /* off + size*/ int sizeof_hdr; /* 0 + 4 */ char data_type[10]; /* 4 + 10 */ char db_name[18]; /* 14 + 18 */ int extents; /* 32 + 4 */ short int session_error; /* 36 + 2 */ char regular; /* 38 + 1 */ char hkey_un0; /* 39 + 1 */ }; /* total=40 */ struct image_dimension /* image_dimension */ { /* off + size*/ short int dim[8]; /* 0 + 16 */ char vox_units[4]; /* 16 + 4 */ char cal_units[8]; /* 20 + 4 */ short int unused1; /* 24 + 2 */ short int datatype; /* 30 + 2 */ short int bitpix; /* 32 + 2 */ short int dim_un0; /* 34 + 2 */ float pixdim[8]; /* 36 + 32 */ /* pixdim[] specifies the voxel dimensions: pixdim[1] - voxel width pixdim[2] - voxel height pixdim[3] - interslice distance ..etc */ float vox_offset; /* 68 + 4 */ float funused1; /* 72 + 4 */ float funused2; /* 76 + 4 */ float funused3; /* 80 + 4 */ float cal_max; /* 84 + 4 */ float cal_min; /* 88 + 4 */ int compressed; /* 92 + 4 */ int verified; /* 96 + 4 */ int glmax, glmin; /* 100 + 8 */ }; /* total=108 */ struct data_history /* data_history */ { /* off + size*/ char descrip[80]; /* 0 + 80 */ char aux_file[24]; /* 80 + 24 */ char orient; /* 104 + 1 */ char originator[10]; /* 105 + 10 */ char generated[10]; /* 115 + 10 */ char scannum[10]; /* 125 + 10 */ char patient_id[10]; /* 135 + 10 */ char exp_date[10]; /* 145 + 10 */ char exp_time[10]; /* 155 + 10 */ char hist_un0[3]; /* 165 + 3 */ int views; /* 168 + 4 */ int vols_added; /* 172 + 4 */ int start_field; /* 176 + 4 */ int field_skip; /* 180 + 4 */ int omax,omin; /* 184 + 8 */ int smax,smin; /* 192 + 8 */ }; /* total=200 */ struct dsr /* dsr */ { /* off + size*/ struct header_key hk; /* 0 + 40 */ struct image_dimension dime; /* 40 + 108 */ struct data_history hist; /* 148 + 200 */ }; /* total=348 */ /* Acceptable values for hdr.dime.datatype */ #define DT_NONE 0 #define DT_UNKNOWN 0 #define DT_BINARY 1 #define DT_UNSIGNED_CHAR 2 #define DT_SIGNED_SHORT 4 #define DT_SIGNED_INT 8 #define DT_FLOAT 16 #define DT_COMPLEX 32 #define DT_DOUBLE 64 #define DT_RGB 128 #define DT_ALL 255 typedef struct { float real; float imag; } COMPLEX; #endif nifti_clib-3.0.1/fsliolib/examples/000077500000000000000000000000001371325713600172465ustar00rootroot00000000000000nifti_clib-3.0.1/fsliolib/examples/CMakeLists.txt000066400000000000000000000014151371325713600220070ustar00rootroot00000000000000 add_executable( ${NIFTI_PACKAGE_PREFIX}fsl_api_driver fsl_api_driver.c) target_link_libraries( ${NIFTI_PACKAGE_PREFIX}fsl_api_driver PUBLIC ${NIFTI_PACKAGE_PREFIX}fslio) target_include_directories(${NIFTI_PACKAGE_PREFIX}fsl_api_driver PUBLIC $ $ ) install(TARGETS ${NIFTI_PACKAGE_PREFIX}fsl_api_driver EXPORT ${NIFTI_INSTALL_EXPORT_NAME} RUNTIME DESTINATION ${NIFTI_INSTALL_RUNTIME_DIR} COMPONENT RuntimeLibraries LIBRARY DESTINATION ${NIFTI_INSTALL_LIBRARY_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${NIFTI_INSTALL_LIBRARY_DIR} COMPONENT Development INCLUDES DESTINATION ${NIFTI_INSTALL_INCLUDE_DIR} ) nifti_clib-3.0.1/fsliolib/examples/Makefile000066400000000000000000000020351371325713600207060ustar00rootroot00000000000000CC = gcc CFLAGS = -ansi -pedantic FSLIO_INCS = -I../include NIFTI_INCS = -I../include ZNZ_INCS = -I/usr/include FSLIO_LIBS = -L../lib -lfslio NIFTI_LIBS = -L../lib -lniftiio ZNZ_LIBS = -L/usr/lib -L../lib -lznz -lm -lz ############################################################## # platform specific redefines (to use, set ARCH appropriately) ## ARCH = X86_64 ifeq ($(ARCH),SGI) ## SGI 32bit ZNZ_INCS = -I/usr/freeware/include ZNZ_LIBS = -L/usr/freeware/lib32 -L../lib -lznz -lm -lz else ifeq ($(ARCH),I386) ## 32-bit Linux ZNZ_INCS = -I/usr/include ZNZ_LIBS = -L/usr/lib -L../lib -lznz -lm -lz else ifeq ($(ARCH),X86_64) ## 64-bit Linux ZNZ_INCS = ZNZ_LIBS = -L../lib -lznz -lm -lz endif endif endif all: fsl_api_driver clean: rm -f fsl_api_driver fsl_api_driver: fsl_api_driver.c ../lib/libfslio.a $(CC) $(CFLAGS) -o fsl_api_driver fsl_api_driver.c $(FSLIO_INCS) $(NIFTI_INCS) $(ZNZ_INCS) $(FSLIO_LIBS) $(NIFTI_LIBS) $(ZNZ_LIBS) help: @echo "all: make the fsl_api_driver program" @echo "clean: rm the fsl_api_driver program" nifti_clib-3.0.1/fsliolib/examples/fsl_api_driver.c000066400000000000000000000074671371325713600224200ustar00rootroot00000000000000/******************************************************************* * * fsl_api_driver.c * * Test fslio API * * Usage: fsl_api_driver [params] * * * print * print dataset header fields * peek X Y Z T * print value at voxel location X Y Z T (0-based index) * timecourse X Y Z * print timecourse at voxel location X Y Z (0-based index) * * Kate Fissell, University of Pittsburgh * 12/04 *******************************************************************/ #include #include #include #include void pusage(char *cmd); int main(int argc, char * argv[]) { FSLIO *fslio; void *buffer; char *f1name; double ***vol; int x,y,z,t; /*** process commandline parameters */ if (argc < 2) { pusage(argv[0]); exit(1); } /************************* PRINT ***************************/ if (!strncmp(argv[1],"print",5)) { if (argc != 3) { fprintf(stderr, "\nError, print command takes one parameter: print \n"); exit(1); } f1name = argv[2]; /** open nifti dataset */ fslio = FslInit(); buffer = FslReadAllVolumes(fslio,f1name); if (buffer == NULL) { fprintf(stderr, "\nError opening and reading %s.\n",f1name); exit(1); } nifti_image_infodump(fslio->niftiptr); exit(0); } /************************* PEEK ***************************/ if (!strncmp(argv[1],"peek",4)) { if (argc != 7) { fprintf(stderr, "\nError, peek command takes five parameters: peek X Y Z T\n"); exit(1); } /**** get inputs */ f1name = argv[2]; x = atoi(argv[3]); y = atoi(argv[4]); z = atoi(argv[5]); t = atoi(argv[6]); /** open nifti dataset header */ fslio = FslReadHeader(f1name); if (fslio == NULL) { fprintf(stderr, "\nError, could not read header info for %s.\n",f1name); exit(1); } /**** check inputs */ if ( (x<0) || (x>=fslio->niftiptr->nx) ) { fprintf(stderr, "\nError: x index (%d) out of range [0..%d]\n",x,fslio->niftiptr->nx-1); exit(1); } if ( (y<0) || (y>=fslio->niftiptr->ny) ) { fprintf(stderr, "\nError: y index (%d) out of range [0..%d]\n",y,fslio->niftiptr->ny-1); exit(1); } if ( (z<0) || (z>=fslio->niftiptr->nz) ) { fprintf(stderr, "\nError: z index (%d) out of range [0..%d]\n",z,fslio->niftiptr->nz-1); exit(1); } if ( (t<0) || (t>=fslio->niftiptr->nt) ) { fprintf(stderr, "\nError: t index (%d) out of range [0..%d]\n",t,fslio->niftiptr->nt-1); exit(1); } /*** get volume data as scaled doubles */ vol = FslGetVolumeAsScaledDouble(fslio,t); if (vol == NULL) { fprintf(stderr, "\nError accessing %s\n",f1name); exit(1); } else { fprintf(stderr, "\nLocation %d %d %d %d: %.4f\n",x,y,z,t,vol[z][y][x]); exit(0); } } fprintf(stderr, "\nError, unrecognized command %s\n",argv[1]); pusage(argv[0]); exit(1); } void pusage(char *cmd) { fprintf(stderr, "\n%s is a small driver program to test out the fslio API.\n",cmd); fprintf(stderr, "\nUsage: %s ",cmd); fprintf(stderr, "\n\n\tCommands:"); fprintf(stderr, "\n\tprint \t\t\tprint dataset header"); fprintf(stderr, "\n\tpeek X Y Z T\t\tprint dataset value at location (0-based) (x,y,z,t)."); fprintf(stderr, "\n"); return; } nifti_clib-3.0.1/fsliolib/fslio.c000066400000000000000000002404071371325713600167170ustar00rootroot00000000000000/* fslio.c (Input and output routines for images in FSL) Mark Jenkinson FMRIB Image Analysis Group */ /* The fslio.c file was originally part of FSL - FMRIB's Software Library http://www.fmrib.ox.ac.uk/fsl fslio.c has now been placed in the public domain. Developed at FMRIB (Oxford Centre for Functional Magnetic Resonance Imaging of the Brain), Department of Clinical Neurology, Oxford University, Oxford, UK */ /** \file fslio.c \brief Main collection of FSL i/o routines, written by Mark Jenkinson, FMRIB - updates by Rick Reynolds, SSCC, NIMH */ #include "fslio.h" #include "assert.h" static int FslIgnoreMFQ=0; static int FslOverrideOutputType=-1; #define FSLIOERR(x) { fprintf(stderr,"Error:: %s\n",(x)); fflush(stderr); exit(EXIT_FAILURE); } /************************************************************ * FslFileTypeString ************************************************************/ /*! \fn char* FslFileTypeString(int filetype) \brief Return a string describing the format of the dataset \param filetype FSL data format code. Legal values are as defined by FSL_TYPE. \return A string with the data format name, e.g. "ANALYZE-7.5" \sa FSL_TYPE */ const char* FslFileTypeString(int filetype) { if (filetype==FSL_TYPE_ANALYZE) return "ANALYZE-7.5"; if (filetype==FSL_TYPE_NIFTI) return "NIFTI-1+"; if (filetype==FSL_TYPE_NIFTI_PAIR) return "NIFTI-1"; if (filetype==FSL_TYPE_ANALYZE_GZ) return "ANALYZE-7.5"; if (filetype==FSL_TYPE_NIFTI_GZ) return "NIFTI-1+"; if (filetype==FSL_TYPE_NIFTI_PAIR_GZ) return "NIFTI-1"; return "UNKNOWN"; } int FslIsValidFileType(int filetype) { if ( (filetype!=FSL_TYPE_ANALYZE) && (filetype!=FSL_TYPE_ANALYZE_GZ) && (filetype!=FSL_TYPE_NIFTI) && (filetype!=FSL_TYPE_NIFTI_GZ) && (filetype!=FSL_TYPE_NIFTI_PAIR) && (filetype!=FSL_TYPE_NIFTI_PAIR_GZ) && (filetype!=FSL_TYPE_MINC) && (filetype!=FSL_TYPE_MINC_GZ) ) { fprintf(stderr,"Error: unrecognised file type: %d\n",filetype); return 0; } return 1; } int FslBaseFileType(int filetype) { /* returns -1 to indicate error - unrecognised filetype */ if ( (filetype==FSL_TYPE_ANALYZE_GZ) || (filetype==FSL_TYPE_ANALYZE) ) return FSL_TYPE_ANALYZE; if ( (filetype==FSL_TYPE_NIFTI_GZ) || (filetype==FSL_TYPE_NIFTI) ) return FSL_TYPE_NIFTI; if ( (filetype==FSL_TYPE_NIFTI_PAIR_GZ) || (filetype==FSL_TYPE_NIFTI_PAIR) ) return FSL_TYPE_NIFTI_PAIR; if ( (filetype==FSL_TYPE_MINC_GZ) || (filetype==FSL_TYPE_MINC) ) return FSL_TYPE_MINC; fprintf(stderr,"Error: unrecognised file type (%d)\n",filetype); return -1; } int FslGetFileType2(const FSLIO *fslio, int quiet) { FSLIO *mutablefslio; if (fslio==NULL) FSLIOERR("FslGetFileType: Null pointer passed for FSLIO"); if ( (fslio->file_mode==FSL_TYPE_MINC) || (fslio->file_mode==FSL_TYPE_MINC_GZ) ) { return fslio->file_mode; } if ( !FslIsValidFileType(fslio->file_mode) ) return -1; if (fslio->niftiptr!=NULL) { /* check that it is nifti_type and filetype are consistent */ if (fslio->niftiptr->nifti_type != FslBaseFileType(fslio->file_mode)) { if (!quiet) { fprintf(stderr,"Warning: nifti structure and fsl structure disagree on file type\n"); fprintf(stderr,"nifti = %d and fslio = %d\n",fslio->niftiptr->nifti_type,fslio->file_mode); } mutablefslio = (FSLIO *) fslio; /* dodgy and will generate warnings */ mutablefslio->niftiptr->nifti_type = FslBaseFileType(fslio->file_mode); return fslio->file_mode; } } return fslio->file_mode; } int FslGetFileType(const FSLIO *fslio) { return FslGetFileType2(fslio,0); } void FslSetFileType(FSLIO *fslio, int filetype) { if (fslio==NULL) FSLIOERR("FslSetFileType: Null pointer passed for FSLIO"); if ( (filetype==FSL_TYPE_MINC) || (filetype==FSL_TYPE_MINC_GZ) ) { fslio->file_mode = filetype; return; } if (! FslIsValidFileType(filetype)) { return; } fslio->file_mode = filetype; /* indicates general nifti - details in niftiptr */ if (fslio->niftiptr!=NULL) { fslio->niftiptr->nifti_type = FslBaseFileType(filetype); nifti_set_iname_offset(fslio->niftiptr); } } int FslIsSingleFileType(int filetype) { if ( (filetype==FSL_TYPE_NIFTI) || (filetype==FSL_TYPE_NIFTI_GZ) || (filetype==FSL_TYPE_MINC) || (filetype==FSL_TYPE_MINC_GZ) ) return 1; return 0; } int FslIsCompressedFileType(int filetype) { if ( filetype >=100 ) return 1; return 0; } int FslGetWriteMode(const FSLIO *fslio) { if (fslio==NULL) FSLIOERR("FslGetWriteMode: Null pointer passed for FSLIO"); return fslio->write_mode; } void FslSetWriteMode(FSLIO *fslio, int mode) { if (fslio==NULL) FSLIOERR("FslSetWriteMode: Null pointer passed for FSLIO"); fslio->write_mode = mode; } int FslGetEnvOutputType(void) { /* return type is one of FSL_TYPE_* or -1 to indicate error */ char *otype; if (FslOverrideOutputType>=0) return FslOverrideOutputType; otype = getenv("FSLOUTPUTTYPE"); if (otype == NULL) { fprintf(stderr,"ERROR:: Environment variable FSLOUTPUTTYPE is not set!\n"); fprintf(stderr,"Please make sure that the appropriate configuration file is sourced by your shell (e.g. by putting it in .profile).\n"); fprintf(stderr,"e.g. bash or sh users add the line \". ${FSLDIR}/etc/fslconf/fsl.sh\"\n"); fprintf(stderr,"e.g. tcsh or csh users add the line \"source ${FSLDIR}/etc/fslconf/fsl.csh\"\n"); exit(EXIT_FAILURE); } if (strcmp(otype,"ANALYZE")==0) { return FSL_TYPE_ANALYZE; } if (strcmp(otype,"ANALYZE_GZ")==0) { return FSL_TYPE_ANALYZE_GZ; } if (strcmp(otype,"NIFTI")==0) { return FSL_TYPE_NIFTI; } if (strcmp(otype,"NIFTI_GZ")==0) { return FSL_TYPE_NIFTI_GZ; } if (strcmp(otype,"NIFTI_PAIR")==0) { return FSL_TYPE_NIFTI_PAIR; } if (strcmp(otype,"NIFTI_PAIR_GZ")==0) { return FSL_TYPE_NIFTI_PAIR_GZ; } if (strcmp(otype,"MINC")==0) { return FSL_TYPE_MINC; } if (strcmp(otype,"MINC_GZ")==0) { return FSL_TYPE_MINC_GZ; } fprintf(stderr,"ERROR:: Unrecognised value (%s) of environment variable FSLOUTPUT\n",otype); fprintf(stderr,"Legal values are: ANALYZE, NIFTI, NIFTI_PAIR, MINC, ANALYZE_GZ, NIFTI_GZ, NIFTI_PAIR_GZ, MINC_GZ\n"); exit(EXIT_FAILURE); return -1; } int FslFileType(const char* fname) { /* return type is FSL_TYPE_* or -1 to indicate undetermined */ /* use name as first priority but if that is ambiguous then resolve using environment */ int flen; int retval=-1; if (fname==NULL) return retval; flen = strlen(fname); /* debian@onerussian.com had to group conditions to avoid possible * illegal memory read-ins */ if (flen<5) return retval; /* smallest name + extension is a.nii */ if (strcmp(fname + flen - 4,".nii")==0) retval=FSL_TYPE_NIFTI; if (strcmp(fname + flen - 4,".mnc")==0) retval=FSL_TYPE_MINC; if (strcmp(fname + flen - 4,".hdr")==0) retval=FSL_TYPE_NIFTI_PAIR; if (strcmp(fname + flen - 4,".img")==0) retval=FSL_TYPE_NIFTI_PAIR; if ((retval==-1) && (flen<8)) return retval; /* small name + ext.gz is a.nii.gz */ if (strcmp(fname + flen - 7,".nii.gz")==0) retval=FSL_TYPE_NIFTI_GZ; if (strcmp(fname + flen - 7,".mnc.gz")==0) retval=FSL_TYPE_MINC; if (strcmp(fname + flen - 7,".hdr.gz")==0) retval=FSL_TYPE_NIFTI_PAIR_GZ; if (strcmp(fname + flen - 7,".img.gz")==0) retval=FSL_TYPE_NIFTI_PAIR_GZ; if ( (retval==FSL_TYPE_NIFTI_PAIR) || (retval==FSL_TYPE_NIFTI_PAIR_GZ) ) { /* If it was hdr or img, check if Analyze was requested by environment */ if ( (FslGetEnvOutputType() == FSL_TYPE_ANALYZE) && (retval == FSL_TYPE_NIFTI_PAIR) ) retval=FSL_TYPE_ANALYZE; if ( (FslGetEnvOutputType() == FSL_TYPE_ANALYZE_GZ) && (retval == FSL_TYPE_NIFTI_PAIR_GZ) ) retval=FSL_TYPE_ANALYZE_GZ; } return retval; } /************************************************************ * FslGetReadFileType ************************************************************/ /*! \fn int FslGetReadFileType(const FSLIO *fslio) \brief return the best estimate of the true file type This function is used to return the best estimate of the true file type once a simple open has occurred - for now it is used after a nifti open call is made \param fslio data structure \return FSL_TYPE filetype code \sa FSL_TYPE */ int FslGetReadFileType(const FSLIO *fslio) { int filetype=FSL_TYPE_ANALYZE; /* unused default */ if (fslio==NULL) FSLIOERR("FslReadGetFileType: Null pointer passed for FSLIO"); /* Don't use fslio->file_mode as it hasn't been set yet */ if (fslio->niftiptr!=NULL) { /* use the nifti_type and hdr or img name to determine the actual type */ if (fslio->niftiptr->nifti_type == FSL_TYPE_ANALYZE) { if (FslIsCompressedFileType(FslFileType(fslio->niftiptr->iname))) { filetype = FSL_TYPE_ANALYZE_GZ; } else { filetype = FSL_TYPE_ANALYZE; } } if (fslio->niftiptr->nifti_type == FSL_TYPE_NIFTI_PAIR) { if (FslIsCompressedFileType(FslFileType(fslio->niftiptr->iname))) { filetype = FSL_TYPE_NIFTI_PAIR_GZ; } else { filetype = FSL_TYPE_NIFTI_PAIR; } } if (fslio->niftiptr->nifti_type == FSL_TYPE_NIFTI) { if (FslIsCompressedFileType(FslFileType(fslio->niftiptr->fname))) { filetype = FSL_TYPE_NIFTI_GZ; } else { filetype = FSL_TYPE_NIFTI; } } } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); filetype = FSL_TYPE_MINC; } return filetype; } int FslFileExists(const char *filename) { /* return 1 if file(s) exists, otherwise return 0 */ char *hdrname = nifti_findhdrname(filename); char *imgname = NULL; if (hdrname!=NULL){ imgname = nifti_findimgname(filename, FslBaseFileType(FslFileType(hdrname))); free(hdrname); if (imgname != NULL) { free(imgname); return 1; } } return 0; } char *FslMakeBaseName(const char *fname) { char *basename; int blen; basename = nifti_makebasename(fname); blen = strlen(basename); #ifdef HAVE_ZLIB if ((blen>7) && (strcmp(basename + blen-7,".mnc.gz") == 0)) { basename[blen-7]='\0'; return basename; } #endif if ((blen>4) && (strcmp(basename + blen-4,".mnc") == 0)) { basename[blen-4]='\0'; return basename; } return basename; } void FslGetHdrImgNames(const char* filename, const FSLIO* fslio, char** hdrname, char** imgname) { char *basename; int filetype; basename = FslMakeBaseName(filename); *hdrname = (char *)calloc(sizeof(char),strlen(basename)+8); *imgname = (char *)calloc(sizeof(char),strlen(basename)+8); strcpy(*hdrname,basename); strcpy(*imgname,basename); filetype = FslGetFileType(fslio); if (filetype==FSL_TYPE_NIFTI_GZ) { strcat(*hdrname,".nii.gz"); strcat(*imgname,".nii.gz"); free(basename); return; } if (filetype==FSL_TYPE_NIFTI) { strcat(*hdrname,".nii"); strcat(*imgname,".nii"); free(basename); return; } if (filetype==FSL_TYPE_MINC_GZ) { strcat(*hdrname,".mnc.gz"); strcat(*imgname,".mnc.gz"); free(basename); return; } if (filetype==FSL_TYPE_MINC) { strcat(*hdrname,".mnc"); strcat(*imgname,".mnc"); free(basename); return; } if ( (filetype==FSL_TYPE_NIFTI_PAIR_GZ) || (filetype==FSL_TYPE_ANALYZE_GZ) ) { strcat(*hdrname,".hdr.gz"); strcat(*imgname,".img.gz"); free(basename); return; } if ( (filetype==FSL_TYPE_NIFTI_PAIR) || (filetype==FSL_TYPE_ANALYZE) ) { strcat(*hdrname,".hdr"); strcat(*imgname,".img"); free(basename); return; } fprintf(stderr,"Error: Unrecognised filetype (%d)\n",FslGetFileType(fslio)); free(basename); /* Failure */ free(*hdrname); *hdrname = NULL; free(*imgname); *imgname = NULL; } /*************************************************************** * FslInit() ***************************************************************/ /*! \fn FSLIO *FslInit() \brief allocate space for the FSLIO struct and set some sensible defaults \return A pointer to an initialized FSLIO data structure */ FSLIO *FslInit(void) { FSLIO *fslio; fslio = (FSLIO *) calloc(1,sizeof(FSLIO)); FslSetInit(fslio); return fslio; } void FslSetInit(FSLIO* fslio) { /* set some sensible defaults */ fslio->niftiptr = NULL; fslio->mincptr = NULL; FslSetFileType(fslio,FslGetEnvOutputType()); FslSetWriteMode(fslio,0); fslio->written_hdr = 0; } void FslInit4Write(FSLIO* fslio, const char* filename, int ft) { /* ft determines filetype if ft>=0*/ int imgtype; FslSetWriteMode(fslio,1); /* Determine file type from image name (first priority) or environment (default) */ imgtype = FslFileType(filename); if (imgtype<0) imgtype = FslGetEnvOutputType(); if (ft >= 0) imgtype = ft; if (!FslIsValidFileType(imgtype)) { fprintf(stderr,"Error: Failed to determine file type for writing in FslOpen()\n"); exit(EXIT_FAILURE); } if ( (FslBaseFileType(imgtype)!=FSL_TYPE_MINC) ) { FslInitHeader(fslio, NIFTI_TYPE_FLOAT32, 1, 1, 1, 3, 0.0, 0.0, 0.0, 0.0, 4); FslSetFileType(fslio,imgtype); /* this is after InitHeader as niftiptr set there */ /* determine the header and image filename */ FslGetHdrImgNames(filename,fslio,&(fslio->niftiptr->fname),&(fslio->niftiptr->iname)); if ( (fslio->niftiptr->fname == NULL) || (fslio->niftiptr->iname == NULL) ) { fprintf(stderr,"Error: cannot find filenames for %s\n",filename); } } else if (FslBaseFileType(imgtype)==FSL_TYPE_MINC) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); return; } else { fprintf(stderr,"Error:: unrecognised image type requested\n"); return; } return; } void FslInitHeader(FSLIO *fslio, short t, size_t x, size_t y, size_t z, size_t v, float vx, float vy, float vz, float tr, size_t dim) { /* NB: This function does not set the file type or write mode*/ if (fslio==NULL) FSLIOERR("FslInitHeader: Null pointer passed for FSLIO"); fslio->niftiptr = nifti_simple_init_nim(); /* make nifti type consistent with fslio */ fslio->niftiptr->nifti_type = FslBaseFileType(fslio->file_mode); fslio->mincptr = NULL; FslSetDataType(fslio,t); FslSetDim(fslio,x,y,z,v); FslSetVoxDim(fslio,vx,vy,vz,tr); FslSetTimeUnits(fslio,"s"); FslSetDimensionality(fslio,dim); } void FslCloneHeader(FSLIO *dest, const FSLIO *src) { /* only clone the information that is stored in the disk version of the header */ /* - therefore _not_ the filenames, output type, write mode, etc */ void *data=NULL; int filetype, writemode; int preserve_nifti_values = 0; if (dest==NULL) FSLIOERR("FslCloneHeader: Null pointer passed for FSLIO"); if (src==NULL) FSLIOERR("FslCloneHeader: Null pointer passed for FSLIO"); if (src->niftiptr!=NULL) { /* preserve the filenames, output type and write mode */ if (dest->niftiptr != NULL) { data = dest->niftiptr->data; preserve_nifti_values = 1; } filetype = FslGetFileType2(dest,1); writemode = FslGetWriteMode(dest); /* copy _all_ info across */ dest->niftiptr = nifti_copy_nim_info(src->niftiptr); /* restore old values */ if (preserve_nifti_values) { dest->niftiptr->data = data; } else { /* destroy the values that the nifti copy creates */ free(dest->niftiptr->fname); free(dest->niftiptr->iname); nifti_free_extensions(dest->niftiptr); dest->niftiptr->fname = NULL; dest->niftiptr->iname = NULL; dest->niftiptr->data = NULL; /* should already be NULL */ } FslSetFileType(dest,filetype); FslSetWriteMode(dest,writemode); } if (src->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } int fsl_fileexists(const char* fname) { znzFile fp; fp = znzopen( fname , "rb" , 1 ) ; if( !znz_isnull(fp) ) { znzclose(fp); return 1; } return 0; } int FslCheckForMultipleFileNames(const char* filename) { char *basename, *tmpname; int singlecount=0, hdrcount=0, imgcount=0, ambiguous=0; basename = nifti_makebasename(filename); tmpname = (char *)calloc(strlen(basename) + 10,sizeof(char)); strcpy(tmpname,basename); strcat(tmpname,".nii"); if (fsl_fileexists(tmpname)) { singlecount++; } strcpy(tmpname,basename); strcat(tmpname,".nii.gz"); if (fsl_fileexists(tmpname)) { singlecount++; } strcpy(tmpname,basename); strcat(tmpname,".mnc"); if (fsl_fileexists(tmpname)) { singlecount++; } strcpy(tmpname,basename); strcat(tmpname,".mnc.gz"); if (fsl_fileexists(tmpname)) { singlecount++; } strcpy(tmpname,basename); strcat(tmpname,".img"); if (fsl_fileexists(tmpname)) { imgcount++; } strcpy(tmpname,basename); strcat(tmpname,".img.gz"); if (fsl_fileexists(tmpname)) { imgcount++; } strcpy(tmpname,basename); strcat(tmpname,".hdr"); if (fsl_fileexists(tmpname)) { hdrcount++; } strcpy(tmpname,basename); strcat(tmpname,".hdr.gz"); if (fsl_fileexists(tmpname)) { hdrcount++; } ambiguous = 1; if ( (hdrcount==1) && (imgcount==1) && (singlecount==0) ) { ambiguous=0; } if ( (hdrcount==0) && (imgcount==0) && (singlecount==1) ) { ambiguous=0; } /* treat no image found as not ambiguous - want opening errors instead */ if ( (hdrcount==0) && (imgcount==0) && (singlecount==0) ) { ambiguous=0; } free(tmpname); free(basename); return ambiguous; } int check_for_multiple_filenames(const char* filename) { char *basename, *tmpname; char *otype; if (FslCheckForMultipleFileNames(filename)) { /* take action */ basename = nifti_makebasename(filename); tmpname = (char *)calloc(strlen(basename) + 10,sizeof(char)); fprintf(stderr,"\n\n\nWARNING!!!! Multiple image files detected:\n"); /* list the offending files */ strcpy(tmpname,basename); strcat(tmpname,".nii"); if (fsl_fileexists(tmpname)) { fprintf(stderr,"%s ",tmpname); } strcpy(tmpname,basename); strcat(tmpname,".nii.gz"); if (fsl_fileexists(tmpname)) { fprintf(stderr,"%s ",tmpname); } strcpy(tmpname,basename); strcat(tmpname,".mnc"); if (fsl_fileexists(tmpname)) { fprintf(stderr,"%s ",tmpname); } strcpy(tmpname,basename); strcat(tmpname,".mnc.gz"); if (fsl_fileexists(tmpname)) { fprintf(stderr,"%s ",tmpname); } strcpy(tmpname,basename); strcat(tmpname,".img"); if (fsl_fileexists(tmpname)) { fprintf(stderr,"%s ",tmpname); } strcpy(tmpname,basename); strcat(tmpname,".img.gz"); if (fsl_fileexists(tmpname)) { fprintf(stderr,"%s ",tmpname); } strcpy(tmpname,basename); strcat(tmpname,".hdr"); if (fsl_fileexists(tmpname)) { fprintf(stderr,"%s ",tmpname); } strcpy(tmpname,basename); strcat(tmpname,".hdr.gz"); if (fsl_fileexists(tmpname)) { fprintf(stderr,"%s ",tmpname); } fprintf(stderr,"\n\n"); if (!FslIgnoreMFQ) { otype = getenv("FSLMULTIFILEQUIT"); if (otype!=NULL) { free(tmpname); fprintf(stderr,"STOPPING PROGRAM\n"); exit(EXIT_FAILURE); } } free(tmpname); return 1; } return 0; } /*************************************************************** * FslOpen ***************************************************************/ /*! \fn FSLIO *FslOpen(const char *filename, const char *opts) \brief Opens a file for either reading or writing. The format of the output dataset is determined automatically by passing filetype -1 to FslXOpen. \sa FslXOpen */ FSLIO *FslOpen(const char *filename, const char *opts) { /* Note: -1 for filetype indicates that FslXOpen should determine filetype for itself */ return FslXOpen(filename,opts,-1); } /*************************************************************** * FslXOpen ***************************************************************/ /*! \fn FSLIO *FslXOpen(const char *filename, const char *opts, int filetype) \brief Opens a file for either reading or writing Files to be read are automatically read whether compressed or not. Also, reading uses the file extension and will fail if that file does not exist. For a more robust read, pass the basename in as then all types will be tried. \param filename Name (or basename) of the file to open \param opts Flags for fopen() of dataset, eg "r", "wb", etc. \param filetype specifies the type of file to be written. Legal values are as defined by FSL_TYPE. If filetype is less than zero, then it is ignored and the type is determined by the filename extension or, failing that, the environment default. \return pointer to FSLIO dataset datastructure \sa FSLIO \sa FSL_TYPE */ FSLIO *FslXOpen(const char *filename, const char *opts, int filetype) { FSLIO *fslio; char bopts[1024]; size_t i, bi; int imgtype; fslio = FslInit(); bi=0; for(i=0;iwritten_hdr = 0; /* open the image file - not the header */ if ( fslio->niftiptr == NULL ) { free(fslio); return NULL; } fslio->fileptr = znzopen(fslio->niftiptr->iname,bopts,FslIsCompressedFileType(imgtype)); if (znz_isnull(fslio->fileptr)) { fprintf(stderr,"Error: failed to open file %s\n",fslio->niftiptr->iname); free(fslio); return NULL; } if (!FslIsSingleFileType(imgtype)) { /* set up pointer at end of iname_offset for dual file formats (not singles) */ FslSeekVolume(fslio,0); } return fslio; } /** ======================== Open file for reading ====================== **/ check_for_multiple_filenames(filename); /* see if the extension indicates a minc file */ imgtype = FslFileType(filename); if ((imgtype>=0) && (FslBaseFileType(imgtype)==FSL_TYPE_MINC)) { free(fslio); fprintf(stderr,"Warning:: Minc is not yet supported\n"); return NULL; } /* otherwise open nifti file: read header and open img file (may be same file) */ fslio->fileptr = nifti_image_open(filename,bopts,&(fslio->niftiptr)); if (znz_isnull(fslio->fileptr)) { fprintf(stderr,"Error: failed to open file %s\n",filename); return NULL; } /* set the file type given what has been read - it uses nifti_type and filenames */ imgtype = FslGetReadFileType(fslio); FslSetFileType(fslio,imgtype); FslSetWriteMode(fslio,0); if (FslBaseFileType(FslGetFileType(fslio))==FSL_TYPE_ANALYZE) { /* For the ANALYZE case in FSL, must cheat and grab the originator field! */ /* Note that the header file is always separate here and closed by now */ struct dsr ahdr; short orig[5]; FslReadRawHeader(&ahdr,fslio->niftiptr->fname); if (fslio->niftiptr->byteorder != nifti_short_order()) { AvwSwapHeader(&ahdr); } /* Read the origin and set the sform up (if origin is non-zero) */ /* Note that signed pixdims are passed in to set the LR orientation */ memcpy(orig,&(ahdr.hist.originator),10); FslSetAnalyzeSform(fslio, orig, fslio->niftiptr->pixdim[1], fslio->niftiptr->pixdim[2], fslio->niftiptr->pixdim[3]); } /* from now on force all vox dims to be positive - LR info is in sform */ if (fslio->niftiptr!=NULL) { fslio->niftiptr->dx = fabs(fslio->niftiptr->dx); fslio->niftiptr->dy = fabs(fslio->niftiptr->dy); fslio->niftiptr->dz = fabs(fslio->niftiptr->dz); fslio->niftiptr->pixdim[1] = fabs(fslio->niftiptr->pixdim[1]); fslio->niftiptr->pixdim[2] = fabs(fslio->niftiptr->pixdim[2]); fslio->niftiptr->pixdim[3] = fabs(fslio->niftiptr->pixdim[3]); } /* set up pointer at end of iname_offset , ready for reading */ FslSeekVolume(fslio,0); return fslio; } /*************************************************************** * FslReadAllVolumes ***************************************************************/ /*! \fn void* FslReadAllVolumes(FSLIO* fslio, char* filename) \brief Read the header and all data into the FSLIO structure There is no need for FslOpen or FslClose calls when FslReadAllVolumes() is called.
This routine allocates the buffer to hold the entire dataset.
The data block returned will contain the data in whatever datatype it is stored as on disk (therefore it is a void *).
The data buffer will be byteswapped to native-endian.
The data buffer will not be scaled.
The best call to make before this is FslInit() or a calloc() for fslio. (??? why calloc if this allocates the buffer ???) \param fslio pointer to an open dataset \param filename Name of the dataset to read. \return A pointer to the data block buffer (allocated by this function).
Return Null on error ??? is this true ???
  • Note this pointer is also in the FSLIO structure as fslio->niftiptr->data.
  • Note a void pointer is returned, as the datablock is of variable datatype.
*/ void* FslReadAllVolumes(FSLIO* fslio, char* filename) { int imgtype; if (fslio==NULL) FSLIOERR("FslReadAllVolumes: Null pointer passed for FSLIO"); /* see if the extension indicates a minc file */ imgtype = FslFileType(filename); if ((imgtype>=0) && (FslBaseFileType(imgtype)==FSL_TYPE_MINC)) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); return NULL; } /** otherwise it is a nifti file - so read it! **/ fslio->mincptr = NULL; /* make sure an FslOpen hasn't locked the file */ if (!znz_isnull(fslio->fileptr)) FslClose(fslio); fslio->niftiptr = nifti_image_read(filename,1); /* check for failure, from David Akers */ if (fslio->niftiptr == NULL) { FSLIOERR("FslReadAllVolumes: error reading NIfTI image"); return(NULL); } FslSetFileType(fslio,fslio->niftiptr->nifti_type); FslSetWriteMode(fslio,0); return fslio->niftiptr->data; } /*************************************************************** * FslReadVolumes ***************************************************************/ /*! \fn size_t FslReadVolumes(FSLIO *fslio, void *buffer, size_t nvols) \brief Read the first nvols Volumes from a 4D dataset \param fslio pointer to open dataset \param buffer buffer to read data into, allocated by ??? \param nvols number of volumes to read \return Number of volumes read. */ size_t FslReadVolumes(FSLIO *fslio, void *buffer, size_t nvols) { int volbytes; size_t retval=0; if (fslio==NULL) FSLIOERR("FslReadVolumes: Null pointer passed for FSLIO"); if (znz_isnull(fslio->fileptr)) FSLIOERR("FslReadVolumes: Null file pointer"); if (fslio->niftiptr!=NULL) { fslio->niftiptr->data = buffer; volbytes = FslGetVolSize(fslio) * fslio->niftiptr->nbyper; retval = nifti_read_buffer(fslio->fileptr,fslio->niftiptr->data,nvols*volbytes,fslio->niftiptr); retval /= volbytes; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return retval; } /*************************************************************** * FslWriteAllVolumes ***************************************************************/ /*! \fn void FslWriteAllVolumes(FSLIO *fslio, const void *buffer) \brief Writes all data from buffer (using size info from fslio) to file. Dimension and datatype of buffer are as is specified in nifti_image structure fslio->niftiptr. Note: If file format is Analyze (not nifti) and in Neurological order then SWAP DATA into Radiological order. \param fslio pointer to open dataset \param buffer pointer to data array. Size and datatype of this buffer */ void FslWriteAllVolumes(FSLIO *fslio, const void *buffer) { short x,y,z,t; if (fslio==NULL || fslio->niftiptr == NULL ) FSLIOERR("FslWriteAllVolumes: Null pointer passed for FSLIO"); FslGetDim(fslio,&x,&y,&z,&t); FslWriteHeader(fslio); FslWriteVolumes(fslio,buffer,t); return; } /*************************************************************** * FslWriteVolumes ***************************************************************/ /*! \fn size_t FslWriteVolumes(FSLIO *fslio, const void *buffer, size_t nvols) \brief Write the first nvols volumes in buffer to disk. Dimension and datatype of buffer are as is specified in nifti_image structure fslio->niftiptr. Note: If file format is Analyze (not nifti) and in Neurological order then SWAP DATA into Radiological order. \param fslio pointer to open dataset \param buffer pointer to data array. Size and datatype of this buffer \param nvols number of volumes to write \return number of bytes written */ size_t FslWriteVolumes(FSLIO *fslio, const void *buffer, size_t nvols) { /* The dimensions and datatype must be set before calling this function */ size_t retval = 0; /* initialize to failure */ if (fslio==NULL) FSLIOERR("FslWriteVolumes: Null pointer passed for FSLIO"); if ( (!fslio->written_hdr) && (FslIsSingleFileType(FslGetFileType(fslio))) && (FslIsCompressedFileType(FslGetFileType(fslio))) ) { FSLIOERR("FslWriteVolumes: header must be written before data for single compressed file types"); } if (fslio->niftiptr!=NULL) { size_t bytes_written; size_t nbytes; long int bpv = fslio->niftiptr->nbyper; /* bytes per voxel */ nbytes = nvols * FslGetVolSize(fslio) * bpv; if ( (FslBaseFileType(FslGetFileType(fslio))==FSL_TYPE_ANALYZE) && (FslGetLeftRightOrder(fslio)==FSL_NEUROLOGICAL) ) { /* If it is Analyze and Neurological order then SWAP DATA into Radiological order */ /* This is nasty - but what else can be done?!? */ char *tmpbuf, *inbuf; long int x, b, n, nrows; short nx, ny, nz, nv; inbuf = (char *) buffer; tmpbuf = (char *)calloc(nbytes,1); FslGetDim(fslio,&nx,&ny,&nz,&nv); nrows = nbytes / (nx * bpv); for (n=0; nfileptr, tmpbuf, nbytes); free(tmpbuf); } else { bytes_written = nifti_write_buffer(fslio->fileptr, buffer, nbytes); } retval = ( bytes_written == nbytes ) ? bytes_written : 0; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return retval; } /*************************************************************** * FslWriteHeader ***************************************************************/ /*! \fn void FslWriteHeader(FSLIO *fslio) \brief Writes nifti/anz header and opens img file ready for writing \param fslio pointer to open dataset */ void FslWriteHeader(FSLIO *fslio) { /* writes header and opens img file ready for writing */ if (fslio==NULL) FSLIOERR("FslWriteHeader: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { fslio->written_hdr = 1; if (znz_isnull(fslio->fileptr)) FSLIOERR("FslWriteHeader: no file opened!"); strcpy(fslio->niftiptr->descrip,"FSL3.2beta"); if (FslIsSingleFileType(FslGetFileType(fslio))) { /* write header info but don't close the file */ nifti_image_write_hdr_img2(fslio->niftiptr,2,"wb",fslio->fileptr,NULL); /* set up pointer at end of iname_offset for single files only */ FslSeekVolume(fslio,0); } else { /* open a new hdr file, write it and close it */ nifti_image_write_hdr_img(fslio->niftiptr,0,"wb"); } } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return; } /*************************************************************** * FslReadSliceSeries ***************************************************************/ /*! \fn size_t FslReadSliceSeries(FSLIO *fslio, void *buffer, short slice, size_t nvols) \brief Read one slice from each of the first nvols volumes in the dataset, ie get an xyt buffer. Dimension and datatype of buffer are as is specified in nifti_image structure fslio->niftiptr. Note: filepointer in file data array is restored to its initial position. \param fslio pointer to open dataset \param buffer buffer large enough to hold 1 slice from each volume \param slice slice number (0 based) to read [0 z-1] \param nvols number of volumes to read a slice from \return Number of volumes from which a slice was successfully read. 0 on error. */ size_t FslReadSliceSeries(FSLIO *fslio, void *buffer, short slice, size_t nvols) { size_t slbytes,volbytes; size_t n, orig_offset; short x,y,z,v,type; if (fslio==NULL) FSLIOERR("FslReadSliceSeries: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { FslGetDim(fslio,&x,&y,&z,&v); if ((slice<0) || (slice>=z)) FSLIOERR("FslReadSliceSeries: slice outside valid range"); slbytes = x * y * (FslGetDataType(fslio, &type) / 8); volbytes = slbytes * z; orig_offset = znztell(fslio->fileptr); znzseek(fslio->fileptr, slbytes*slice, SEEK_CUR); for (n=0; n0) znzseek(fslio->fileptr, volbytes - slbytes, SEEK_CUR); if (znzread((char *)buffer+n*slbytes, 1, slbytes, fslio->fileptr) != slbytes) FSLIOERR("FslReadSliceSeries: failed to read values"); if (fslio->niftiptr->byteorder != nifti_short_order()) nifti_swap_Nbytes(slbytes / fslio->niftiptr->swapsize, fslio->niftiptr->swapsize, (char *)buffer+n*slbytes); } /* restore file pointer to original position */ znzseek(fslio->fileptr,orig_offset,SEEK_SET); return n; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return 0; } /*************************************************************** * FslReadRowSeries ***************************************************************/ /*! \fn size_t FslReadRowSeries(FSLIO *fslio, void *buffer, short row, short slice, size_t nvols) \brief Read one row from one slice for first nvols volumes in dataset; ie get an xt buffer. Dimension and datatype of buffer are as is specified in nifti_image structure fslio->niftiptr. Note: filepointer in file data array is restored to its initial position. \param fslio pointer to open dataset \param buffer buffer to hold one row from each volume. \param row row number (0 based) to read [0 y-1] \param slice slice number (0 based) to read \param nvols number of volumes to read a row from \return Number of volumes from which a row was successfully read. 0 on error. */ size_t FslReadRowSeries(FSLIO *fslio, void *buffer, short row, short slice, size_t nvols) { size_t rowbytes,slbytes,volbytes; size_t n, orig_offset; short x,y,z,v,type; if (fslio==NULL) FSLIOERR("FslReadRowSeries: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { FslGetDim(fslio,&x,&y,&z,&v); if ((slice<0) || (slice>=z)) FSLIOERR("FslReadRowSeries: slice outside valid range"); if ((row<0) || (row>=y)) FSLIOERR("FslReadRowSeries: row outside valid range"); rowbytes = x * (FslGetDataType(fslio, &type)) / 8; slbytes = rowbytes * y; volbytes = slbytes * z; orig_offset = znztell(fslio->fileptr); znzseek(fslio->fileptr, rowbytes*row + slbytes*slice, SEEK_CUR); for (n=0; n0) znzseek(fslio->fileptr, volbytes - rowbytes, SEEK_CUR); if (znzread((char *)buffer+n*rowbytes, 1, rowbytes, fslio->fileptr) != rowbytes) FSLIOERR("FslReadRowSeries: failed to read values"); if (fslio->niftiptr->byteorder != nifti_short_order()) nifti_swap_Nbytes(rowbytes / fslio->niftiptr->swapsize, fslio->niftiptr->swapsize, (char *)buffer+n*rowbytes); } /* restore file pointer to original position */ znzseek(fslio->fileptr,orig_offset,SEEK_SET); return n; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return 0; } /*************************************************************** * FslReadTimeSeries ***************************************************************/ /*! \fn size_t FslReadTimeSeries(FSLIO *fslio, void *buffer, short xVox, short yVox, short zVox, size_t nvols) \brief Read one voxel (xyz location) from first nvols volumes in dataset; ie get a t dim buffer. Dimension and datatype of buffer are as is specified in nifti_image structure fslio->niftiptr. Note: filepointer in file data array is restored to its initial position. \param fslio pointer to open dataset \param buffer buffer to hold one timeseries vector \param xVox x voxel [0 x-1] \param yVox y voxel [0 y-1] \param zVox z voxel [0 z-1] \param nvols number of volumes to read a voxel from \return Number of volumes from which a voxel was successfully read. 0 on error. */ size_t FslReadTimeSeries(FSLIO *fslio, void *buffer, short xVox, short yVox, short zVox, size_t nvols) { size_t volbytes, offset, orig_offset; size_t n; short xdim,ydim,zdim,v; size_t wordsize; if (fslio==NULL) FSLIOERR("FslReadTimeSeries: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { FslGetDim(fslio,&xdim,&ydim,&zdim,&v); if ((xVox<0) || (xVox >=xdim)) FSLIOERR("FslReadTimeSeries: voxel outside valid range"); if ((yVox<0) || (yVox >=ydim)) FSLIOERR("FslReadTimeSeries: voxel outside valid range"); if ((zVox<0) || (zVox >=zdim)) FSLIOERR("FslReadTimeSeries: voxel outside valid range"); wordsize = fslio->niftiptr->nbyper; volbytes = xdim * ydim * zdim * wordsize; orig_offset = znztell(fslio->fileptr); offset = ((ydim * zVox + yVox) * xdim + xVox) * wordsize; znzseek(fslio->fileptr,offset,SEEK_CUR); for (n=0; n0) znzseek(fslio->fileptr, volbytes - wordsize, SEEK_CUR); if (znzread((char *)buffer+(n*wordsize), 1, wordsize,fslio->fileptr) != wordsize) FSLIOERR("FslReadTimeSeries: failed to read values"); if (fslio->niftiptr->byteorder != nifti_short_order()) nifti_swap_Nbytes(1,fslio->niftiptr->swapsize, (char *)buffer+(n*wordsize)); } /* restore file pointer to original position */ znzseek(fslio->fileptr,orig_offset,SEEK_SET); return n; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return 0; } int FslSeekVolume(FSLIO *fslio, size_t vols) { int offset; if (fslio==NULL) FSLIOERR("FslSeekVolume: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { offset = fslio->niftiptr->iname_offset + vols * FslGetVolSize(fslio) * fslio->niftiptr->nbyper; if (znz_isnull(fslio->fileptr)) FSLIOERR("FslSeekVolume: Null file pointer"); return znzseek(fslio->fileptr,offset,SEEK_SET); } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return 0; } size_t FslGetVolSize(FSLIO *fslio) { /* returns number of voxels per 3D volume */ if (fslio==NULL) FSLIOERR("FslGetVolSize: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { return (fslio->niftiptr->nx * fslio->niftiptr->ny * fslio->niftiptr->nz); } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return 0; } void FslSetDim(FSLIO *fslio, short x, short y, short z, short v) { int ndim; if (fslio==NULL) FSLIOERR("FslSetDim: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { ndim=4; if (v<=1) {ndim--; if (z<=1) {ndim--; if (y<=1) {ndim--; if (x<=1) {ndim--;}}}} fslio->niftiptr->ndim = ndim; if (x>=1) fslio->niftiptr->nx = x; else fslio->niftiptr->nx=1; if (y>=1) fslio->niftiptr->ny = y; else fslio->niftiptr->ny=1; if (z>=1) fslio->niftiptr->nz = z; else fslio->niftiptr->nz=1; if (v>=1) fslio->niftiptr->nt = v; else fslio->niftiptr->nt=1; fslio->niftiptr->nu = 1; fslio->niftiptr->nv = 1; fslio->niftiptr->nw = 1; /* deal with stupid redundancies */ fslio->niftiptr->dim[0] = fslio->niftiptr->ndim ; fslio->niftiptr->dim[1] = fslio->niftiptr->nx; fslio->niftiptr->dim[2] = fslio->niftiptr->ny; fslio->niftiptr->dim[3] = fslio->niftiptr->nz; fslio->niftiptr->dim[4] = fslio->niftiptr->nt; fslio->niftiptr->dim[5] = fslio->niftiptr->nu; fslio->niftiptr->dim[6] = fslio->niftiptr->nv; fslio->niftiptr->dim[7] = fslio->niftiptr->nw; fslio->niftiptr->nvox = fslio->niftiptr->nx * fslio->niftiptr->ny * fslio->niftiptr->nz * fslio->niftiptr->nt * fslio->niftiptr->nu * fslio->niftiptr->nv * fslio->niftiptr->nw ; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslGetDim(FSLIO *fslio, short *x, short *y, short *z, short *v) { if (fslio==NULL) FSLIOERR("FslGetDim: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { *x = fslio->niftiptr->nx; *y = fslio->niftiptr->ny; *z = fslio->niftiptr->nz; *v = fslio->niftiptr->nt; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslSetDimensionality(FSLIO *fslio, size_t dim) { if (fslio==NULL) FSLIOERR("FslSetDimensionality: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { fslio->niftiptr->ndim = dim; fslio->niftiptr->dim[0] = dim; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslGetDimensionality(FSLIO *fslio, size_t *dim) { if (fslio==NULL) FSLIOERR("FslGetDimensionality: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { *dim = fslio->niftiptr->ndim; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslSetVoxDim(FSLIO *fslio, float x, float y, float z, float tr) { if (fslio==NULL) FSLIOERR("FslSetVoxDim: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { fslio->niftiptr->dx = fabs(x); fslio->niftiptr->dy = fabs(y); fslio->niftiptr->dz = fabs(z); fslio->niftiptr->dt = fabs(tr); fslio->niftiptr->pixdim[1] = fabs(x); fslio->niftiptr->pixdim[2] = fabs(y); fslio->niftiptr->pixdim[3] = fabs(z); fslio->niftiptr->pixdim[4] = fabs(tr); /* set the units to mm and seconds */ fslio->niftiptr->xyz_units = NIFTI_UNITS_MM; fslio->niftiptr->time_units = NIFTI_UNITS_SEC; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslGetVoxDim(FSLIO *fslio, float *x, float *y, float *z, float *tr) { if (fslio==NULL) FSLIOERR("FslGetVoxDim: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { *x = fabs(fslio->niftiptr->dx); *y = fabs(fslio->niftiptr->dy); *z = fabs(fslio->niftiptr->dz); *tr = fabs(fslio->niftiptr->dt); /* now check the units and convert to mm and sec */ if (fslio->niftiptr->xyz_units == NIFTI_UNITS_METER) { *x *= 1000.0; *y *= 1000.0; *z *= 1000.0; } if (fslio->niftiptr->xyz_units == NIFTI_UNITS_MICRON) { *x /= 1000.0; *y /= 1000.0; *z /= 1000.0; } if (fslio->niftiptr->xyz_units == NIFTI_UNITS_MSEC) { *tr /= 1000.0; } if (fslio->niftiptr->xyz_units == NIFTI_UNITS_USEC) { *tr /= 1000000.0; } /* if it is Hz or other frequency then leave it */ } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslGetCalMinMax(FSLIO *fslio, float *min, float *max) { if (fslio==NULL) FSLIOERR("FslGetCalMinMax: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { *min = fslio->niftiptr->cal_min; *max = fslio->niftiptr->cal_max; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslSetCalMinMax(FSLIO *fslio, float min, float max) { if (fslio==NULL) FSLIOERR("FslSetCalMinMax: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { fslio->niftiptr->cal_min = min; fslio->niftiptr->cal_max = max; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslGetAuxFile(FSLIO *fslio,char *aux_file) { if (fslio==NULL) FSLIOERR("FslGetAuxFile: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { strncpy(aux_file,fslio->niftiptr->aux_file, 24); aux_file[23] = '\0'; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslSetAuxFile(FSLIO *fslio,const char *aux_file) { if (fslio==NULL) FSLIOERR("FslSetAuxFile: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { strncpy(fslio->niftiptr->aux_file, aux_file, 24); } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslSetVoxUnits(FSLIO *fslio, const char *units) { int unitcode=0; if (fslio==NULL) FSLIOERR("FslSetVoxUnits: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { if (strcmp(units,nifti_units_string(NIFTI_UNITS_METER))==0) { unitcode = NIFTI_UNITS_METER; } else if (strcmp(units,nifti_units_string(NIFTI_UNITS_MM))==0) { unitcode = NIFTI_UNITS_MM; } else if (strcmp(units,nifti_units_string(NIFTI_UNITS_MICRON))==0) { unitcode = NIFTI_UNITS_MICRON; } fslio->niftiptr->xyz_units = unitcode; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslGetVoxUnits(FSLIO *fslio, char *units) { if (fslio==NULL) FSLIOERR("FslGetVoxUnits: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { strcpy(units,nifti_units_string(fslio->niftiptr->xyz_units)); } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslSetTimeUnits(FSLIO *fslio, const char *units) { int unitcode=0; if (fslio==NULL) FSLIOERR("FslSetTimeUnits: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { if (strcmp(units,nifti_units_string(NIFTI_UNITS_HZ))==0) { unitcode = NIFTI_UNITS_HZ; } else if (strcmp(units,nifti_units_string(NIFTI_UNITS_PPM))==0) { unitcode = NIFTI_UNITS_PPM; } else if (strcmp(units,nifti_units_string(NIFTI_UNITS_RADS))==0) { unitcode = NIFTI_UNITS_RADS; } else if (strcmp(units,nifti_units_string(NIFTI_UNITS_SEC))==0) { unitcode = NIFTI_UNITS_SEC; } else if (strcmp(units,nifti_units_string(NIFTI_UNITS_MSEC))==0) { fprintf(stderr,"Warning::Setting time units to msec is not fully recommended in fslio\n"); unitcode = NIFTI_UNITS_MSEC; } else if (strcmp(units,nifti_units_string(NIFTI_UNITS_USEC))==0) { fprintf(stderr,"Warning::Setting time units to msec is not fully recommended in fslio\n"); unitcode = NIFTI_UNITS_USEC; } fslio->niftiptr->time_units = unitcode; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslGetTimeUnits(FSLIO *fslio, char *units) { if (fslio==NULL) FSLIOERR("FslGetTimeUnits: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { strcpy(units,nifti_units_string(fslio->niftiptr->time_units)); } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslSetDataType(FSLIO *fslio, short t) { int nbytepix=0, ss=0; if (fslio==NULL) FSLIOERR("FslSetDataType: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { fslio->niftiptr->datatype = t; nifti_datatype_sizes(t,&nbytepix,&ss); fslio->niftiptr->nbyper = nbytepix; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } size_t FslGetDataType(FSLIO *fslio, short *t) { /* returns bits per pixel */ int nbytepix=32, ss=0; if (fslio==NULL) FSLIOERR("FslGetDataType: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { *t = fslio->niftiptr->datatype; nifti_datatype_sizes(*t,&nbytepix,&ss); } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return (size_t) 8 * nbytepix; } void FslGetMMCoord(mat44 stdmat, float voxx, float voxy, float voxz, float *mmx, float *mmy, float *mmz) { *mmx = stdmat.m[0][0] * voxx + stdmat.m[0][1] * voxy + stdmat.m[0][2] * voxz + stdmat.m[0][3]; *mmy = stdmat.m[1][0] * voxx + stdmat.m[1][1] * voxy + stdmat.m[1][2] * voxz + stdmat.m[1][3]; *mmz = stdmat.m[2][0] * voxx + stdmat.m[2][1] * voxy + stdmat.m[2][2] * voxz + stdmat.m[2][3]; } void FslGetVoxCoord(mat44 stdmat, float mmx, float mmy, float mmz, float *voxx, float *voxy, float *voxz) { mat44 mm2vox; mm2vox = nifti_mat44_inverse(stdmat); *voxx = mm2vox.m[0][0] * mmx + mm2vox.m[0][1] * mmy + mm2vox.m[0][2] * mmz + mm2vox.m[0][3]; *voxy = mm2vox.m[1][0] * mmx + mm2vox.m[1][1] * mmy + mm2vox.m[1][2] * mmz + mm2vox.m[1][3]; *voxz = mm2vox.m[2][0] * mmx + mm2vox.m[2][1] * mmy + mm2vox.m[2][2] * mmz + mm2vox.m[2][3]; } void FslSetStdXform(FSLIO *fslio, short sform_code, mat44 stdmat) { /* NB: stdmat must point to a 4x4 array */ if (fslio==NULL) FSLIOERR("FslSetStdXform: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { fslio->niftiptr->sform_code = sform_code; fslio->niftiptr->sto_xyz.m[0][0] = stdmat.m[0][0]; fslio->niftiptr->sto_xyz.m[0][1] = stdmat.m[0][1]; fslio->niftiptr->sto_xyz.m[0][2] = stdmat.m[0][2]; fslio->niftiptr->sto_xyz.m[0][3] = stdmat.m[0][3]; fslio->niftiptr->sto_xyz.m[1][0] = stdmat.m[1][0]; fslio->niftiptr->sto_xyz.m[1][1] = stdmat.m[1][1]; fslio->niftiptr->sto_xyz.m[1][2] = stdmat.m[1][2]; fslio->niftiptr->sto_xyz.m[1][3] = stdmat.m[1][3]; fslio->niftiptr->sto_xyz.m[2][0] = stdmat.m[2][0]; fslio->niftiptr->sto_xyz.m[2][1] = stdmat.m[2][1]; fslio->niftiptr->sto_xyz.m[2][2] = stdmat.m[2][2]; fslio->niftiptr->sto_xyz.m[2][3] = stdmat.m[2][3]; fslio->niftiptr->sto_xyz.m[3][0] = 0; fslio->niftiptr->sto_xyz.m[3][1] = 0; fslio->niftiptr->sto_xyz.m[3][2] = 0; fslio->niftiptr->sto_xyz.m[3][3] = 1; fslio->niftiptr->sto_ijk = nifti_mat44_inverse(fslio->niftiptr->sto_xyz); } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } short FslGetStdXform(FSLIO *fslio, mat44 *stdmat) { /* returns sform code (NB: stdmat must point to a 4x4 array) */ float dx,dy,dz,tr; if (fslio==NULL) FSLIOERR("FslGetStdXform: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { stdmat->m[0][0] = fslio->niftiptr->sto_xyz.m[0][0]; stdmat->m[0][1] = fslio->niftiptr->sto_xyz.m[0][1]; stdmat->m[0][2] = fslio->niftiptr->sto_xyz.m[0][2]; stdmat->m[0][3] = fslio->niftiptr->sto_xyz.m[0][3]; stdmat->m[1][0] = fslio->niftiptr->sto_xyz.m[1][0]; stdmat->m[1][1] = fslio->niftiptr->sto_xyz.m[1][1]; stdmat->m[1][2] = fslio->niftiptr->sto_xyz.m[1][2]; stdmat->m[1][3] = fslio->niftiptr->sto_xyz.m[1][3]; stdmat->m[2][0] = fslio->niftiptr->sto_xyz.m[2][0]; stdmat->m[2][1] = fslio->niftiptr->sto_xyz.m[2][1]; stdmat->m[2][2] = fslio->niftiptr->sto_xyz.m[2][2]; stdmat->m[2][3] = fslio->niftiptr->sto_xyz.m[2][3]; stdmat->m[3][0] = 0.0; stdmat->m[3][1] = 0.0; stdmat->m[3][2] = 0.0; stdmat->m[3][3] = 1.0; /* the code below gives a default but it really should never be used */ if (fslio->niftiptr->sform_code == NIFTI_XFORM_UNKNOWN) { FslGetVoxDim(fslio,&dx,&dy,&dz,&tr); stdmat->m[0][0] = -dx; /* default Radiological convention */ stdmat->m[0][1] = 0; stdmat->m[0][2] = 0; stdmat->m[0][3] = 0; stdmat->m[1][0] = 0; stdmat->m[1][1] = dy; stdmat->m[1][2] = 0; stdmat->m[1][3] = 0; stdmat->m[2][0] = 0; stdmat->m[2][1] = 0; stdmat->m[2][2] = dz; stdmat->m[2][3] = 0; stdmat->m[3][0] = 0.0; stdmat->m[3][1] = 0.0; stdmat->m[3][2] = 0.0; stdmat->m[3][3] = 1.0; } return fslio->niftiptr->sform_code; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return NIFTI_XFORM_UNKNOWN; } void FslSetRigidXform(FSLIO *fslio, short qform_code, mat44 rigidmat) { /* NB: rigidmat must point to an allocated mat44 */ float dx, dy, dz; if (fslio==NULL) FSLIOERR("FslSetRigidXform: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { fslio->niftiptr->qform_code = qform_code; fslio->niftiptr->qto_xyz.m[0][0] = rigidmat.m[0][0]; fslio->niftiptr->qto_xyz.m[0][1] = rigidmat.m[0][1]; fslio->niftiptr->qto_xyz.m[0][2] = rigidmat.m[0][2]; fslio->niftiptr->qto_xyz.m[0][3] = rigidmat.m[0][3]; fslio->niftiptr->qto_xyz.m[1][0] = rigidmat.m[1][0]; fslio->niftiptr->qto_xyz.m[1][1] = rigidmat.m[1][1]; fslio->niftiptr->qto_xyz.m[1][2] = rigidmat.m[1][2]; fslio->niftiptr->qto_xyz.m[1][3] = rigidmat.m[1][3]; fslio->niftiptr->qto_xyz.m[2][0] = rigidmat.m[2][0]; fslio->niftiptr->qto_xyz.m[2][1] = rigidmat.m[2][1]; fslio->niftiptr->qto_xyz.m[2][2] = rigidmat.m[2][2]; fslio->niftiptr->qto_xyz.m[2][3] = rigidmat.m[2][3]; fslio->niftiptr->qto_xyz.m[3][0] = 0; fslio->niftiptr->qto_xyz.m[3][1] = 0; fslio->niftiptr->qto_xyz.m[3][2] = 0; fslio->niftiptr->qto_xyz.m[3][3] = 1; nifti_mat44_to_quatern( fslio->niftiptr->qto_xyz,&(fslio->niftiptr->quatern_b), &(fslio->niftiptr->quatern_c),&(fslio->niftiptr->quatern_d), &(fslio->niftiptr->qoffset_x),&(fslio->niftiptr->qoffset_y), &(fslio->niftiptr->qoffset_z),&dx,&dy,&dz,&(fslio->niftiptr->qfac)); fslio->niftiptr->qto_ijk = nifti_mat44_inverse(fslio->niftiptr->qto_xyz); } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } short FslGetRigidXform(FSLIO *fslio, mat44 *rigidmat) { /* returns qform code (NB: rigidmat must point to an allocated mat44) */ float dx,dy,dz,tr; if (fslio==NULL) FSLIOERR("FslGetRigidXform: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { rigidmat->m[0][0] = fslio->niftiptr->qto_xyz.m[0][0]; rigidmat->m[0][1] = fslio->niftiptr->qto_xyz.m[0][1]; rigidmat->m[0][2] = fslio->niftiptr->qto_xyz.m[0][2]; rigidmat->m[0][3] = fslio->niftiptr->qto_xyz.m[0][3]; rigidmat->m[1][0] = fslio->niftiptr->qto_xyz.m[1][0]; rigidmat->m[1][1] = fslio->niftiptr->qto_xyz.m[1][1]; rigidmat->m[1][2] = fslio->niftiptr->qto_xyz.m[1][2]; rigidmat->m[1][3] = fslio->niftiptr->qto_xyz.m[1][3]; rigidmat->m[2][0] = fslio->niftiptr->qto_xyz.m[2][0]; rigidmat->m[2][1] = fslio->niftiptr->qto_xyz.m[2][1]; rigidmat->m[2][2] = fslio->niftiptr->qto_xyz.m[2][2]; rigidmat->m[2][3] = fslio->niftiptr->qto_xyz.m[2][3]; rigidmat->m[3][0] = 0.0; rigidmat->m[3][1] = 0.0; rigidmat->m[3][2] = 0.0; rigidmat->m[3][3] = 1.0; /* the code gives a default but it should never really be used */ if (fslio->niftiptr->sform_code == NIFTI_XFORM_UNKNOWN) { FslGetVoxDim(fslio,&dx,&dy,&dz,&tr); rigidmat->m[0][0] = dx; rigidmat->m[0][1] = 0; rigidmat->m[0][2] = 0; rigidmat->m[0][3] = 0; rigidmat->m[1][0] = 0; rigidmat->m[1][1] = dy; rigidmat->m[1][2] = 0; rigidmat->m[1][3] = 0; rigidmat->m[2][0] = 0; rigidmat->m[2][1] = 0; rigidmat->m[2][2] = dz; rigidmat->m[3][0] = 0.0; rigidmat->m[3][1] = 0.0; rigidmat->m[3][2] = 0.0; rigidmat->m[3][3] = 1.0; } return fslio->niftiptr->qform_code; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return NIFTI_XFORM_UNKNOWN; } void FslSetIntent(FSLIO *fslio, short intent_code, float p1, float p2, float p3) { if (fslio==NULL) FSLIOERR("FslSetIntent: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { fslio->niftiptr->intent_code = intent_code; fslio->niftiptr->intent_p1 = p1; fslio->niftiptr->intent_p2 = p2; fslio->niftiptr->intent_p3 = p3; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } short FslGetIntent(FSLIO *fslio, short *intent_code, float *p1, float *p2, float *p3) { /* also returns intent code */ if (fslio==NULL) FSLIOERR("FslGetIntent: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { *intent_code = fslio->niftiptr->intent_code; *p1 = fslio->niftiptr->intent_p1; *p2 = fslio->niftiptr->intent_p2; *p3 = fslio->niftiptr->intent_p3; return fslio->niftiptr->intent_code; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return NIFTI_INTENT_NONE; } void FslSetIntensityScaling(FSLIO *fslio, float slope, float intercept) { if (fslio==NULL) FSLIOERR("FslSetIntensityScaling: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { fslio->niftiptr->scl_slope = slope; fslio->niftiptr->scl_inter = intercept; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } int FslGetIntensityScaling(FSLIO *fslio, float *slope, float *intercept) { /* returns 1 if scaling required or 0 otherwise */ if (fslio==NULL) FSLIOERR("FslGetIntensityScaling: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { *slope = fslio->niftiptr->scl_slope; *intercept = fslio->niftiptr->scl_inter; if (fabs(*slope)<1e-30) { *slope = 1.0; *intercept = 0.0; return 0; } if ( (fabs(*slope - 1.0)>1e-30) || (fabs(*intercept)>1e-30) ) { return 1; } else { return 0; } } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return 0; } mat33 mat44_to_mat33(mat44 x) { mat33 y; int i,j; for (i=0; i<3; i++) { for (j=0; j<3; j++) { y.m[i][j] = x.m[i][j]; } } return y; } int FslGetLeftRightOrder(FSLIO *fslio) { /* Determines if the image is stored in neurological or radiological convention */ int order=FSL_RADIOLOGICAL, sform_code, qform_code; float det=-1.0; mat44 sform44, qform44; mat33 sform33, qform33; if (fslio==NULL) FSLIOERR("FslGetLeftRightOrder: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { sform_code = FslGetStdXform(fslio,&sform44); qform_code = FslGetRigidXform(fslio,&qform44); if (sform_code!=NIFTI_XFORM_UNKNOWN) { sform33 = mat44_to_mat33(sform44); det = nifti_mat33_determ(sform33); } else if (qform_code!=NIFTI_XFORM_UNKNOWN) { qform33 = mat44_to_mat33(qform44); det = nifti_mat33_determ(qform33); } if (det<0.0) order=FSL_RADIOLOGICAL; else order=FSL_NEUROLOGICAL; } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return order; } void FslSetAnalyzeSform(FSLIO *fslio, const short *orig, float dx, float dy, float dz) { /* Creates an sform matrix for an Analyze file */ /* THIS ALWAYS CREATES A RADIOLOGICAL ORDERED SFORM */ /* NB: the origin passed in here is in Analyze convention - starting at 1, not 0 */ float x, y, z; if (fslio==NULL) FSLIOERR("FslSetAnalyzeSform: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { if (FslBaseFileType(FslGetFileType(fslio))==FSL_TYPE_ANALYZE) { /* default case */ fslio->niftiptr->sform_code = NIFTI_XFORM_UNKNOWN; } /* ignore all zero origins - really all serious coord stuff should be done via the FslSetStdCoord call */ if ((orig[0]!=0) || (orig[1]!=0) || (orig[2]!=0)) { short origx=0, origy=0, origz=0; if ((orig[0]!=0) || (orig[1]!=0) || (orig[2]!=0)) { /* convert to nifti conventions (start at 0 not 1) */ origx = orig[0] - 1; origy = orig[1] - 1; origz = orig[2] - 1; } if ( dx * dy * dz > 0 ) { /* change neurological convention to radiological if necessary */ dx = -dx; } if ( (FslBaseFileType(FslGetFileType(fslio))==FSL_TYPE_ANALYZE) || (fslio->niftiptr->sform_code == NIFTI_XFORM_UNKNOWN) ) { /* make a default transform with the requested origin at xyz=000 */ fslio->niftiptr->sform_code = NIFTI_XFORM_ALIGNED_ANAT; fslio->niftiptr->sto_xyz.m[0][0] = dx; fslio->niftiptr->sto_xyz.m[0][1] = 0; fslio->niftiptr->sto_xyz.m[0][2] = 0; fslio->niftiptr->sto_xyz.m[0][3] = -(origx)*(dx); fslio->niftiptr->sto_xyz.m[1][0] = 0; fslio->niftiptr->sto_xyz.m[1][1] = dy; fslio->niftiptr->sto_xyz.m[1][2] = 0; fslio->niftiptr->sto_xyz.m[1][3] = -(origy)*(dy); fslio->niftiptr->sto_xyz.m[2][0] = 0; fslio->niftiptr->sto_xyz.m[2][1] = 0; fslio->niftiptr->sto_xyz.m[2][2] = dz; fslio->niftiptr->sto_xyz.m[2][3] = -(origz)*(dz); fslio->niftiptr->sto_xyz.m[3][0] = 0; fslio->niftiptr->sto_xyz.m[3][1] = 0; fslio->niftiptr->sto_xyz.m[3][2] = 0; fslio->niftiptr->sto_xyz.m[3][3] = 1; fslio->niftiptr->sto_ijk = nifti_mat44_inverse(fslio->niftiptr->sto_xyz); } else { /* update the existing origin */ /* find out what the existing xyz of the requested origin is */ x = fslio->niftiptr->sto_xyz.m[0][0] * origx + fslio->niftiptr->sto_xyz.m[0][1] * origy + fslio->niftiptr->sto_xyz.m[0][2] * origz + fslio->niftiptr->sto_xyz.m[0][3]; y = fslio->niftiptr->sto_xyz.m[1][0] * origx + fslio->niftiptr->sto_xyz.m[1][1] * origy + fslio->niftiptr->sto_xyz.m[1][2] * origz + fslio->niftiptr->sto_xyz.m[1][3]; z = fslio->niftiptr->sto_xyz.m[2][0] * origx + fslio->niftiptr->sto_xyz.m[2][1] * origy + fslio->niftiptr->sto_xyz.m[2][2] * origz + fslio->niftiptr->sto_xyz.m[2][3]; /* subtract off whatever is currently the xyz of the origin */ fslio->niftiptr->sto_xyz.m[0][3] -= x; fslio->niftiptr->sto_xyz.m[1][3] -= y; fslio->niftiptr->sto_xyz.m[2][3] -= z; fslio->niftiptr->sto_ijk = nifti_mat44_inverse(fslio->niftiptr->sto_xyz); } } } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } void FslGetAnalyzeOrigin(FSLIO *fslio, short orig[5]) { /* NB: orig returned here is in Analyze convention - starting at 1, not 0 */ if (fslio==NULL) FSLIOERR("FslGetAnalyzeOrigin: Null pointer passed for FSLIO"); if (fslio->niftiptr!=NULL) { /* Use sform or qform to determine the origin - default is zero */ orig[0]=0; orig[1]=0; orig[2]=0; orig[3]=0; orig[4]=0; if (fslio->niftiptr->qform_code != NIFTI_XFORM_UNKNOWN) { orig[0]=(short) fslio->niftiptr->qto_ijk.m[0][3] + 1; orig[1]=(short) fslio->niftiptr->qto_ijk.m[1][3] + 1; orig[2]=(short) fslio->niftiptr->qto_ijk.m[2][3] + 1; } if (fslio->niftiptr->sform_code != NIFTI_XFORM_UNKNOWN) { orig[0]=(short) fslio->niftiptr->sto_ijk.m[0][3] + 1; orig[1]=(short) fslio->niftiptr->sto_ijk.m[1][3] + 1; orig[2]=(short) fslio->niftiptr->sto_ijk.m[2][3] + 1; } } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } } /*************************************************************** * FslClose ***************************************************************/ /*! \fn int FslClose(FSLIO *fslio) \brief Write header and image data if this dataset was open for writing. Close the dataset header and data files. \param fslio pointer to FSLIO data structure \return -1 on error, 0 OK ???. */ int FslClose(FSLIO *fslio) { int retval=0, filetype; struct dsr *hdr; znzFile hptr=NULL; if (fslio==NULL) return 0; /* close the (data) file */ if (!znz_isnull(fslio->fileptr)) retval=znzclose(fslio->fileptr); /** ----- if writing the image, need to worry about the header bit ----- **/ if ( (fslio->niftiptr!=NULL) && (FslGetWriteMode(fslio)==1) && (fslio->written_hdr==0) ) { /* ensure that the type is set correctly */ fslio->niftiptr->nifti_type = FslBaseFileType(FslGetFileType(fslio)); /* must write the header now */ filetype = FslGetFileType(fslio); strcpy(fslio->niftiptr->descrip,"FSL3.2beta"); if (!FslIsSingleFileType(filetype)) { /* for file pairs - open new header file and write it */ nifti_image_write_hdr_img(fslio->niftiptr,0,"wb"); } else { /* for single files it is more complicated */ if (!FslIsCompressedFileType(filetype)) { /* noncompressed -> reopen this file in r+ mode and write the header part again */ nifti_image_write_hdr_img(fslio->niftiptr,0,"r+b"); } else { /* compressed mode -> not possible! */ fprintf(stderr,"Error:: header must be written before writing any other data.\n"); return -1; } } } /* --- nasty hack to write the origin in Analyze files --- */ if ( (FslGetWriteMode(fslio)==1) && (fslio->niftiptr!=NULL) && (FslBaseFileType(FslGetFileType(fslio))==FSL_TYPE_ANALYZE) ) { /* read in the old header, change the origin and write it out again */ hdr = (struct dsr *) calloc(1,sizeof(struct dsr)); FslReadRawHeader(hdr,fslio->niftiptr->fname); if (fslio->niftiptr->byteorder != nifti_short_order()) {AvwSwapHeader(hdr);} /* calculate origin from sform (if set) */ { short blah[5]; FslGetAnalyzeOrigin(fslio,blah); memcpy(hdr->hist.originator,blah,5*sizeof(short)); /* Write out in radiological order if origin is non-zero */ /* set negative pixdim if needed to keep LR orientation consistent */ if ( (blah[0]!=0) || (blah[1]!=0) || (blah[2]!=0) ) { if (hdr->dime.pixdim[1] * hdr->dime.pixdim[2] * hdr->dime.pixdim[3] > 0) { hdr->dime.pixdim[1] = - hdr->dime.pixdim[1]; } } } /* swap back byte order and write out */ if (fslio->niftiptr->byteorder != nifti_short_order()) {AvwSwapHeader(hdr);} hptr = znzopen(fslio->niftiptr->fname,"wb",FslIsCompressedFileType(FslGetFileType(fslio))); if (znz_isnull(hptr)) { free(hdr); fprintf(stderr,"Error:: Could not write origin data to header file %s.\n", fslio->niftiptr->fname); return -1; }; znzwrite(hdr,1,sizeof(struct dsr),hptr); znzclose(hptr); free(hdr); } if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); return -1; } return retval; } void AvwSwapHeader(struct dsr *avw) { char *ptr; ptr = (char *) &(avw->hk); nifti_swap_4bytes(1,ptr); /* sizeof_hdr */ ptr += 32; nifti_swap_4bytes(1,ptr); /* extents */ ptr += 4; nifti_swap_2bytes(1,ptr); /* session_error */ ptr = (char *) &(avw->dime); nifti_swap_2bytes(8,ptr); /* dims */ ptr += 28; nifti_swap_2bytes(4,ptr); /* unused1, datatype, bitpix, dim_un0 */ ptr += 8; nifti_swap_4bytes(18,ptr); /* pixdim, vox_offset, ... */ /* cal_min, compressed, ... glmin */ ptr = (char *) &(avw->hist); ptr += 105; nifti_swap_2bytes(5,ptr); /* originator (used to store origin) */ ptr += 63; nifti_swap_4bytes(8,ptr); /* views, ... smin */ } int FslReadRawHeader(void *buffer, const char* filename) { znzFile fp; int retval; fp = znzopen(filename,"rb",1); if (znz_isnull(fp)) { fprintf(stderr,"Could not open header %s\n",filename); return 0; } retval = znzread(buffer,1,348,fp); znzclose(fp); if (retval != 348) { fprintf(stderr,"Could not read header %s\n",filename); return retval; } return retval; } void FslSetOverrideOutputType(int type) { if ( (type==-1) || (FslIsValidFileType(type)) ) { FslOverrideOutputType=type; } else { fprintf(stderr,"Invalid file type (%d) requested - ignoring this\n",type); } } int FslGetOverrideOutputType(void) { return FslOverrideOutputType; } void FslSetIgnoreMFQ(int flag) { assert((flag==0) || (flag==1)); FslIgnoreMFQ=flag; } int FslGetIgnoreMFQ(void) { return FslIgnoreMFQ; } /*************************************************************** * FslReadHeader ***************************************************************/ /*! \fn FSLIO * FslReadHeader(char *fname) \brief Reads nifti/anz header, no data is read \param fname filename specification (could be .img,.hdr,.nii, or no ext \return FSLIO data structure with the nifti_image structure fields filled as per fname header. NULL on error */ FSLIO * FslReadHeader(char *fname) { char *hdrname, *imgname; FSLIO *fslio; fslio = FslInit(); /** get header file name */ FslGetHdrImgNames(fname, fslio, &hdrname, &imgname); /** read header information */ fslio->niftiptr = nifti_image_read(hdrname, 0); if( imgname ) free(imgname); if( hdrname ) free(hdrname); if (fslio->niftiptr == NULL) { FSLIOERR("FslReadHeader: error reading header information"); return(NULL); } fslio->file_mode = FslGetReadFileType(fslio); return(fslio); } /*************************************************************** * FslGetVolumeAsScaledDouble ***************************************************************/ /*! \fn double *** FslGetVolumeAsScaledDouble(FSLIO *fslio, int vol) \brief Return volume #vol (0-based) as a 3D array of scaled doubles. Volume Array is indexed as [0..zdim-1][0..ydim-1][0..xdim-1].
The array will be byteswapped to native-endian.
Array values are scaled as per fslio header slope and intercept fields. \param fslio pointer to open dataset \param vol volume number to read (legal range [0..tdim-1]) \return Pointer to 3D double array, NULL on error */ double ***FslGetVolumeAsScaledDouble(FSLIO *fslio, int vol) { double ***newbuf; void *diskbuf; int xx,yy,zz; int ret; float inter, slope; int dims_to_get[8]; int i; if (fslio==NULL) FSLIOERR("FslGetVolumeAsScaledDouble: Null pointer passed for FSLIO"); if ((fslio->niftiptr->dim[0] < 3) || (fslio->niftiptr->dim[0] > 4)) FSLIOERR("FslGetVolumeAsScaledDouble: Incorrect dataset dimension, 3D-4D needed"); /***** nifti dataset */ if (fslio->niftiptr!=NULL) { xx = (fslio->niftiptr->nx == 0 ? 1 : (long)fslio->niftiptr->nx); yy = (fslio->niftiptr->ny == 0 ? 1 : (long)fslio->niftiptr->ny); zz = (fslio->niftiptr->nz == 0 ? 1 : (long)fslio->niftiptr->nz); if (fslio->niftiptr->scl_slope == 0) { slope = 1.0; inter = 0.0; } else { slope = fslio->niftiptr->scl_slope; inter = fslio->niftiptr->scl_inter; } /** allocate new 3D buffer */ newbuf = d3matrix(zz-1,yy-1,xx-1); /** read in the data in disk format */ dims_to_get[0] = 0; for (i=1; i<8; i++) dims_to_get[i] = -1; dims_to_get[4] = vol; diskbuf = NULL; ret = nifti_read_collapsed_image(fslio->niftiptr, dims_to_get, &diskbuf ); if (ret <= 0) { fprintf(stderr,"ERROR:: read of disk buffer for volume %d from %s failed.\n",vol,fslio->niftiptr->iname); return(NULL); } /** cvt disk buffer to scaled double buffer */ ret = convertBufferToScaledDouble(newbuf[0][0], diskbuf, (long)(xx*yy*zz), slope, inter, fslio->niftiptr->datatype); free(diskbuf); if (ret == 0) return(newbuf); else return(NULL); } /* nifti data */ if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return(NULL); } /*************************************************************** * FslGetBufferAsScaledDouble ***************************************************************/ /*! \fn double **** FslGetBufferAsScaledDouble(FSLIO *fslio) \brief Return the fslio data buffer of a 1-4D dataset as a 4D array of scaled doubles. Array is indexed as buf[0..tdim-1][0..zdim-1][0..ydim-1][0..xdim-1].
The array will be byteswapped to native-endian.
Array values are scaled as per fslio header slope and intercept fields. \param fslio pointer to open dataset \return Pointer to 4D double array, NULL on error */ double ****FslGetBufferAsScaledDouble(FSLIO *fslio) { double ****newbuf; int xx,yy,zz,tt; int ret; float inter, slope; if (fslio==NULL) FSLIOERR("FslGetBufferAsScaledDouble: Null pointer passed for FSLIO"); if ((fslio->niftiptr->dim[0] <= 0) || (fslio->niftiptr->dim[0] > 4)) FSLIOERR("FslGetBufferAsScaledDouble: Incorrect dataset dimension, 1-4D needed"); /***** nifti dataset */ if (fslio->niftiptr!=NULL) { xx = (fslio->niftiptr->nx == 0 ? 1 : (long)fslio->niftiptr->nx); yy = (fslio->niftiptr->ny == 0 ? 1 : (long)fslio->niftiptr->ny); zz = (fslio->niftiptr->nz == 0 ? 1 : (long)fslio->niftiptr->nz); tt = (fslio->niftiptr->nt == 0 ? 1 : (long)fslio->niftiptr->nt); if (fslio->niftiptr->scl_slope == 0) { slope = 1.0; inter = 0.0; } else { slope = fslio->niftiptr->scl_slope; inter = fslio->niftiptr->scl_inter; } /** allocate new 4D buffer */ newbuf = d4matrix(tt-1,zz-1,yy-1,xx-1); /** cvt it */ ret = convertBufferToScaledDouble(newbuf[0][0][0], fslio->niftiptr->data, (long)(xx*yy*zz*tt), slope, inter, fslio->niftiptr->datatype); if (ret == 0) return(newbuf); else { free(newbuf); return(NULL); } } /* nifti data */ if (fslio->mincptr!=NULL) { fprintf(stderr,"Warning:: Minc is not yet supported\n"); } return(NULL); } /*************************************************************** * convertBufferToScaledDouble ***************************************************************/ /*! \fn int convertBufferToScaledDouble(double *outbuf, void *inbuf, long len, float slope, float inter, int nifti_datatype ) \brief allocate a 4D buffer, use 1 contiguous buffer for the data Array is indexed as buf[0..th-1][0..zh-1][0..yh-1][0..xh-1].
To access all elements as a vector, use buf[0][0][0][i] where i can range from 0 to th*zh*yh*xh - 1. \param outbuf pointer to array of doubles of size len \param inbuf void pointer to an array of len items of datatype nifti_datatype \param len number of elements in outbuf and inbuf \param slope slope term of scaling to be applied \param inter intercept term of scaling to be applied: out = (in*slope)+inter \param nifti_datatype NIFTI datatype code for the datatype of the elements in inbuf \return error code: 0=OK -1=error */ int convertBufferToScaledDouble(double *outbuf, void *inbuf, long len, float slope, float inter, int nifti_datatype ) { long i; /** fill the buffer */ for (i=0; iTo access all elements as a vector, use buf[0][0][i] where i can range from 0 to zh*yh*xh - 1. Adaptation of Numerical Recipes in C nrutil.c allocation routines. \param zh slowest changing dimension \param yh 2nd fastest changing dimension \param xh fastest changing dimension \return Pointer to 3D double array */ double ***d3matrix(int zh, int yh, int xh) { int j; int nslice = zh+1; int nrow = yh+1; int ncol = xh+1; double ***t; /** allocate pointers to slices */ t=(double ***) malloc((size_t)((nslice)*sizeof(double**))); if (!t) FSLIOERR("d3matrix: allocation failure"); /** allocate pointers for ydim */ t[0]=(double **) malloc((size_t)((nslice*nrow)*sizeof(double*))); if (!t[0]) FSLIOERR("d3matrix: allocation failure"); /** allocate the data blob */ t[0][0]=(double *) malloc((size_t)((nslice*nrow*ncol)*sizeof(double))); if (!t[0][0]) FSLIOERR("d3matrix: allocation failure"); /** point everything to the data blob */ for(j=1;jTo access all elements as a vector, use buf[0][0][0][i] where i can range from 0 to th*zh*yh*xh - 1. Adaptation of Numerical Recipes in C nrutil.c allocation routines. \param th slowest changing dimension \param zh 2nd slowest changing dimension \param yh 2nd fastest changing dimension \param xh fastest changing dimension \return Pointer to 4D double array */ double ****d4matrix(int th, int zh, int yh, int xh) { int j; int nvol = th+1; int nslice = zh+1; int nrow = yh+1; int ncol = xh+1; double ****t; /** allocate pointers to vols */ t=(double ****) malloc((size_t)((nvol)*sizeof(double***))); if (!t) FSLIOERR("d4matrix: allocation failure"); /** allocate pointers to slices */ t[0]=(double ***) malloc((size_t)((nvol*nslice)*sizeof(double**))); if (!t[0]) FSLIOERR("d4matrix: allocation failure"); /** allocate pointers for ydim */ t[0][0]=(double **) malloc((size_t)((nvol*nslice*nrow)*sizeof(double*))); if (!t[0][0]) FSLIOERR("d4matrix: allocation failure"); /** allocate the data blob */ t[0][0][0]=(double *) malloc((size_t)((nvol*nslice*nrow*ncol)*sizeof(double))); if (!t[0][0][0]) FSLIOERR("d4matrix: allocation failure"); /** point everything to the data blob */ for(j=1;j #include #include #include "dbh.h" #ifdef __cplusplus extern "C" { #endif /* Note that this library is similar to avwio but has changed in many ways. It is almost fully backwards compatible, but not quite, as it cannot write .nii.gz files using the old style functions. Recommended ways of reading and writing images are: Reading ------- Use the FslOpen(), FslReadVolumes() and FslClose() functions. e.g. FSLIO *fslio; void *buffer; int nvols; fslio = FslOpen("/some/path/name_of_file","rb"); ... can now access header info via the FslGet calls ... ... allocate room for buffer ... FslReadVolumes(fslio,buffer,nvols); ... do something ... FslClose(fslio); Writing ------- This is more complicated due to the nature of gzipped writing, which must be done in the correct order, and for single files (*.nii.gz) this means that the header information must be written before any image data. (1) The best method to use is almost backwards compatible, but requires an FslWriteHeader() call: FSLIO* fslio; fslio = FslOpen("/some/path/name_of_file","wb"); ... set the appropriate header information using FslSet calls ... FslWriteHeader(fslio); ... now can write one or more volumes at a time using FslWriteVolumes(fslio,buffer,nvols) ... FslClose(fslio); This version is useful if your image data needs to be written from different blocks of memory. (2) Another method is available, but which is discouraged, is: FSLIO* fslio; fslio = FslOpen("/some/path/name_of_file","wb"); ... set some appropriate header information using FslSet calls ... ... now can write one or more volumes at a time using FslWriteVolumes(fslio,buffer,nvols) ... ... set more appropriate header information using FslSet calls ... FslClose(fslio); WARNING: this cannot write .nii.gz files as the header information cannot be written by FslClose() after the image data is written, which is how the previous versions have worked. */ /*! \defgroup FSL_TYPE \brief FSL data format type codes @{ */ #define FSL_TYPE_ANALYZE 0 #define FSL_TYPE_NIFTI 1 #define FSL_TYPE_NIFTI_PAIR 2 #define FSL_TYPE_MINC 4 #define FSL_TYPE_ANALYZE_GZ 100 #define FSL_TYPE_NIFTI_GZ 101 #define FSL_TYPE_NIFTI_PAIR_GZ 102 #define FSL_TYPE_MINC_GZ 104 /* @} */ #define FSL_RADIOLOGICAL -1 #define FSL_NEUROLOGICAL 1 /*! \struct FSLIO \brief High level data structure for open datasets in the fslio API. \sa nifti_image \sa minc_image */ typedef struct { znzFile fileptr; nifti_image *niftiptr; #ifdef USE_MINC minc_image *mincptr; #else void *mincptr; #endif int file_mode; int write_mode; int written_hdr; } FSLIO; /* basic file i/o commands */ FSLIO *FslOpen(const char *filename, const char *opts); FSLIO *FslXOpen(const char *filename, const char *opts, int filetype); int FslSeekVolume(FSLIO *fslio, size_t vols); int FslClose(FSLIO *fslio); /* basic read and write commands */ void* FslReadAllVolumes(FSLIO* fslio, char* filename); void FslWriteAllVolumes(FSLIO *fslio, const void *buffer); size_t FslReadVolumes(FSLIO *fslio, void *buffer, size_t nvols); size_t FslWriteVolumes(FSLIO *fslio, const void *buffer, size_t nvols); void FslWriteHeader(FSLIO *fslio); /* support functions for file names and types */ int FslFileExists(const char *filename); char *FslMakeBaseName(const char *fname); int FslCheckForMultipleFileNames(const char* filename); int FslGetEnvOutputType(void); void FslSetIgnoreMFQ(int flag); int FslGetIgnoreMFQ(void); void FslSetOverrideOutputType(int type); int FslGetOverrideOutputType(void); int FslGetFileType(const FSLIO *fslio); void FslSetFileType(FSLIO *fslio, int filetype); int FslIsSingleFileType(int filetype); int FslIsCompressedFileType(int filetype); int FslBaseFileType(int filetype); const char* FslFileTypeString(int filetype); int FslGetWriteMode(const FSLIO *fslio); void FslSetWriteMode(FSLIO *fslio, int mode); void AvwSwapHeader(struct dsr *avw); int FslReadRawHeader(void *buffer, const char* filename); /* simple creation and clone/copy operations */ FSLIO *FslInit(void); void FslInitHeader(FSLIO *fslio, short t, size_t x, size_t y, size_t z, size_t v, float vx, float vy, float vz, float tr, size_t dim); void FslSetInit(FSLIO* fslio); void FslCloneHeader(FSLIO *dest, const FSLIO *src); /* get and set routines for properties */ size_t FslGetVolSize(FSLIO *fslio); void FslSetDim(FSLIO *fslio, short x, short y, short z, short v); void FslGetDim(FSLIO *fslio, short *x, short *y, short *z, short *v); void FslSetDimensionality(FSLIO *fslio, size_t dim); void FslGetDimensionality(FSLIO *fslio, size_t *dim); void FslSetVoxDim(FSLIO *fslio, float x, float y, float z, float tr); void FslGetVoxDim(FSLIO *fslio, float *x, float *y, float *z, float *tr); void FslGetCalMinMax(FSLIO *fslio, float *min, float *max); void FslSetCalMinMax(FSLIO *fslio, float min, float max); void FslGetAuxFile(FSLIO *fslio,char *aux_file); void FslSetAuxFile(FSLIO *fslio,const char *aux_file); void FslSetTimeUnits(FSLIO *fslio, const char *units); void FslGetTimeUnits(FSLIO *fslio, char *units); void FslSetDataType(FSLIO *fslio, short t); size_t FslGetDataType(FSLIO *fslio, short *t); int FslGetIntensityScaling(FSLIO *fslio, float *slope, float *intercept); void FslSetIntent(FSLIO *fslio, short intent_code, float p1, float p2, float p3); short FslGetIntent(FSLIO *fslio, short *intent_code, float *p1, float *p2, float *p3); short FslGetStdXform(FSLIO *fslio, mat44 *stdmat); void FslSetStdXform(FSLIO *fslio, short sform_code, mat44 stdmat); void FslGetMMCoord(mat44 stdmat, float voxx, float voxy, float voxz, float *mmx, float *mmy, float *mmz); void FslGetVoxCoord(mat44 stdmat, float mmx, float mmy, float mmz, float *voxx, float *voxy, float *voxz); short FslGetRigidXform(FSLIO *fslio, mat44 *rigidmat); void FslSetRigidXform(FSLIO *fslio, short qform_code, mat44 rigidmat); int FslGetLeftRightOrder(FSLIO *fslio); /* these two functions are deprecated with the nifti/analyze support */ /* please do all spatial coordinate origins via the Std and Rigid Xforms */ void FslSetAnalyzeSform(FSLIO *fslio, const short *orig, float dx, float dy, float dz); void FslGetAnalyzeOrigin(FSLIO *fslio, short orig[5]); /* other read and write commands */ size_t FslReadSliceSeries(FSLIO *fslio, void *buffer,short slice, size_t nvols); size_t FslReadRowSeries(FSLIO *fslio, void *buffer, short row, short slice, size_t nvols); size_t FslReadTimeSeries(FSLIO *fslio, void *buffer, short xVox, short yVox, short zVox, size_t nvols); /* miscellaneous helper stuff */ mat33 mat44_to_mat33(mat44 x); /* added by KF pending discussion w/ Mark */ typedef unsigned char THIS_UINT8; typedef char THIS_INT8; typedef unsigned short THIS_UINT16; typedef short THIS_INT16; typedef unsigned int THIS_UINT32; typedef int THIS_INT32; typedef unsigned long THIS_UINT64; typedef long THIS_INT64; typedef float THIS_FLOAT32; typedef double THIS_FLOAT64; FSLIO * FslReadHeader(char *fname); double ****FslGetBufferAsScaledDouble(FSLIO *fslio); double ***FslGetVolumeAsScaledDouble(FSLIO *fslio, int vol); int convertBufferToScaledDouble(double *outbuf, void *inbuf, long len, float slope, float inter, int nifti_datatype ) ; double ****d4matrix(int th, int zh, int yh, int xh); double ***d3matrix(int zh, int yh, int xh); #ifdef __cplusplus } #endif #endif nifti_clib-3.0.1/fsliolib/fslio.tcl000066400000000000000000000034051371325713600172520ustar00rootroot00000000000000#{{{ copyright and setup # FEAT TCL FSLIO wrappers # # Stephen Smith, FMRIB Image Analysis Group # # # # The fslio.tcl file was originally part of FSL - FMRIB's Software Library # http://www.fmrib.ox.ac.uk/fsl # fslio.tcl has now been placed in the public domain. # # Developed at FMRIB (Oxford Centre for Functional Magnetic Resonance # Imaging of the Brain), Department of Clinical Neurology, Oxford # University, Oxford, UK # # #}}} proc imcp { args } { global FSLDIR regsub -all "\{" $args "" cleanedargs regsub -all "\}" $cleanedargs "" cleanedargs return [ exec sh -c "${FSLDIR}/bin/imcp $args" ] } proc imglob { args } { global FSLDIR regsub -all "\{" $args "" cleanedargs regsub -all "\}" $cleanedargs "" cleanedargs return [ exec sh -c "${FSLDIR}/bin/imglob $args" ] } proc imln { args } { global FSLDIR regsub -all "\{" $args "" cleanedargs regsub -all "\}" $cleanedargs "" cleanedargs return [ exec sh -c "${FSLDIR}/bin/imln $args" ] } proc immv { args } { global FSLDIR regsub -all "\{" $args "" cleanedargs regsub -all "\}" $cleanedargs "" cleanedargs return [ exec sh -c "${FSLDIR}/bin/immv $args" ] } proc imrm { args } { global FSLDIR regsub -all "\{" $args "" cleanedargs regsub -all "\}" $cleanedargs "" cleanedargs return [ exec sh -c "${FSLDIR}/bin/imrm $args" ] } proc imtest { args } { global FSLDIR regsub -all "\{" $args "" cleanedargs regsub -all "\}" $cleanedargs "" cleanedargs return [ exec sh -c "${FSLDIR}/bin/imtest $args" ] } proc remove_ext { args } { global FSLDIR regsub -all "\{" $args "" cleanedargs regsub -all "\}" $cleanedargs "" cleanedargs return [ exec sh -c "${FSLDIR}/bin/remove_ext $cleanedargs" ] } nifti_clib-3.0.1/fsliolib/imcp000066400000000000000000000043351371325713600163100ustar00rootroot00000000000000#!/bin/sh # imcp - copy image files # # Stephen Smith and Mark Jenkinson, FMRIB Image Analysis Group # # # The imcp file was originally part of FSL - FMRIB's Software Library # http://www.fmrib.ox.ac.uk/fsl # imcp has now been placed in the public domain. # # # Developed at FMRIB (Oxford Centre for Functional Magnetic Resonance # Imaging of the Brain), Department of Clinical Neurology, Oxford # University, Oxford, UK # # if [ $# -lt 1 ] ; then echo "Usage: $0 " echo "Usage: $0 ... " echo " Copies images from file1 to file2 (including all extensions)" echo " NB: filenames can be basenames or include an extension" exit 1; fi if [ $# -eq 2 -a ! -d $2 ] ; then f1=`${FSLDIR}/bin/remove_ext $1`; f2=`${FSLDIR}/bin/remove_ext $2`; # do the copies if [ -f ${f1}.hdr ] ; then /bin/cp ${f1}.hdr ${f2}.hdr ; fi if [ -f ${f1}.hdr.gz ] ; then /bin/cp ${f1}.hdr.gz ${f2}.hdr.gz ; fi if [ -f ${f1}.img ] ; then /bin/cp ${f1}.img ${f2}.img ; fi if [ -f ${f1}.img.gz ] ; then /bin/cp ${f1}.img.gz ${f2}.img.gz ; fi if [ -f ${f1}.nii ] ; then /bin/cp ${f1}.nii ${f2}.nii ; fi if [ -f ${f1}.nii.gz ] ; then /bin/cp ${f1}.nii.gz ${f2}.nii.gz ; fi if [ -f ${f1}.mnc ] ; then /bin/cp ${f1}.mnc ${f2}.mnc ; fi if [ -f ${f1}.mnc.gz ] ; then /bin/cp ${f1}.mnc.gz ${f2}.mnc.gz ; fi fi if [ $# -gt 2 -o -d $2 ] ; then for nm in $@ ; do dir=$nm; done if [ ! -d $dir ] ; then echo "When using multiple arguments, last name must be a directory" exit 1; fi # remove directory from list of files flist="echo $@ | sed s/$dir \*\$//"; for fn in $flist ; do f1=`${FSLDIR}/bin/remove_ext $fn`; # do the copies if [ -f ${f1}.hdr ] ; then /bin/cp ${f1}.hdr ${dir} ; fi if [ -f ${f1}.hdr.gz ] ; then /bin/cp ${f1}.hdr.gz ${dir} ; fi if [ -f ${f1}.img ] ; then /bin/cp ${f1}.img ${dir} ; fi if [ -f ${f1}.img.gz ] ; then /bin/cp ${f1}.img.gz ${dir} ; fi if [ -f ${f1}.nii ] ; then /bin/cp ${f1}.nii ${dir} ; fi if [ -f ${f1}.nii.gz ] ; then /bin/cp ${f1}.nii.gz ${dir} ; fi if [ -f ${f1}.mnc ] ; then /bin/cp ${f1}.mnc ${dir} ; fi if [ -f ${f1}.mnc.gz ] ; then /bin/cp ${f1}.mnc.gz ${dir} ; fi done fi nifti_clib-3.0.1/fsliolib/imglob000066400000000000000000000026321371325713600166270ustar00rootroot00000000000000#!/bin/sh # imglob - expand list of image filenames # # Stephen Smith and Mark Jenkinson, FMRIB Image Analysis Group # # # The imglob file was originally part of FSL - FMRIB's Software Library # http://www.fmrib.ox.ac.uk/fsl # imglob has now been placed in the public domain. # # # Developed at FMRIB (Oxford Centre for Functional Magnetic Resonance # Imaging of the Brain), Department of Clinical Neurology, Oxford # University, Oxford, UK # # if [ $# -lt 1 ] ; then echo "Usage: $0 [-oneperimage] " exit 0; fi oneperimg=0; if [ X"$1"X = "X-oneperimageX" ] ; then oneperimg=1; shift; fi # process each argument, removing any possible extension and # then expanding for valid extensions lst=""; for aa in $@ ; do # repeat remove_ext a few times to expand out all wildmasking a=`${FSLDIR}/bin/remove_ext ${aa}`; # at this point variable 'a' may have been expanded into a list for b in $a ; do if [ $oneperimg = 1 ] ; then fn=`echo ${b}.hdr ${b}.hdr.gz ${b}.nii ${b}.nii.gz ${b}.mnc ${b}.mnc.gz`; else fn=`echo ${b}.hdr ${b}.hdr.gz ${b}.nii ${b}.nii.gz ${b}.mnc ${b}.mnc.gz ${b}.img ${b}.img.gz`; fi lst="$lst $fn"; done done # remove any instances of unmatched wildmasks (still with * in them) lst2=""; for fn in $lst ; do if [ -f $fn ] ; then lst2="$lst2 $fn"; fi done # make list unique lst=`echo $lst2 | tr ' ' '\n' | sort -u`; echo $lst nifti_clib-3.0.1/fsliolib/imln000066400000000000000000000023141371325713600163120ustar00rootroot00000000000000#!/bin/sh # imln - make symbolic link(s) to image file(s) # # Stephen Smith and Mark Jenkinson, FMRIB Image Analysis Group # # # The imln file was originally part of FSL - FMRIB's Software Library # http://www.fmrib.ox.ac.uk/fsl # imln has now been placed in the public domain. # # # Developed at FMRIB (Oxford Centre for Functional Magnetic Resonance # Imaging of the Brain), Department of Clinical Neurology, Oxford # University, Oxford, UK # # if [ $# -lt 2 ] ; then echo "Usage: $0 " echo " Makes a link (called file2) to file1" echo " NB: filenames can be basenames or include an extension" exit 1; fi f1=`${FSLDIR}/bin/remove_ext $1`; f2=`${FSLDIR}/bin/remove_ext $2`; if [ -f ${f1}.hdr ] ; then ln -fs ${f1}.hdr ${f2}.hdr ; fi if [ -f ${f1}.hdr.gz ] ; then ln -fs ${f1}.hdr.gz ${f2}.hdr.gz ; fi if [ -f ${f1}.img ] ; then ln -fs ${f1}.img ${f2}.img ; fi if [ -f ${f1}.img.gz ] ; then ln -fs ${f1}.img.gz ${f2}.img.gz ; fi if [ -f ${f1}.nii ] ; then ln -fs ${f1}.nii ${f2}.nii ; fi if [ -f ${f1}.nii.gz ] ; then ln -fs ${f1}.nii.gz ${f2}.nii.gz ; fi if [ -f ${f1}.mnc ] ; then ln -fs ${f1}.mnc ${f2}.mnc ; fi if [ -f ${f1}.mnc.gz ] ; then ln -fs ${f1}.mnc.gz ${f2}.mnc.gz ; fi nifti_clib-3.0.1/fsliolib/immv000066400000000000000000000042471371325713600163320ustar00rootroot00000000000000#!/bin/sh # immv - rename/move image files # # Stephen Smith and Mark Jenkinson, FMRIB Image Analysis Group # # # The immv file was originally part of FSL - FMRIB's Software Library # http://www.fmrib.ox.ac.uk/fsl # immv has now been placed in the public domain. # # # Developed at FMRIB (Oxford Centre for Functional Magnetic Resonance # Imaging of the Brain), Department of Clinical Neurology, Oxford # University, Oxford, UK # # if [ $# -lt 1 ] ; then echo "Usage: $0 " echo " Moves images from file1 to file2 (including all extensions)" echo " NB: filenames can be basenames or include an extension" exit 1; fi if [ $# -eq 2 -a ! -d $2 ] ; then f1=`${FSLDIR}/bin/remove_ext $1`; f2=`${FSLDIR}/bin/remove_ext $2`; # do the moves if [ -f ${f1}.hdr ] ; then /bin/mv ${f1}.hdr ${f2}.hdr ; fi if [ -f ${f1}.hdr.gz ] ; then /bin/mv ${f1}.hdr.gz ${f2}.hdr.gz ; fi if [ -f ${f1}.img ] ; then /bin/mv ${f1}.img ${f2}.img ; fi if [ -f ${f1}.img.gz ] ; then /bin/mv ${f1}.img.gz ${f2}.img.gz ; fi if [ -f ${f1}.nii ] ; then /bin/mv ${f1}.nii ${f2}.nii ; fi if [ -f ${f1}.nii.gz ] ; then /bin/mv ${f1}.nii.gz ${f2}.nii.gz ; fi if [ -f ${f1}.mnc ] ; then /bin/mv ${f1}.mnc ${f2}.mnc ; fi if [ -f ${f1}.mnc.gz ] ; then /bin/mv ${f1}.mnc.gz ${f2}.mnc.gz ; fi fi if [ $# -gt 2 -o -d $2 ] ; then for nm in $@ ; do dir=$nm; done if [ ! -d $dir ] ; then echo "When using multiple arguments, last name must be a directory" exit 1; fi # remove directory from list of files flist="echo $@ | sed s/$dir \*\$//"; for fn in $flist ; do f1=`${FSLDIR}/bin/remove_ext $fn`; # do the copies if [ -f ${f1}.hdr ] ; then /bin/mv ${f1}.hdr ${dir} ; fi if [ -f ${f1}.hdr.gz ] ; then /bin/mv ${f1}.hdr.gz ${dir} ; fi if [ -f ${f1}.img ] ; then /bin/mv ${f1}.img ${dir} ; fi if [ -f ${f1}.img.gz ] ; then /bin/mv ${f1}.img.gz ${dir} ; fi if [ -f ${f1}.nii ] ; then /bin/mv ${f1}.nii ${dir} ; fi if [ -f ${f1}.nii.gz ] ; then /bin/mv ${f1}.nii.gz ${dir} ; fi if [ -f ${f1}.mnc ] ; then /bin/mv ${f1}.mnc ${dir} ; fi if [ -f ${f1}.mnc.gz ] ; then /bin/mv ${f1}.mnc.gz ${dir} ; fi done fi nifti_clib-3.0.1/fsliolib/imrm000066400000000000000000000013741371325713600163240ustar00rootroot00000000000000#!/bin/sh # imrm - remove image files # # Stephen Smith and Mark Jenkinson, FMRIB Image Analysis Group # # # The imrm file was originally part of FSL - FMRIB's Software Library # http://www.fmrib.ox.ac.uk/fsl # imrm has now been placed in the public domain. # # Developed at FMRIB (Oxford Centre for Functional Magnetic Resonance # Imaging of the Brain), Department of Clinical Neurology, Oxford # University, Oxford, UK # # if [ $# -lt 1 ] ; then echo "Usage: $0 " echo "NB: filenames can be basenames or not" exit 1; fi for f in $@ ; do fn=`${FSLDIR}/bin/remove_ext $f`; # do the rm silently /bin/rm -f ${fn}.img ${fn}.hdr ${fn}.hdr.gz ${fn}.img.gz ${fn}.nii ${fn}.nii.gz ${fn}.mnc ${fn}.mnc.gz done nifti_clib-3.0.1/fsliolib/imtest000066400000000000000000000022521371325713600166610ustar00rootroot00000000000000#!/bin/sh # imtest - test to see if a valid image file exists with this name (root) # # Stephen Smith and Mark Jenkinson, FMRIB Image Analysis Group # # # The fslio.c file was originally part of FSL - FMRIB's Software Library # http://www.fmrib.ox.ac.uk/fsl # imtest has now been placed in the public domain. # # Developed at FMRIB (Oxford Centre for Functional Magnetic Resonance # Imaging of the Brain), Department of Clinical Neurology, Oxford # University, Oxford, UK # # # return 0 if no image exists or 1 if the image exists if [ $# -lt 1 ] ; then echo "0"; exit; fi filename=`${FSLDIR}/bin/remove_ext $1`; if [ -r ${filename}.nii -o -r ${filename}.nii.gz ] ; then echo "1"; exit; fi if [ -r ${filename}.mnc -o -r ${filename}.mnc.gz ] ; then echo "1"; exit; fi if [ ! -r ${filename}.hdr -a ! -r ${filename}.hdr.gz ] ; then # return 0 here as no header exists and no single image means no image! echo "0"; exit; fi if [ ! -r ${filename}.img -a ! -r ${filename}.img.gz ] ; then # return 0 here as no img file exists and no single image means no image! echo "0"; exit; fi # only gets to here if there was a hdr and an img file echo "1"; exit; nifti_clib-3.0.1/fsliolib/remove_ext000066400000000000000000000021231371325713600175260ustar00rootroot00000000000000#!/bin/sh # remove_ext - remove extension from image filename # # Stephen Smith and Mark Jenkinson, FMRIB Image Analysis Group # # # The remove_ext file was originally part of FSL - FMRIB's Software Library # http://www.fmrib.ox.ac.uk/fsl # remove_ext has now been placed in the public domain. # # Developed at FMRIB (Oxford Centre for Functional Magnetic Resonance # Imaging of the Brain), Department of Clinical Neurology, Oxford # University, Oxford, UK # # if [ $# -lt 1 ] ; then exit 0 fi lst=""; for fn in $@ ; do # for the ones at the end of the line f=`echo "$fn" | sed 's/\.hdr\.gz$//' | sed 's/\.img\.gz$//' | sed 's/\.hdr$//' | sed 's/\.img$//' | sed 's/\.nii.gz$//' | sed 's/\.nii$//' | sed 's/\.mnc.gz$//' | sed 's/\.mnc$//' | sed 's/\.$//'`; # for the ones in the middle of the line f=`echo "$f" | sed 's/\.hdr\.gz[ ]/ /g' | sed 's/\.img\.gz[ ]/ /g' | sed 's/\.hdr[ ]/ /g' | sed 's/\.img[ ]/ /g' | sed 's/\.nii\.gz[ ]/ /g' | sed 's/\.nii[ ]/ /g' | sed 's/\.mnc\.gz[ ]/ /g' | sed 's/\.mnc[ ]/ /g' |sed 's/\.[ ]/ /g'`; lst="$lst $f"; done echo $lst; nifti_clib-3.0.1/nifti2/000077500000000000000000000000001371325713600150205ustar00rootroot00000000000000nifti_clib-3.0.1/nifti2/CMakeLists.txt000066400000000000000000000363471371325713600175750ustar00rootroot00000000000000set(NIFTI_NIFTILIB2_NAME ${NIFTI_PACKAGE_PREFIX}nifti2) add_nifti_library(${NIFTI_NIFTILIB2_NAME} nifti2_io.c ) target_link_libraries( ${NIFTI_NIFTILIB2_NAME} PUBLIC ${NIFTI_PACKAGE_PREFIX}znz ${NIFTI_SYSTEM_MATH_LIB}) set_target_properties( ${NIFTI_NIFTILIB2_NAME} PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_LIST_DIR}/nifti1.h;${CMAKE_CURRENT_LIST_DIR}/nifti2.h;${CMAKE_CURRENT_LIST_DIR}/nifti2_io.h" ) # Set library version when building shared libs. if(BUILD_SHARED_LIBS) get_lib_version_vars("nifti2_io_version.h" NIFTI2_VERSION NIFTI2_MAJOR_VERSION) set_target_properties(${NIFTI_NIFTILIB2_NAME} PROPERTIES ${NIFTI_LIBRARY_PROPERTIES} VERSION ${NIFTI2_VERSION} SOVERSION ${NIFTI2_MAJOR_VERSION} ) endif() install_nifti_target(${NIFTI_NIFTILIB2_NAME}) if(NIFTI_BUILD_APPLICATIONS) set(NIFTI_TOOL ${NIFTI_PACKAGE_PREFIX}nifti_tool) add_nifti_executable(${NIFTI_TOOL} nifti_tool.c) target_link_libraries(${NIFTI_TOOL} PUBLIC ${NIFTI_NIFTILIB2_NAME}) install_nifti_target(${NIFTI_TOOL}) install_man_page( ${NIFTI_TOOL} OPTIONS_FOR_SECTIONS "-see_also" OPTS "--help-option=-help;--version-option=-ver_man;--no-info" ) endif() if(NIFTI_BUILD_TESTING AND NIFTI_BUILD_APPLICATIONS) # in order to decouble nifti2 and niftilib, the nifti1.h file # is duplicated here. The verify_nifti1_headers_are_same test # will fail if these two files are not identical. if( ( IS_DIRECTORY ${PROJECT_SOURCE_DIR}/nifti2 ) AND (IS_DIRECTORY ${PROJECT_SOURCE_DIR}/niftilib)) message(STATUS "Testing same") add_test( NAME ${NIFTI_PACKAGE_PREFIX}verify_nifti1_headers_are_same COMMAND ${CMAKE_COMMAND} -E compare_files ${PROJECT_SOURCE_DIR}/nifti2/nifti1.h ${PROJECT_SOURCE_DIR}/niftilib/nifti1.h) endif() add_executable(${NIFTI_PACKAGE_PREFIX}clib_02_nifti2 clib_02_nifti2.c) target_link_libraries(${NIFTI_PACKAGE_PREFIX}clib_02_nifti2 PUBLIC ${NIFTI_NIFTILIB2_NAME}) # Do all regression tests set(TOOL_SUFFIX "") # The suffxi used for this tool "1" for nifti1, and "" for nifti2 set(TEST_PREFIX "${NIFTI_PACKAGE_PREFIX}nifti${TOOL_SUFFIX}") set(TOOL_NAME ${TEST_PREFIX}_tool) add_test( NAME ${TEST_PREFIX}_test_help COMMAND $) add_test( NAME ${TEST_PREFIX}_test_n1 COMMAND $ -n1 ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/ATestReferenceImageForReadingAndWriting.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/n1 ) add_test( NAME ${TEST_PREFIX}_test_n2 COMMAND $ -n2 ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/ATestReferenceImageForReadingAndWriting.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/n2 ) add_test( NAME ${TEST_PREFIX}_test_a2 COMMAND $ -a2 ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/ATestReferenceImageForReadingAndWriting.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/a2 ) add_test( NAME ${TEST_PREFIX}_test_zn1 COMMAND $ -zn1 ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/ATestReferenceImageForReadingAndWriting.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/zn1 ) add_test( NAME ${TEST_PREFIX}_test_zn2 COMMAND $ -zn2 ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/ATestReferenceImageForReadingAndWriting.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/zn2 ) add_test( NAME ${TEST_PREFIX}_test_za2 COMMAND $ -za2 ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/ATestReferenceImageForReadingAndWriting.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/za2 ) add_test( NAME ${TEST_PREFIX}_ver COMMAND $ -nifti_ver) add_test( NAME ${TEST_PREFIX}_tool_ver COMMAND $ -ver) add_test( NAME ${TEST_PREFIX}_help COMMAND $ -help) add_test( NAME ${TEST_PREFIX}_nifti_hist COMMAND $ -nifti_hist) add_test( NAME ${TEST_PREFIX}_hist COMMAND $ -hist) add_test( NAME ${TEST_PREFIX}_disp_hdr COMMAND $ -disp_hdr -infiles ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/anat0.nii ) add_test( NAME ${TEST_PREFIX}_disp_nim COMMAND $ -disp_nim -infiles ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/anat0.nii ) add_test( NAME ${TEST_PREFIX}_disp_ext COMMAND $ -disp_ext -infiles ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/anat0.nii ) add_test( NAME ${TEST_PREFIX}_header_check COMMAND $ -check_hdr -infiles ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/anat0.nii ) add_test( NAME ${TEST_PREFIX}_nim_check COMMAND $ -check_nim -infiles ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/anat0.nii ) set_tests_properties(${TEST_PREFIX}_disp_hdr PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_disp_nim PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_disp_ext PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_header_check PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_nim_check PROPERTIES LABELS NEEDS_DATA) #The help screens always return 1; add_test( NAME ${NIFTI_PACKAGE_PREFIX}nifti1_tool1_help COMMAND $) add_test( NAME ${TEST_PREFIX}_tool_n1 COMMAND $ -disp_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/n1 ) add_test( NAME ${TEST_PREFIX}_tool_n2 COMMAND $ -disp_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/n2 ) add_test( NAME ${TEST_PREFIX}_tool_a2 COMMAND $ -disp_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/a2 ) add_test( NAME ${TEST_PREFIX}_tool_zn1 COMMAND $ -disp_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1 ) add_test( NAME ${TEST_PREFIX}_tool_zn2 COMMAND $ -disp_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/zn2 ) add_test( NAME ${TEST_PREFIX}_tool_za2 COMMAND $ -disp_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/za2 ) add_test( NAME ${TEST_PREFIX}_tool_diff_hdr COMMAND $ -diff_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1 ${CMAKE_CURRENT_BINARY_DIR}/zn1 ) add_test( NAME ${TEST_PREFIX}_tool_diff_nims COMMAND $ -diff_nim -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1 ${CMAKE_CURRENT_BINARY_DIR}/zn1 ) add_test( NAME ${TEST_PREFIX}_tool_copy_brick_list COMMAND $ -cbl -prefix cbl_zn1.nii -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz[0,1]) add_test( NAME ${TEST_PREFIX}_tool_disp_ci COMMAND $ -disp_ci 2 2 2 -1 0 0 0 -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz ) add_test( NAME ${TEST_PREFIX}_tool_disp_ts COMMAND $ -disp_ts 2 2 2 -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz ) add_test( NAME ${TEST_PREFIX}_tool_strip_extras COMMAND $ -strip_extras -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz ) # This test needs a file that has extensions to remove #add_test( NAME ${TEST_PREFIX}_tool_rm_ext /bin/sh ${NIFTI_SOURCE_DIR}/niftilib/rmthenrun rm_ext.nii COMMAND $ -rm_ext ALL -prefix rm_ext.nii -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz ) add_test( NAME ${TEST_PREFIX}_tool_check_hdr COMMAND $ -check_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/za2 ) add_test( NAME ${TEST_PREFIX}_tool_check_nim COMMAND $ -check_nim -infile ${CMAKE_CURRENT_BINARY_DIR}/za2 ) set_tests_properties(${TEST_PREFIX}_tool_check_hdr PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_tool_check_nim PROPERTIES LABELS NEEDS_DATA) #add_test( NAME ${TEST_PREFIX}_tool_copy_collapsed_image /bin/sh ${NIFTI_SOURCE_DIR}/niftilib/rmthenrun cci_zn1.nii COMMAND $ -cci 2 2 2 -1 -1 -1 -1 -prefix cci_zn1.nii -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz ) add_test( NAME cleanup_n1 COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/n1.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/n1.nii ) add_test( NAME cleanup_n2 COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/n2.nii ${CMAKE_CURRENT_BINARY_DIR}/n2.hdr ${CMAKE_CURRENT_BINARY_DIR}/n2.img) add_test( NAME cleanup_a2 COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/a2.img ${CMAKE_CURRENT_BINARY_DIR}/a2.hdr ) add_test( NAME cleanup_zn1 COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/cbl_zn1.nii ) add_test( NAME cleanup_zn2 COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/zn2.img.gz ${CMAKE_CURRENT_BINARY_DIR}/zn2.hdr.gz ) add_test( NAME cleanup_za2 COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/za2.img.gz ${CMAKE_CURRENT_BINARY_DIR}/za2.hdr.gz ) # https://crascit.com/2016/10/18/test-fixtures-with-cmake-ctest/ as of cmake 3.7 fixtures are supported foreach( testsuffix "n1" "n2" "a2" "zn1" "zn2" "za2") #message(STATUS "Setting up ${testsuffix}") set_tests_properties( ${TEST_PREFIX}_tool_${testsuffix} PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_${testsuffix} ) set_tests_properties( ${TEST_PREFIX}_test_${testsuffix} PROPERTIES FIXTURES_SETUP NiftiTestGeneratedFiles_${testsuffix}) message(STATUS "NiftiTestGeneratedFiles_${testsuffix}" ) set_tests_properties( ${TEST_PREFIX}_tool_${testsuffix} ${TEST_PREFIX}_test_${testsuffix} PROPERTIES RESOURCE_LOCK Serial_${testsuffix} LABELS NEEDS_DATA ) set_tests_properties(cleanup_${testsuffix} PROPERTIES FIXTURES_CLEANUP NiftiTestGeneratedFiles_${testsuffix} ) endforeach() set_tests_properties( ${TEST_PREFIX}_tool_diff_hdr PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_zn1) set_tests_properties( ${TEST_PREFIX}_tool_diff_nims PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_zn1) set_tests_properties( ${TEST_PREFIX}_tool_copy_brick_list PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_zn1) set_tests_properties( ${TEST_PREFIX}_tool_disp_ci PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_zn1) set_tests_properties( ${TEST_PREFIX}_tool_disp_ts PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_zn1) set_tests_properties( ${TEST_PREFIX}_tool_strip_extras PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_zn1) set_tests_properties( ${TEST_PREFIX}_tool_check_hdr PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_za2) set_tests_properties( ${TEST_PREFIX}_tool_check_nim PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_za2) #set_tests_properties( ${TEST_PREFIX}_tool_copy_collapsed_image PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFileszn1) set_tests_properties( ${TEST_PREFIX}_tool_diff_hdr ${TEST_PREFIX}_tool_diff_nims ${TEST_PREFIX}_tool_copy_brick_list ${TEST_PREFIX}_tool_disp_ci ${TEST_PREFIX}_tool_disp_ts ${TEST_PREFIX}_tool_strip_extras PROPERTIES RESOURCE_LOCK Serial_zn1 LABELS NEEDS_DATA ) #==END NIFTI1 and NIFTI2 common tests ============================================ add_test( NAME ${TEST_PREFIX}_misc_tests COMMAND $ -run_misc_tests -debug 2 -infiles ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/e4.60005.nii.gz ) set_tests_properties(${TEST_PREFIX}_misc_tests PROPERTIES LABELS NEEDS_DATA) if(UNIX AND NIFTI_SHELL_SCRIPT_TESTS) # unix needed to run shell scripts set(NIFTI_TEST_SCRIPT_DIR ${CMAKE_CURRENT_LIST_DIR}/nifti_regress_test/cmake_testscripts) add_test( NAME ${TEST_PREFIX}_modhdr_exts COMMAND sh ${NIFTI_TEST_SCRIPT_DIR}/mod_header_test.sh $ ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data ) add_test( NAME ${TEST_PREFIX}_bricks_test COMMAND sh ${NIFTI_TEST_SCRIPT_DIR}/bricks_test.sh $ ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data ) set_tests_properties(${TEST_PREFIX}_modhdr_exts PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_bricks_test PROPERTIES LABELS NEEDS_DATA) add_test( NAME ${TEST_PREFIX}_dci_test COMMAND sh ${NIFTI_TEST_SCRIPT_DIR}/dci_test.sh $ ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data ) add_test( NAME ${TEST_PREFIX}_comment_test COMMAND sh ${NIFTI_TEST_SCRIPT_DIR}/comment_test.sh $ ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data ) add_test( NAME ${TEST_PREFIX}_dsets_test COMMAND sh ${NIFTI_TEST_SCRIPT_DIR}/dsets_test.sh $ ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data ) add_test( NAME ${TEST_PREFIX}_newfiles_test COMMAND sh ${NIFTI_TEST_SCRIPT_DIR}/newfiles_test.sh $ ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data ) set_tests_properties(${TEST_PREFIX}_dci_test PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_comment_test PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_newfiles_test PROPERTIES LABELS NEEDS_DATA) add_test( NAME ${TEST_PREFIX}_dts_test COMMAND sh ${NIFTI_TEST_SCRIPT_DIR}/dts_test.sh $ ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data ) set_tests_properties( ${TEST_PREFIX}_dts_test PROPERTIES DEPENDS ${TEST_PREFIX}_bricks_test LABELS NEEDS_DATA) add_test( NAME ${TEST_PREFIX}_mod_hdr2_test COMMAND sh ${NIFTI_TEST_SCRIPT_DIR}/mod_header_2_test.sh $ ${fetch_testing_data_SOURCE_DIR}/CiftiLib_data ) add_test( NAME ${TEST_PREFIX}_c21_a_info_test COMMAND sh ${NIFTI_TEST_SCRIPT_DIR}/c21_a_info_test.sh $ ${fetch_testing_data_SOURCE_DIR}/CiftiLib_data ) add_test( NAME ${TEST_PREFIX}_c21_b_cifti_in_test COMMAND sh ${NIFTI_TEST_SCRIPT_DIR}/c21_b_cifti_in.sh $ ${fetch_testing_data_SOURCE_DIR}/CiftiLib_data ) add_test( NAME ${TEST_PREFIX}_c21_c_make_im_test COMMAND sh ${NIFTI_TEST_SCRIPT_DIR}/c21_c_make_im.sh $ ${fetch_testing_data_SOURCE_DIR}/CiftiLib_data ) add_test( NAME ${TEST_PREFIX}_c21_d_misc_tests COMMAND sh ${NIFTI_TEST_SCRIPT_DIR}/c21_d_misc_tests.sh $ ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data ) set_tests_properties(${TEST_PREFIX}_mod_hdr2_test PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_c21_a_info_test PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_c21_b_cifti_in_test PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_c21_c_make_im_test PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_c21_d_misc_tests PROPERTIES LABELS NEEDS_DATA) # Test that installed linking works if(TEST_INSTALL) add_test( NAME install_linking COMMAND sh ${NIFTI_TEST_SCRIPT_DIR}/install_linking_test.sh ${CMAKE_MAKE_PROGRAM} WORKING_DIRECTORY ${PROJECT_BINARY_DIR} ) endif() endif() unset(TEST_SUFFIX) unset(TEST_PREFIX) unset(TOOL_NAME) endif() nifti_clib-3.0.1/nifti2/Makefile000066400000000000000000000025771371325713600164730ustar00rootroot00000000000000 # note the TARFILE_NAME embeds the release version number TARFILE_NAME = nifti2clib-0.0.1 USEZLIB = -DHAVE_ZLIB ## Compiler defines CC = gcc IFLAGS = -I. -I../niftilib -I../znzlib CFLAGS = -Wall -std=gnu99 -pedantic $(USEZLIB) $(IFLAGS) LLIBS = -lz -lm MISC_OBJS = nifticdf.o znzlib.o OBJS = nifti2_io.o $(MISC_OBJS) TOOLS = nifti_tool nifti1_tool nifti2_tool EXAMPLES = clib_02_nifti2 # -------------------------------------------------- # default compile for C files %.o : %.c %.h $(CC) -c $(CFLAGS) $< -o $@ # -------------------------------------------------- # main targets (primary is nifti_tool, for now) nifti_tool: nifti_tool.o nifti_tool.h nifti2objs $(CC) -o $@ $(CFLAGS) $< $(OBJS) $(LLIBS) all: $(TOOLS) $(EXAMPLES) clean: $(RM) *.o $(TOOLS) $(EXAMPLES) nifti2objs: $(OBJS) clib_02_nifti2: clib_02_nifti2.o nifti2objs $(CC) -o $@ $(CFLAGS) $< $(OBJS) $(LLIBS) # -------------------------------------------------- # targets from source residing elsewhere nifticdf.o: $(CC) -c $(CFLAGS) ../nifticdf/nifticdf.c -o $@ znzlib.o: $(CC) -c $(CFLAGS) ../znzlib/znzlib.c -o $@ # maybe we want to build NIFTI-1 nifti_tool nifti1_tool: $(MISC_OBJS) $(CC) -o $@ -I../utils $(CFLAGS) \ ../niftilib/nifti_tool.c ../niftilib/nifti1_io.c $(MISC_OBJS) $(LLIBS) # make non-clashing version nifti2_tool: nifti_tool cp -p nifti_tool nifti2_tool nifti_clib-3.0.1/nifti2/clib_02_nifti2.c000066400000000000000000000117341371325713600176570ustar00rootroot00000000000000/* ---------------------------------------------------------------------- * A basic example to read/write a nifti dataset (e.g. cp command). * * compile example (consider -pedantic or -Wall): * * gcc -o clib_02_nifti2 clib_02.nifti2.c \ * -I../include -L../lib -lniftiio -lznz -lz -lm * * OR * * gcc -o clib_02_nifti2 clib_02.nifti2.c -I ../niftilib \ * -I ../znzlib ../niftilib/nifti2_io.o ../znzlib/znzlib.o -lz -lm * * R Reynolds 3 Apr 2014 *---------------------------------------------------------------------- */ #include #include int disp_float(nifti_image * nim, int vol, int slice, int line, int offset); int show_help( void ) { printf( "clib_02_nifti2: short exmample of reading/writing NIfTI2\n" "\n" " This program is to demonstrate how to read a NIfTI-2 dataset,\n" " set output filenames and write a NIfTI-2 dataset, all via the\n" " standard NIfTI C library.\n" "\n" " basic usage: clib_02_nifti2 -input FILE_IN -output FILE_OUT\n" " clib_02_nifti2 -input FILE_IN -disp_float_example\n" "\n" " options:\n" "\n" " -help : show this help\n" " -disp_float_example : show some voxel's data\n" " -input INFILE : specify input dataset\n" " -output OUTFILE : specify output dataset\n" " -verb LEVEL : set the verbose level to LEVEL\n" "\n"); return 0; } int main(int argc, char * argv[]) { nifti_image * nim=NULL; char * fin=NULL, * fout=NULL; int ac, disp_float_eg=0; if( argc < 2 ) return show_help(); /* typing '-help' is sooo much work */ /* process user options: 4 are valid presently */ for( ac = 1; ac < argc; ac++ ) { if( ! strncmp(argv[ac], "-h", 2) ) { return show_help(); } else if( ! strcmp(argv[ac], "-disp_float_example") ) { disp_float_eg = 1; } else if( ! strcmp(argv[ac], "-input") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -input\n"); return 1; } fin = argv[ac]; /* no string copy, just pointer assignment */ } else if( ! strcmp(argv[ac], "-output") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -output\n"); return 2; } fout = argv[ac]; } else if( ! strcmp(argv[ac], "-verb") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -verb\n"); return 2; } nifti_set_debug_level(atoi(argv[ac])); } else { fprintf(stderr,"** invalid option, '%s'\n", argv[ac]); return 1; } } if( !fin ) { fprintf(stderr, "** missing option '-input'\n"); return 1; } /* read input dataset, including data */ nim = nifti_image_read(fin, 1); if( !nim ) { fprintf(stderr,"** failed to read NIfTI image from '%s'\n", fin); return 2; } if( disp_float_eg ) disp_float(nim, 0, 1, 2, 3); if( !fout ) { fprintf(stderr, "-- no output requested \n"); return 0; } /* assign nifti_image fname/iname pair, based on output filename (request to 'check' image and 'set_byte_order' here) */ if( nifti_set_filenames(nim, fout, 1, 1) ) return 1; /* if we get here, write the output dataset */ nifti_image_write( nim ); /* and clean up memory */ nifti_image_free( nim ); return 0; } int disp_float(nifti_image * nim, int vol, int slice, int line, int offset) { float * dp, * d2; long long lloff; int nx, nxy, nxyz; if( ! nim ) return 1; if( nim->datatype != NIFTI_TYPE_FLOAT32 ) { fprintf(stderr,"** datatype not float, have %s\n", nifti_datatype_to_string(nim->datatype)); return 1; } nx = nim->nx; nxy = nim->nx * nim->ny; nxyz = nim->nx * nim->ny * nim->nz; /* set a float pointer to the beginning of the data, so no more casting is needed */ dp = (float *)nim->data; /* check limits */ if( vol >= nim->nt || vol < 0 ) { fprintf(stderr,"** vol index %d is out of range [0, %lld]\n", vol, (long long)nim->nt-1); return 1; } if( slice >= nim->nz || slice < 0 ) { fprintf(stderr,"** slice index %d is out of range [0, %lld]\n", slice, (long long)nim->nz-1); return 1; } if( line >= nim->ny || line < 0 ) { fprintf(stderr,"** line index %d is out of range [0, %lld]\n", line, (long long)nim->ny-1); return 1; } if( offset >= nim->nx || offset < 0 ) { fprintf(stderr,"** offset %d is out of range [0, %lld]\n", offset, (long long)nim->nx-1); return 1; } lloff = vol*nxyz + slice*nxy + line*nx + offset; d2 = dp + lloff; printf("data[%d,%d,%d,%d] = %f\n", vol, slice, line, offset, *d2); /* or */ printf("data[%lld] = %f\n", lloff, dp[lloff]); return 0; /* success */ } nifti_clib-3.0.1/nifti2/nifti1.h000066400000000000000000002121151371325713600163650ustar00rootroot00000000000000/** \file nifti1.h \brief Official definition of the nifti1 header. Written by Bob Cox, SSCC, NIMH. HISTORY: 29 Nov 2007 [rickr] - added DT_RGBA32 and NIFTI_TYPE_RGBA32 - added NIFTI_INTENT codes: TIME_SERIES, NODE_INDEX, RGB_VECTOR, RGBA_VECTOR, SHAPE 08 Mar 2019 [PT,DRG] - Updated to include [qs]form_code = 5 */ #ifndef _NIFTI_HEADER_ #define _NIFTI_HEADER_ /***************************************************************************** ** This file defines the "NIFTI-1" header format. ** ** It is derived from 2 meetings at the NIH (31 Mar 2003 and ** ** 02 Sep 2003) of the Data Format Working Group (DFWG), ** ** chartered by the NIfTI (Neuroimaging Informatics Technology ** ** Initiative) at the National Institutes of Health (NIH). ** **--------------------------------------------------------------** ** Neither the National Institutes of Health (NIH), the DFWG, ** ** nor any of the members or employees of these institutions ** ** imply any warranty of usefulness of this material for any ** ** purpose, and do not assume any liability for damages, ** ** incidental or otherwise, caused by any use of this document. ** ** If these conditions are not acceptable, do not use this! ** **--------------------------------------------------------------** ** Author: Robert W Cox (NIMH, Bethesda) ** ** Advisors: John Ashburner (FIL, London), ** ** Stephen Smith (FMRIB, Oxford), ** ** Mark Jenkinson (FMRIB, Oxford) ** ******************************************************************************/ /*---------------------------------------------------------------------------*/ /* Note that the ANALYZE 7.5 file header (dbh.h) is (c) Copyright 1986-1995 Biomedical Imaging Resource Mayo Foundation Incorporation of components of dbh.h are by permission of the Mayo Foundation. Changes from the ANALYZE 7.5 file header in this file are released to the public domain, including the functional comments and any amusing asides. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /*! INTRODUCTION TO NIFTI-1: ------------------------ The twin (and somewhat conflicting) goals of this modified ANALYZE 7.5 format are: (a) To add information to the header that will be useful for functional neuroimaging data analysis and display. These additions include: - More basic data types. - Two affine transformations to specify voxel coordinates. - "Intent" codes and parameters to describe the meaning of the data. - Affine scaling of the stored data values to their "true" values. - Optional storage of the header and image data in one file (.nii). (b) To maintain compatibility with non-NIFTI-aware ANALYZE 7.5 compatible software (i.e., such a program should be able to do something useful with a NIFTI-1 dataset -- at least, with one stored in a traditional .img/.hdr file pair). Most of the unused fields in the ANALYZE 7.5 header have been taken, and some of the lesser-used fields have been co-opted for other purposes. Notably, most of the data_history substructure has been co-opted for other purposes, since the ANALYZE 7.5 format describes this substructure as "not required". NIFTI-1 FLAG (MAGIC STRINGS): ---------------------------- To flag such a struct as being conformant to the NIFTI-1 spec, the last 4 bytes of the header must be either the C String "ni1" or "n+1"; in hexadecimal, the 4 bytes 6E 69 31 00 or 6E 2B 31 00 (in any future version of this format, the '1' will be upgraded to '2', etc.). Normally, such a "magic number" or flag goes at the start of the file, but trying to avoid clobbering widely-used ANALYZE 7.5 fields led to putting this marker last. However, recall that "the last shall be first" (Matthew 20:16). If a NIFTI-aware program reads a header file that is NOT marked with a NIFTI magic string, then it should treat the header as an ANALYZE 7.5 structure. NIFTI-1 FILE STORAGE: -------------------- "ni1" means that the image data is stored in the ".img" file corresponding to the header file (starting at file offset 0). "n+1" means that the image data is stored in the same file as the header information. We recommend that the combined header+data filename suffix be ".nii". When the dataset is stored in one file, the first byte of image data is stored at byte location (int)vox_offset in this combined file. The minimum allowed value of vox_offset is 352; for compatibility with some software, vox_offset should be an integral multiple of 16. GRACE UNDER FIRE: ---------------- Most NIFTI-aware programs will only be able to handle a subset of the full range of datasets possible with this format. All NIFTI-aware programs should take care to check if an input dataset conforms to the program's needs and expectations (e.g., check datatype, intent_code, etc.). If the input dataset can't be handled by the program, the program should fail gracefully (e.g., print a useful warning; not crash). SAMPLE CODES: ------------ The associated files nifti1_io.h and nifti1_io.c provide a sample implementation in C of a set of functions to read, write, and manipulate NIFTI-1 files. The file nifti1_test.c is a sample program that uses the nifti1_io.c functions. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* HEADER STRUCT DECLARATION: ------------------------- In the comments below for each field, only NIFTI-1 specific requirements or changes from the ANALYZE 7.5 format are described. For convenience, the 348 byte header is described as a single struct, rather than as the ANALYZE 7.5 group of 3 substructs. Further comments about the interpretation of various elements of this header are after the data type definition itself. Fields that are marked as ++UNUSED++ have no particular interpretation in this standard. (Also see the UNUSED FIELDS comment section, far below.) The presumption below is that the various C types have particular sizes: sizeof(int) = sizeof(float) = 4 ; sizeof(short) = 2 -----------------------------------------------------------------------------*/ /*=================*/ #ifdef __cplusplus extern "C" { #endif /*=================*/ /*! \struct nifti_1_header \brief Data structure defining the fields in the nifti1 header. This binary header should be found at the beginning of a valid NIFTI-1 header file. */ /*************************/ /************************/ struct nifti_1_header { /* NIFTI-1 usage */ /* ANALYZE 7.5 field(s) */ /*************************/ /************************/ /*--- was header_key substruct ---*/ int sizeof_hdr; /*!< MUST be 348 */ /* int sizeof_hdr; */ char data_type[10]; /*!< ++UNUSED++ */ /* char data_type[10]; */ char db_name[18]; /*!< ++UNUSED++ */ /* char db_name[18]; */ int extents; /*!< ++UNUSED++ */ /* int extents; */ short session_error; /*!< ++UNUSED++ */ /* short session_error; */ char regular; /*!< ++UNUSED++ */ /* char regular; */ char dim_info; /*!< MRI slice ordering. */ /* char hkey_un0; */ /*--- was image_dimension substruct ---*/ short dim[8]; /*!< Data array dimensions.*/ /* short dim[8]; */ float intent_p1 ; /*!< 1st intent parameter. */ /* short unused8; */ /* short unused9; */ float intent_p2 ; /*!< 2nd intent parameter. */ /* short unused10; */ /* short unused11; */ float intent_p3 ; /*!< 3rd intent parameter. */ /* short unused12; */ /* short unused13; */ short intent_code ; /*!< NIFTI_INTENT_* code. */ /* short unused14; */ short datatype; /*!< Defines data type! */ /* short datatype; */ short bitpix; /*!< Number bits/voxel. */ /* short bitpix; */ short slice_start; /*!< First slice index. */ /* short dim_un0; */ float pixdim[8]; /*!< Grid spacings. */ /* float pixdim[8]; */ float vox_offset; /*!< Offset into .nii file */ /* float vox_offset; */ float scl_slope ; /*!< Data scaling: slope. */ /* float funused1; */ float scl_inter ; /*!< Data scaling: offset. */ /* float funused2; */ short slice_end; /*!< Last slice index. */ /* float funused3; */ char slice_code ; /*!< Slice timing order. */ char xyzt_units ; /*!< Units of pixdim[1..4] */ float cal_max; /*!< Max display intensity */ /* float cal_max; */ float cal_min; /*!< Min display intensity */ /* float cal_min; */ float slice_duration;/*!< Time for 1 slice. */ /* float compressed; */ float toffset; /*!< Time axis shift. */ /* float verified; */ int glmax; /*!< ++UNUSED++ */ /* int glmax; */ int glmin; /*!< ++UNUSED++ */ /* int glmin; */ /*--- was data_history substruct ---*/ char descrip[80]; /*!< any text you like. */ /* char descrip[80]; */ char aux_file[24]; /*!< auxiliary filename. */ /* char aux_file[24]; */ short qform_code ; /*!< NIFTI_XFORM_* code. */ /*-- all ANALYZE 7.5 ---*/ short sform_code ; /*!< NIFTI_XFORM_* code. */ /* fields below here */ /* are replaced */ float quatern_b ; /*!< Quaternion b param. */ float quatern_c ; /*!< Quaternion c param. */ float quatern_d ; /*!< Quaternion d param. */ float qoffset_x ; /*!< Quaternion x shift. */ float qoffset_y ; /*!< Quaternion y shift. */ float qoffset_z ; /*!< Quaternion z shift. */ float srow_x[4] ; /*!< 1st row affine transform. */ float srow_y[4] ; /*!< 2nd row affine transform. */ float srow_z[4] ; /*!< 3rd row affine transform. */ char intent_name[16];/*!< 'name' or meaning of data. */ char magic[4] ; /*!< MUST be "ni1\0" or "n+1\0". */ } ; /**** 348 bytes total ****/ typedef struct nifti_1_header nifti_1_header ; /*---------------------------------------------------------------------------*/ /* HEADER EXTENSIONS: ----------------- After the end of the 348 byte header (e.g., after the magic field), the next 4 bytes are a char array field named "extension". By default, all 4 bytes of this array should be set to zero. In a .nii file, these 4 bytes will always be present, since the earliest start point for the image data is byte #352. In a separate .hdr file, these bytes may or may not be present. If not present (i.e., if the length of the .hdr file is 348 bytes), then a NIfTI-1 compliant program should use the default value of extension={0,0,0,0}. The first byte (extension[0]) is the only value of this array that is specified at present. The other 3 bytes are reserved for future use. If extension[0] is nonzero, it indicates that extended header information is present in the bytes following the extension array. In a .nii file, this extended header data is before the image data (and vox_offset must be set correctly to allow for this). In a .hdr file, this extended data follows extension and proceeds (potentially) to the end of the file. The format of extended header data is weakly specified. Each extension must be an integer multiple of 16 bytes long. The first 8 bytes of each extension comprise 2 integers: int esize , ecode ; These values may need to be byte-swapped, as indicated by dim[0] for the rest of the header. * esize is the number of bytes that form the extended header data + esize must be a positive integral multiple of 16 + this length includes the 8 bytes of esize and ecode themselves * ecode is a non-negative integer that indicates the format of the extended header data that follows + different ecode values are assigned to different developer groups + at present, the "registered" values for code are = 0 = unknown private format (not recommended!) = 2 = DICOM format (i.e., attribute tags and values) = 4 = AFNI group (i.e., ASCII XML-ish elements) In the interests of interoperability (a primary rationale for NIfTI), groups developing software that uses this extension mechanism are encouraged to document and publicize the format of their extensions. To this end, the NIfTI DFWG will assign even numbered codes upon request to groups submitting at least rudimentary documentation for the format of their extension; at present, the contact is mailto:rwcox@nih.gov. The assigned codes and documentation will be posted on the NIfTI website. All odd values of ecode (and 0) will remain unassigned; at least, until the even ones are used up, when we get to 2,147,483,646. Note that the other contents of the extended header data section are totally unspecified by the NIfTI-1 standard. In particular, if binary data is stored in such a section, its byte order is not necessarily the same as that given by examining dim[0]; it is incumbent on the programs dealing with such data to determine the byte order of binary extended header data. Multiple extended header sections are allowed, each starting with an esize,ecode value pair. The first esize value, as described above, is at bytes #352-355 in the .hdr or .nii file (files start at byte #0). If this value is positive, then the second (esize2) will be found starting at byte #352+esize1 , the third (esize3) at byte #352+esize1+esize2, et cetera. Of course, in a .nii file, the value of vox_offset must be compatible with these extensions. If a malformed file indicates that an extended header data section would run past vox_offset, then the entire extended header section should be ignored. In a .hdr file, if an extended header data section would run past the end-of-file, that extended header data should also be ignored. With the above scheme, a program can successively examine the esize and ecode values, and skip over each extended header section if the program doesn't know how to interpret the data within. Of course, any program can simply ignore all extended header sections simply by jumping straight to the image data using vox_offset. -----------------------------------------------------------------------------*/ /*! \struct nifti1_extender \brief This structure represents a 4-byte string that should follow the binary nifti_1_header data in a NIFTI-1 header file. If the char values are {1,0,0,0}, the file is expected to contain extensions, values of {0,0,0,0} imply the file does not contain extensions. Other sequences of values are not currently defined. */ struct nifti1_extender { char extension[4] ; } ; typedef struct nifti1_extender nifti1_extender ; /*! \struct nifti1_extension \brief Data structure defining the fields of a header extension. */ struct nifti1_extension { int esize ; /*!< size of extension, in bytes (must be multiple of 16) */ int ecode ; /*!< extension code, one of the NIFTI_ECODE_ values */ char * edata ; /*!< raw data, with no byte swapping (length is esize-8) */ } ; typedef struct nifti1_extension nifti1_extension ; /*---------------------------------------------------------------------------*/ /* DATA DIMENSIONALITY (as in ANALYZE 7.5): --------------------------------------- dim[0] = number of dimensions; - if dim[0] is outside range 1..7, then the header information needs to be byte swapped appropriately - ANALYZE supports dim[0] up to 7, but NIFTI-1 reserves dimensions 1,2,3 for space (x,y,z), 4 for time (t), and 5,6,7 for anything else needed. dim[i] = length of dimension #i, for i=1..dim[0] (must be positive) - also see the discussion of intent_code, far below pixdim[i] = voxel width along dimension #i, i=1..dim[0] (positive) - cf. ORIENTATION section below for use of pixdim[0] - the units of pixdim can be specified with the xyzt_units field (also described far below). Number of bits per voxel value is in bitpix, which MUST correspond with the datatype field. The total number of bytes in the image data is dim[1] * ... * dim[dim[0]] * bitpix / 8 In NIFTI-1 files, dimensions 1,2,3 are for space, dimension 4 is for time, and dimension 5 is for storing multiple values at each spatiotemporal voxel. Some examples: - A typical whole-brain FMRI experiment's time series: - dim[0] = 4 - dim[1] = 64 pixdim[1] = 3.75 xyzt_units = NIFTI_UNITS_MM - dim[2] = 64 pixdim[2] = 3.75 | NIFTI_UNITS_SEC - dim[3] = 20 pixdim[3] = 5.0 - dim[4] = 120 pixdim[4] = 2.0 - A typical T1-weighted anatomical volume: - dim[0] = 3 - dim[1] = 256 pixdim[1] = 1.0 xyzt_units = NIFTI_UNITS_MM - dim[2] = 256 pixdim[2] = 1.0 - dim[3] = 128 pixdim[3] = 1.1 - A single slice EPI time series: - dim[0] = 4 - dim[1] = 64 pixdim[1] = 3.75 xyzt_units = NIFTI_UNITS_MM - dim[2] = 64 pixdim[2] = 3.75 | NIFTI_UNITS_SEC - dim[3] = 1 pixdim[3] = 5.0 - dim[4] = 1200 pixdim[4] = 0.2 - A 3-vector stored at each point in a 3D volume: - dim[0] = 5 - dim[1] = 256 pixdim[1] = 1.0 xyzt_units = NIFTI_UNITS_MM - dim[2] = 256 pixdim[2] = 1.0 - dim[3] = 128 pixdim[3] = 1.1 - dim[4] = 1 pixdim[4] = 0.0 - dim[5] = 3 intent_code = NIFTI_INTENT_VECTOR - A single time series with a 3x3 matrix at each point: - dim[0] = 5 - dim[1] = 1 xyzt_units = NIFTI_UNITS_SEC - dim[2] = 1 - dim[3] = 1 - dim[4] = 1200 pixdim[4] = 0.2 - dim[5] = 9 intent_code = NIFTI_INTENT_GENMATRIX - intent_p1 = intent_p2 = 3.0 (indicates matrix dimensions) -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* DATA STORAGE: ------------ If the magic field is "n+1", then the voxel data is stored in the same file as the header. In this case, the voxel data starts at offset (int)vox_offset into the header file. Thus, vox_offset=352.0 means that the data starts immediately after the NIFTI-1 header. If vox_offset is greater than 352, the NIFTI-1 format does not say much about the contents of the dataset file between the end of the header and the start of the data. FILES: ----- If the magic field is "ni1", then the voxel data is stored in the associated ".img" file, starting at offset 0 (i.e., vox_offset is not used in this case, and should be set to 0.0). When storing NIFTI-1 datasets in pairs of files, it is customary to name the files in the pattern "name.hdr" and "name.img", as in ANALYZE 7.5. When storing in a single file ("n+1"), the file name should be in the form "name.nii" (the ".nft" and ".nif" suffixes are already taken; cf. http://www.icdatamaster.com/n.html ). BYTE ORDERING: ------------- The byte order of the data arrays is presumed to be the same as the byte order of the header (which is determined by examining dim[0]). Floating point types are presumed to be stored in IEEE-754 format. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* DETAILS ABOUT vox_offset: ------------------------ In a .nii file, the vox_offset field value is interpreted as the start location of the image data bytes in that file. In a .hdr/.img file pair, the vox_offset field value is the start location of the image data bytes in the .img file. * If vox_offset is less than 352 in a .nii file, it is equivalent to 352 (i.e., image data never starts before byte #352 in a .nii file). * The default value for vox_offset in a .nii file is 352. * In a .hdr file, the default value for vox_offset is 0. * vox_offset should be an integer multiple of 16; otherwise, some programs may not work properly (e.g., SPM). This is to allow memory-mapped input to be properly byte-aligned. Note that since vox_offset is an IEEE-754 32 bit float (for compatibility with the ANALYZE-7.5 format), it effectively has a 24 bit mantissa. All integers from 0 to 2^24 can be represented exactly in this format, but not all larger integers are exactly storable as IEEE-754 32 bit floats. However, unless you plan to have vox_offset be potentially larger than 16 MB, this should not be an issue. (Actually, any integral multiple of 16 up to 2^27 can be represented exactly in this format, which allows for up to 128 MB of random information before the image data. If that isn't enough, then perhaps this format isn't right for you.) In a .img file (i.e., image data stored separately from the NIfTI-1 header), data bytes between #0 and #vox_offset-1 (inclusive) are completely undefined and unregulated by the NIfTI-1 standard. One potential use of having vox_offset > 0 in the .hdr/.img file pair storage method is to make the .img file be a copy of (or link to) a pre-existing image file in some other format, such as DICOM; then vox_offset would be set to the offset of the image data in this file. (It may not be possible to follow the "multiple-of-16 rule" with an arbitrary external file; using the NIfTI-1 format in such a case may lead to a file that is incompatible with software that relies on vox_offset being a multiple of 16.) In a .nii file, data bytes between #348 and #vox_offset-1 (inclusive) may be used to store user-defined extra information; similarly, in a .hdr file, any data bytes after byte #347 are available for user-defined extra information. The (very weak) regulation of this extra header data is described elsewhere. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* DATA SCALING: ------------ If the scl_slope field is nonzero, then each voxel value in the dataset should be scaled as y = scl_slope * x + scl_inter where x = voxel value stored y = "true" voxel value Normally, we would expect this scaling to be used to store "true" floating values in a smaller integer datatype, but that is not required. That is, it is legal to use scaling even if the datatype is a float type (crazy, perhaps, but legal). - However, the scaling is to be ignored if datatype is DT_RGB24. - If datatype is a complex type, then the scaling is to be applied to both the real and imaginary parts. The cal_min and cal_max fields (if nonzero) are used for mapping (possibly scaled) dataset values to display colors: - Minimum display intensity (black) corresponds to dataset value cal_min. - Maximum display intensity (white) corresponds to dataset value cal_max. - Dataset values below cal_min should display as black also, and values above cal_max as white. - Colors "black" and "white", of course, may refer to any scalar display scheme (e.g., a color lookup table specified via aux_file). - cal_min and cal_max only make sense when applied to scalar-valued datasets (i.e., dim[0] < 5 or dim[5] = 1). -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* TYPE OF DATA (acceptable values for datatype field): --------------------------------------------------- Values of datatype smaller than 256 are ANALYZE 7.5 compatible. Larger values are NIFTI-1 additions. These are all multiples of 256, so that no bits below position 8 are set in datatype. But there is no need to use only powers-of-2, as the original ANALYZE 7.5 datatype codes do. The additional codes are intended to include a complete list of basic scalar types, including signed and unsigned integers from 8 to 64 bits, floats from 32 to 128 bits, and complex (float pairs) from 64 to 256 bits. Note that most programs will support only a few of these datatypes! A NIFTI-1 program should fail gracefully (e.g., print a warning message) when it encounters a dataset with a type it doesn't like. -----------------------------------------------------------------------------*/ #undef DT_UNKNOWN /* defined in dirent.h on some Unix systems */ /*! \defgroup NIFTI1_DATATYPES \brief nifti1 datatype codes @{ */ /*--- the original ANALYZE 7.5 type codes ---*/ #define DT_NONE 0 #define DT_UNKNOWN 0 /* what it says, dude */ #define DT_BINARY 1 /* binary (1 bit/voxel) */ #define DT_UNSIGNED_CHAR 2 /* unsigned char (8 bits/voxel) */ #define DT_SIGNED_SHORT 4 /* signed short (16 bits/voxel) */ #define DT_SIGNED_INT 8 /* signed int (32 bits/voxel) */ #define DT_FLOAT 16 /* float (32 bits/voxel) */ #define DT_COMPLEX 32 /* complex (64 bits/voxel) */ #define DT_DOUBLE 64 /* double (64 bits/voxel) */ #define DT_RGB 128 /* RGB triple (24 bits/voxel) */ #define DT_ALL 255 /* not very useful (?) */ /*----- another set of names for the same ---*/ #define DT_UINT8 2 #define DT_INT16 4 #define DT_INT32 8 #define DT_FLOAT32 16 #define DT_COMPLEX64 32 #define DT_FLOAT64 64 #define DT_RGB24 128 /*------------------- new codes for NIFTI ---*/ #define DT_INT8 256 /* signed char (8 bits) */ #define DT_UINT16 512 /* unsigned short (16 bits) */ #define DT_UINT32 768 /* unsigned int (32 bits) */ #define DT_INT64 1024 /* long long (64 bits) */ #define DT_UINT64 1280 /* unsigned long long (64 bits) */ #define DT_FLOAT128 1536 /* long double (128 bits) */ #define DT_COMPLEX128 1792 /* double pair (128 bits) */ #define DT_COMPLEX256 2048 /* long double pair (256 bits) */ #define DT_RGBA32 2304 /* 4 byte RGBA (32 bits/voxel) */ /* @} */ /*------- aliases for all the above codes ---*/ /*! \defgroup NIFTI1_DATATYPE_ALIASES \brief aliases for the nifti1 datatype codes @{ */ /*! unsigned char. */ #define NIFTI_TYPE_UINT8 2 /*! signed short. */ #define NIFTI_TYPE_INT16 4 /*! signed int. */ #define NIFTI_TYPE_INT32 8 /*! 32 bit float. */ #define NIFTI_TYPE_FLOAT32 16 /*! 64 bit complex = 2 32 bit floats. */ #define NIFTI_TYPE_COMPLEX64 32 /*! 64 bit float = double. */ #define NIFTI_TYPE_FLOAT64 64 /*! 3 8 bit bytes. */ #define NIFTI_TYPE_RGB24 128 /*! signed char. */ #define NIFTI_TYPE_INT8 256 /*! unsigned short. */ #define NIFTI_TYPE_UINT16 512 /*! unsigned int. */ #define NIFTI_TYPE_UINT32 768 /*! signed long long. */ #define NIFTI_TYPE_INT64 1024 /*! unsigned long long. */ #define NIFTI_TYPE_UINT64 1280 /*! 128 bit float = long double. */ #define NIFTI_TYPE_FLOAT128 1536 /*! 128 bit complex = 2 64 bit floats. */ #define NIFTI_TYPE_COMPLEX128 1792 /*! 256 bit complex = 2 128 bit floats */ #define NIFTI_TYPE_COMPLEX256 2048 /*! 4 8 bit bytes. */ #define NIFTI_TYPE_RGBA32 2304 /* @} */ /*-------- sample typedefs for complicated types ---*/ #if 0 typedef struct { float r,i; } complex_float ; typedef struct { double r,i; } complex_double ; typedef struct { long double r,i; } complex_longdouble ; typedef struct { unsigned char r,g,b; } rgb_byte ; #endif /*---------------------------------------------------------------------------*/ /* INTERPRETATION OF VOXEL DATA: ---------------------------- The intent_code field can be used to indicate that the voxel data has some particular meaning. In particular, a large number of codes is given to indicate that the the voxel data should be interpreted as being drawn from a given probability distribution. VECTOR-VALUED DATASETS: ---------------------- The 5th dimension of the dataset, if present (i.e., dim[0]=5 and dim[5] > 1), contains multiple values (e.g., a vector) to be stored at each spatiotemporal location. For example, the header values - dim[0] = 5 - dim[1] = 64 - dim[2] = 64 - dim[3] = 20 - dim[4] = 1 (indicates no time axis) - dim[5] = 3 - datatype = DT_FLOAT - intent_code = NIFTI_INTENT_VECTOR mean that this dataset should be interpreted as a 3D volume (64x64x20), with a 3-vector of floats defined at each point in the 3D grid. A program reading a dataset with a 5th dimension may want to reformat the image data to store each voxels' set of values together in a struct or array. This programming detail, however, is beyond the scope of the NIFTI-1 file specification! Uses of dimensions 6 and 7 are also not specified here. STATISTICAL PARAMETRIC DATASETS (i.e., SPMs): -------------------------------------------- Values of intent_code from NIFTI_FIRST_STATCODE to NIFTI_LAST_STATCODE (inclusive) indicate that the numbers in the dataset should be interpreted as being drawn from a given distribution. Most such distributions have auxiliary parameters (e.g., NIFTI_INTENT_TTEST has 1 DOF parameter). If the dataset DOES NOT have a 5th dimension, then the auxiliary parameters are the same for each voxel, and are given in header fields intent_p1, intent_p2, and intent_p3. If the dataset DOES have a 5th dimension, then the auxiliary parameters are different for each voxel. For example, the header values - dim[0] = 5 - dim[1] = 128 - dim[2] = 128 - dim[3] = 1 (indicates a single slice) - dim[4] = 1 (indicates no time axis) - dim[5] = 2 - datatype = DT_FLOAT - intent_code = NIFTI_INTENT_TTEST mean that this is a 2D dataset (128x128) of t-statistics, with the t-statistic being in the first "plane" of data and the degrees-of-freedom parameter being in the second "plane" of data. If the dataset 5th dimension is used to store the voxel-wise statistical parameters, then dim[5] must be 1 plus the number of parameters required by that distribution (e.g., intent_code=NIFTI_INTENT_TTEST implies dim[5] must be 2, as in the example just above). Note: intent_code values 2..10 are compatible with AFNI 1.5x (which is why there is no code with value=1, which is obsolescent in AFNI). OTHER INTENTIONS: ---------------- The purpose of the intent_* fields is to help interpret the values stored in the dataset. Some non-statistical values for intent_code and conventions are provided for storing other complex data types. The intent_name field provides space for a 15 character (plus 0 byte) 'name' string for the type of data stored. Examples: - intent_code = NIFTI_INTENT_ESTIMATE; intent_name = "T1"; could be used to signify that the voxel values are estimates of the NMR parameter T1. - intent_code = NIFTI_INTENT_TTEST; intent_name = "House"; could be used to signify that the voxel values are t-statistics for the significance of 'activation' response to a House stimulus. - intent_code = NIFTI_INTENT_DISPVECT; intent_name = "ToMNI152"; could be used to signify that the voxel values are a displacement vector that transforms each voxel (x,y,z) location to the corresponding location in the MNI152 standard brain. - intent_code = NIFTI_INTENT_SYMMATRIX; intent_name = "DTI"; could be used to signify that the voxel values comprise a diffusion tensor image. If no data name is implied or needed, intent_name[0] should be set to 0. -----------------------------------------------------------------------------*/ /*! default: no intention is indicated in the header. */ #define NIFTI_INTENT_NONE 0 /*-------- These codes are for probability distributions ---------------*/ /* Most distributions have a number of parameters, below denoted by p1, p2, and p3, and stored in - intent_p1, intent_p2, intent_p3 if dataset doesn't have 5th dimension - image data array if dataset does have 5th dimension Functions to compute with many of the distributions below can be found in the CDF library from U Texas. Formulas for and discussions of these distributions can be found in the following books: [U] Univariate Discrete Distributions, NL Johnson, S Kotz, AW Kemp. [C1] Continuous Univariate Distributions, vol. 1, NL Johnson, S Kotz, N Balakrishnan. [C2] Continuous Univariate Distributions, vol. 2, NL Johnson, S Kotz, N Balakrishnan. */ /*----------------------------------------------------------------------*/ /*! [C2, chap 32] Correlation coefficient R (1 param): p1 = degrees of freedom R/sqrt(1-R*R) is t-distributed with p1 DOF. */ /*! \defgroup NIFTI1_INTENT_CODES \brief nifti1 intent codes, to describe intended meaning of dataset contents @{ */ #define NIFTI_INTENT_CORREL 2 /*! [C2, chap 28] Student t statistic (1 param): p1 = DOF. */ #define NIFTI_INTENT_TTEST 3 /*! [C2, chap 27] Fisher F statistic (2 params): p1 = numerator DOF, p2 = denominator DOF. */ #define NIFTI_INTENT_FTEST 4 /*! [C1, chap 13] Standard normal (0 params): Density = N(0,1). */ #define NIFTI_INTENT_ZSCORE 5 /*! [C1, chap 18] Chi-squared (1 param): p1 = DOF. Density(x) proportional to exp(-x/2) * x^(p1/2-1). */ #define NIFTI_INTENT_CHISQ 6 /*! [C2, chap 25] Beta distribution (2 params): p1=a, p2=b. Density(x) proportional to x^(a-1) * (1-x)^(b-1). */ #define NIFTI_INTENT_BETA 7 /*! [U, chap 3] Binomial distribution (2 params): p1 = number of trials, p2 = probability per trial. Prob(x) = (p1 choose x) * p2^x * (1-p2)^(p1-x), for x=0,1,...,p1. */ #define NIFTI_INTENT_BINOM 8 /*! [C1, chap 17] Gamma distribution (2 params): p1 = shape, p2 = scale. Density(x) proportional to x^(p1-1) * exp(-p2*x). */ #define NIFTI_INTENT_GAMMA 9 /*! [U, chap 4] Poisson distribution (1 param): p1 = mean. Prob(x) = exp(-p1) * p1^x / x! , for x=0,1,2,.... */ #define NIFTI_INTENT_POISSON 10 /*! [C1, chap 13] Normal distribution (2 params): p1 = mean, p2 = standard deviation. */ #define NIFTI_INTENT_NORMAL 11 /*! [C2, chap 30] Noncentral F statistic (3 params): p1 = numerator DOF, p2 = denominator DOF, p3 = numerator noncentrality parameter. */ #define NIFTI_INTENT_FTEST_NONC 12 /*! [C2, chap 29] Noncentral chi-squared statistic (2 params): p1 = DOF, p2 = noncentrality parameter. */ #define NIFTI_INTENT_CHISQ_NONC 13 /*! [C2, chap 23] Logistic distribution (2 params): p1 = location, p2 = scale. Density(x) proportional to sech^2((x-p1)/(2*p2)). */ #define NIFTI_INTENT_LOGISTIC 14 /*! [C2, chap 24] Laplace distribution (2 params): p1 = location, p2 = scale. Density(x) proportional to exp(-abs(x-p1)/p2). */ #define NIFTI_INTENT_LAPLACE 15 /*! [C2, chap 26] Uniform distribution: p1 = lower end, p2 = upper end. */ #define NIFTI_INTENT_UNIFORM 16 /*! [C2, chap 31] Noncentral t statistic (2 params): p1 = DOF, p2 = noncentrality parameter. */ #define NIFTI_INTENT_TTEST_NONC 17 /*! [C1, chap 21] Weibull distribution (3 params): p1 = location, p2 = scale, p3 = power. Density(x) proportional to ((x-p1)/p2)^(p3-1) * exp(-((x-p1)/p2)^p3) for x > p1. */ #define NIFTI_INTENT_WEIBULL 18 /*! [C1, chap 18] Chi distribution (1 param): p1 = DOF. Density(x) proportional to x^(p1-1) * exp(-x^2/2) for x > 0. p1 = 1 = 'half normal' distribution p1 = 2 = Rayleigh distribution p1 = 3 = Maxwell-Boltzmann distribution. */ #define NIFTI_INTENT_CHI 19 /*! [C1, chap 15] Inverse Gaussian (2 params): p1 = mu, p2 = lambda Density(x) proportional to exp(-p2*(x-p1)^2/(2*p1^2*x)) / x^3 for x > 0. */ #define NIFTI_INTENT_INVGAUSS 20 /*! [C2, chap 22] Extreme value type I (2 params): p1 = location, p2 = scale cdf(x) = exp(-exp(-(x-p1)/p2)). */ #define NIFTI_INTENT_EXTVAL 21 /*! Data is a 'p-value' (no params). */ #define NIFTI_INTENT_PVAL 22 /*! Data is ln(p-value) (no params). To be safe, a program should compute p = exp(-abs(this_value)). The nifti_stats.c library returns this_value as positive, so that this_value = -log(p). */ #define NIFTI_INTENT_LOGPVAL 23 /*! Data is log10(p-value) (no params). To be safe, a program should compute p = pow(10.,-abs(this_value)). The nifti_stats.c library returns this_value as positive, so that this_value = -log10(p). */ #define NIFTI_INTENT_LOG10PVAL 24 /*! Smallest intent_code that indicates a statistic. */ #define NIFTI_FIRST_STATCODE 2 /*! Largest intent_code that indicates a statistic. */ #define NIFTI_LAST_STATCODE 24 /*---------- these values for intent_code aren't for statistics ----------*/ /*! To signify that the value at each voxel is an estimate of some parameter, set intent_code = NIFTI_INTENT_ESTIMATE. The name of the parameter may be stored in intent_name. */ #define NIFTI_INTENT_ESTIMATE 1001 /*! To signify that the value at each voxel is an index into some set of labels, set intent_code = NIFTI_INTENT_LABEL. The filename with the labels may stored in aux_file. */ #define NIFTI_INTENT_LABEL 1002 /*! To signify that the value at each voxel is an index into the NeuroNames labels set, set intent_code = NIFTI_INTENT_NEURONAME. */ #define NIFTI_INTENT_NEURONAME 1003 /*! To store an M x N matrix at each voxel: - dataset must have a 5th dimension (dim[0]=5 and dim[5]>1) - intent_code must be NIFTI_INTENT_GENMATRIX - dim[5] must be M*N - intent_p1 must be M (in float format) - intent_p2 must be N (ditto) - the matrix values A[i][[j] are stored in row-order: - A[0][0] A[0][1] ... A[0][N-1] - A[1][0] A[1][1] ... A[1][N-1] - etc., until - A[M-1][0] A[M-1][1] ... A[M-1][N-1] */ #define NIFTI_INTENT_GENMATRIX 1004 /*! To store an NxN symmetric matrix at each voxel: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_SYMMATRIX - dim[5] must be N*(N+1)/2 - intent_p1 must be N (in float format) - the matrix values A[i][[j] are stored in row-order: - A[0][0] - A[1][0] A[1][1] - A[2][0] A[2][1] A[2][2] - etc.: row-by-row */ #define NIFTI_INTENT_SYMMATRIX 1005 /*! To signify that the vector value at each voxel is to be taken as a displacement field or vector: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_DISPVECT - dim[5] must be the dimensionality of the displacment vector (e.g., 3 for spatial displacement, 2 for in-plane) */ #define NIFTI_INTENT_DISPVECT 1006 /* specifically for displacements */ #define NIFTI_INTENT_VECTOR 1007 /* for any other type of vector */ /*! To signify that the vector value at each voxel is really a spatial coordinate (e.g., the vertices or nodes of a surface mesh): - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_POINTSET - dim[0] = 5 - dim[1] = number of points - dim[2] = dim[3] = dim[4] = 1 - dim[5] must be the dimensionality of space (e.g., 3 => 3D space). - intent_name may describe the object these points come from (e.g., "pial", "gray/white" , "EEG", "MEG"). */ #define NIFTI_INTENT_POINTSET 1008 /*! To signify that the vector value at each voxel is really a triple of indexes (e.g., forming a triangle) from a pointset dataset: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_TRIANGLE - dim[0] = 5 - dim[1] = number of triangles - dim[2] = dim[3] = dim[4] = 1 - dim[5] = 3 - datatype should be an integer type (preferably DT_INT32) - the data values are indexes (0,1,...) into a pointset dataset. */ #define NIFTI_INTENT_TRIANGLE 1009 /*! To signify that the vector value at each voxel is a quaternion: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_QUATERNION - dim[0] = 5 - dim[5] = 4 - datatype should be a floating point type */ #define NIFTI_INTENT_QUATERNION 1010 /*! Dimensionless value - no params - although, as in _ESTIMATE the name of the parameter may be stored in intent_name. */ #define NIFTI_INTENT_DIMLESS 1011 /*---------- these values apply to GIFTI datasets ----------*/ /*! To signify that the value at each location is from a time series. */ #define NIFTI_INTENT_TIME_SERIES 2001 /*! To signify that the value at each location is a node index, from a complete surface dataset. */ #define NIFTI_INTENT_NODE_INDEX 2002 /*! To signify that the vector value at each location is an RGB triplet, of whatever type. - dataset must have a 5th dimension - dim[0] = 5 - dim[1] = number of nodes - dim[2] = dim[3] = dim[4] = 1 - dim[5] = 3 */ #define NIFTI_INTENT_RGB_VECTOR 2003 /*! To signify that the vector value at each location is a 4 valued RGBA vector, of whatever type. - dataset must have a 5th dimension - dim[0] = 5 - dim[1] = number of nodes - dim[2] = dim[3] = dim[4] = 1 - dim[5] = 4 */ #define NIFTI_INTENT_RGBA_VECTOR 2004 /*! To signify that the value at each location is a shape value, such as the curvature. */ #define NIFTI_INTENT_SHAPE 2005 /*! The following intent codes have been used by FSL FNIRT for displacement/coefficient files. These codes are included to prevent clashes in community-created extensions to NIfTI. Encoding and decoding behavior for these intents is not specified by the standard, and support is OPTIONAL for conforming implementations. */ #define NIFTI_INTENT_FSL_FNIRT_DISPLACEMENT_FIELD 2006 #define NIFTI_INTENT_FSL_CUBIC_SPLINE_COEFFICIENTS 2007 #define NIFTI_INTENT_FSL_DCT_COEFFICIENTS 2008 #define NIFTI_INTENT_FSL_QUADRATIC_SPLINE_COEFFICIENTS 2009 /*! The following intent codes have been used by FSL TOPUP for displacement/coefficient files. These codes are included to prevent clashes in community-created extensions to NIfTI. Encoding and decoding behavior for these intents is not specified by the standard, and support is OPTIONAL for conforming implementations. */ #define NIFTI_INTENT_FSL_TOPUP_CUBIC_SPLINE_COEFFICIENTS 2016 #define NIFTI_INTENT_FSL_TOPUP_QUADRATIC_SPLINE_COEFFICIENTS 2017 #define NIFTI_INTENT_FSL_TOPUP_FIELD 2018 /* @} */ /*---------------------------------------------------------------------------*/ /* 3D IMAGE (VOLUME) ORIENTATION AND LOCATION IN SPACE: --------------------------------------------------- There are 3 different methods by which continuous coordinates can attached to voxels. The discussion below emphasizes 3D volumes, and the continuous coordinates are referred to as (x,y,z). The voxel index coordinates (i.e., the array indexes) are referred to as (i,j,k), with valid ranges: i = 0 .. dim[1]-1 j = 0 .. dim[2]-1 (if dim[0] >= 2) k = 0 .. dim[3]-1 (if dim[0] >= 3) The (x,y,z) coordinates refer to the CENTER of a voxel. In methods 2 and 3, the (x,y,z) axes refer to a subject-based coordinate system, with +x = Right +y = Anterior +z = Superior. This is a right-handed coordinate system. However, the exact direction these axes point with respect to the subject depends on qform_code (Method 2) and sform_code (Method 3). N.B.: The i index varies most rapidly, j index next, k index slowest. Thus, voxel (i,j,k) is stored starting at location (i + j*dim[1] + k*dim[1]*dim[2]) * (bitpix/8) into the dataset array. N.B.: The ANALYZE 7.5 coordinate system is +x = Left +y = Anterior +z = Superior which is a left-handed coordinate system. This backwardness is too difficult to tolerate, so this NIFTI-1 standard specifies the coordinate order which is most common in functional neuroimaging. N.B.: The 3 methods below all give the locations of the voxel centers in the (x,y,z) coordinate system. In many cases, programs will wish to display image data on some other grid. In such a case, the program will need to convert its desired (x,y,z) values into (i,j,k) values in order to extract (or interpolate) the image data. This operation would be done with the inverse transformation to those described below. N.B.: Method 2 uses a factor 'qfac' which is either -1 or 1; qfac is stored in the otherwise unused pixdim[0]. If pixdim[0]=0.0 (which should not occur), we take qfac=1. Of course, pixdim[0] is only used when reading a NIFTI-1 header, not when reading an ANALYZE 7.5 header. N.B.: The units of (x,y,z) can be specified using the xyzt_units field. METHOD 1 (the "old" way, used only when qform_code = 0): ------------------------------------------------------- The coordinate mapping from (i,j,k) to (x,y,z) is the ANALYZE 7.5 way. This is a simple scaling relationship: x = pixdim[1] * i y = pixdim[2] * j z = pixdim[3] * k No particular spatial orientation is attached to these (x,y,z) coordinates. (NIFTI-1 does not have the ANALYZE 7.5 orient field, which is not general and is often not set properly.) This method is not recommended, and is present mainly for compatibility with ANALYZE 7.5 files. METHOD 2 (used when qform_code > 0, which should be the "normal" case): --------------------------------------------------------------------- The (x,y,z) coordinates are given by the pixdim[] scales, a rotation matrix, and a shift. This method is intended to represent "scanner-anatomical" coordinates, which are often embedded in the image header (e.g., DICOM fields (0020,0032), (0020,0037), (0028,0030), and (0018,0050)), and represent the nominal orientation and location of the data. This method can also be used to represent "aligned" coordinates, which would typically result from some post-acquisition alignment of the volume to a standard orientation (e.g., the same subject on another day, or a rigid rotation to true anatomical orientation from the tilted position of the subject in the scanner). The formula for (x,y,z) in terms of header parameters and (i,j,k) is: [ x ] [ R11 R12 R13 ] [ pixdim[1] * i ] [ qoffset_x ] [ y ] = [ R21 R22 R23 ] [ pixdim[2] * j ] + [ qoffset_y ] [ z ] [ R31 R32 R33 ] [ qfac * pixdim[3] * k ] [ qoffset_z ] The qoffset_* shifts are in the NIFTI-1 header. Note that the center of the (i,j,k)=(0,0,0) voxel (first value in the dataset array) is just (x,y,z)=(qoffset_x,qoffset_y,qoffset_z). The rotation matrix R is calculated from the quatern_* parameters. This calculation is described below. The scaling factor qfac is either 1 or -1. The rotation matrix R defined by the quaternion parameters is "proper" (has determinant 1). This may not fit the needs of the data; for example, if the image grid is i increases from Left-to-Right j increases from Anterior-to-Posterior k increases from Inferior-to-Superior Then (i,j,k) is a left-handed triple. In this example, if qfac=1, the R matrix would have to be [ 1 0 0 ] [ 0 -1 0 ] which is "improper" (determinant = -1). [ 0 0 1 ] If we set qfac=-1, then the R matrix would be [ 1 0 0 ] [ 0 -1 0 ] which is proper. [ 0 0 -1 ] This R matrix is represented by quaternion [a,b,c,d] = [0,1,0,0] (which encodes a 180 degree rotation about the x-axis). METHOD 3 (used when sform_code > 0): ----------------------------------- The (x,y,z) coordinates are given by a general affine transformation of the (i,j,k) indexes: x = srow_x[0] * i + srow_x[1] * j + srow_x[2] * k + srow_x[3] y = srow_y[0] * i + srow_y[1] * j + srow_y[2] * k + srow_y[3] z = srow_z[0] * i + srow_z[1] * j + srow_z[2] * k + srow_z[3] The srow_* vectors are in the NIFTI_1 header. Note that no use is made of pixdim[] in this method. WHY 3 METHODS? -------------- Method 1 is provided only for backwards compatibility. The intention is that Method 2 (qform_code > 0) represents the nominal voxel locations as reported by the scanner, or as rotated to some fiducial orientation and location. Method 3, if present (sform_code > 0), is to be used to give the location of the voxels in some standard space. The sform_code indicates which standard space is present. Both methods 2 and 3 can be present, and be useful in different contexts (method 2 for displaying the data on its original grid; method 3 for displaying it on a standard grid). In this scheme, a dataset would originally be set up so that the Method 2 coordinates represent what the scanner reported. Later, a registration to some standard space can be computed and inserted in the header. Image display software can use either transform, depending on its purposes and needs. In Method 2, the origin of coordinates would generally be whatever the scanner origin is; for example, in MRI, (0,0,0) is the center of the gradient coil. In Method 3, the origin of coordinates would depend on the value of sform_code; for example, for the Talairach coordinate system, (0,0,0) corresponds to the Anterior Commissure. QUATERNION REPRESENTATION OF ROTATION MATRIX (METHOD 2) ------------------------------------------------------- The orientation of the (x,y,z) axes relative to the (i,j,k) axes in 3D space is specified using a unit quaternion [a,b,c,d], where a*a+b*b+c*c+d*d=1. The (b,c,d) values are all that is needed, since we require that a = sqrt(1.0-(b*b+c*c+d*d)) be nonnegative. The (b,c,d) values are stored in the (quatern_b,quatern_c,quatern_d) fields. The quaternion representation is chosen for its compactness in representing rotations. The (proper) 3x3 rotation matrix that corresponds to [a,b,c,d] is [ a*a+b*b-c*c-d*d 2*b*c-2*a*d 2*b*d+2*a*c ] R = [ 2*b*c+2*a*d a*a+c*c-b*b-d*d 2*c*d-2*a*b ] [ 2*b*d-2*a*c 2*c*d+2*a*b a*a+d*d-c*c-b*b ] [ R11 R12 R13 ] = [ R21 R22 R23 ] [ R31 R32 R33 ] If (p,q,r) is a unit 3-vector, then rotation of angle h about that direction is represented by the quaternion [a,b,c,d] = [cos(h/2), p*sin(h/2), q*sin(h/2), r*sin(h/2)]. Requiring a >= 0 is equivalent to requiring -Pi <= h <= Pi. (Note that [-a,-b,-c,-d] represents the same rotation as [a,b,c,d]; there are 2 quaternions that can be used to represent a given rotation matrix R.) To rotate a 3-vector (x,y,z) using quaternions, we compute the quaternion product [0,x',y',z'] = [a,b,c,d] * [0,x,y,z] * [a,-b,-c,-d] which is equivalent to the matrix-vector multiply [ x' ] [ x ] [ y' ] = R [ y ] (equivalence depends on a*a+b*b+c*c+d*d=1) [ z' ] [ z ] Multiplication of 2 quaternions is defined by the following: [a,b,c,d] = a*1 + b*I + c*J + d*K where I*I = J*J = K*K = -1 (I,J,K are square roots of -1) I*J = K J*K = I K*I = J J*I = -K K*J = -I I*K = -J (not commutative!) For example [a,b,0,0] * [0,0,0,1] = [0,0,-b,a] since this expands to (a+b*I)*(K) = (a*K+b*I*K) = (a*K-b*J). The above formula shows how to go from quaternion (b,c,d) to rotation matrix and direction cosines. Conversely, given R, we can compute the fields for the NIFTI-1 header by a = 0.5 * sqrt(1+R11+R22+R33) (not stored) b = 0.25 * (R32-R23) / a => quatern_b c = 0.25 * (R13-R31) / a => quatern_c d = 0.25 * (R21-R12) / a => quatern_d If a=0 (a 180 degree rotation), alternative formulas are needed. See the nifti1_io.c function mat44_to_quatern() for an implementation of the various cases in converting R to [a,b,c,d]. Note that R-transpose (= R-inverse) would lead to the quaternion [a,-b,-c,-d]. The choice to specify the qoffset_x (etc.) values in the final coordinate system is partly to make it easy to convert DICOM images to this format. The DICOM attribute "Image Position (Patient)" (0020,0032) stores the (Xd,Yd,Zd) coordinates of the center of the first voxel. Here, (Xd,Yd,Zd) refer to DICOM coordinates, and Xd=-x, Yd=-y, Zd=z, where (x,y,z) refers to the NIFTI coordinate system discussed above. (i.e., DICOM +Xd is Left, +Yd is Posterior, +Zd is Superior, whereas +x is Right, +y is Anterior , +z is Superior. ) Thus, if the (0020,0032) DICOM attribute is extracted into (px,py,pz), then qoffset_x = -px qoffset_y = -py qoffset_z = pz is a reasonable setting when qform_code=NIFTI_XFORM_SCANNER_ANAT. That is, DICOM's coordinate system is 180 degrees rotated about the z-axis from the neuroscience/NIFTI coordinate system. To transform between DICOM and NIFTI, you just have to negate the x- and y-coordinates. The DICOM attribute (0020,0037) "Image Orientation (Patient)" gives the orientation of the x- and y-axes of the image data in terms of 2 3-vectors. The first vector is a unit vector along the x-axis, and the second is along the y-axis. If the (0020,0037) attribute is extracted into the value (xa,xb,xc,ya,yb,yc), then the first two columns of the R matrix would be [ -xa -ya ] [ -xb -yb ] [ xc yc ] The negations are because DICOM's x- and y-axes are reversed relative to NIFTI's. The third column of the R matrix gives the direction of displacement (relative to the subject) along the slice-wise direction. This orientation is not encoded in the DICOM standard in a simple way; DICOM is mostly concerned with 2D images. The third column of R will be either the cross-product of the first 2 columns or its negative. It is possible to infer the sign of the 3rd column by examining the coordinates in DICOM attribute (0020,0032) "Image Position (Patient)" for successive slices. However, this method occasionally fails for reasons that I (RW Cox) do not understand. -----------------------------------------------------------------------------*/ /* [qs]form_code value: */ /* x,y,z coordinate system refers to: */ /*-----------------------*/ /*---------------------------------------*/ /*! \defgroup NIFTI1_XFORM_CODES \brief nifti1 xform codes to describe the "standard" coordinate system @{ */ /*! Arbitrary coordinates (Method 1). */ #define NIFTI_XFORM_UNKNOWN 0 /*! Scanner-based anatomical coordinates */ #define NIFTI_XFORM_SCANNER_ANAT 1 /*! Coordinates aligned to another file's, or to anatomical "truth". */ #define NIFTI_XFORM_ALIGNED_ANAT 2 /*! Coordinates aligned to Talairach- Tournoux Atlas; (0,0,0)=AC, etc. */ #define NIFTI_XFORM_TALAIRACH 3 /*! MNI 152 normalized coordinates. */ #define NIFTI_XFORM_MNI_152 4 /*! Normalized coordinates (for any general standard template space). Added March 8, 2019. */ #define NIFTI_XFORM_TEMPLATE_OTHER 5 /* @} */ /*---------------------------------------------------------------------------*/ /* UNITS OF SPATIAL AND TEMPORAL DIMENSIONS: ---------------------------------------- The codes below can be used in xyzt_units to indicate the units of pixdim. As noted earlier, dimensions 1,2,3 are for x,y,z; dimension 4 is for time (t). - If dim[4]=1 or dim[0] < 4, there is no time axis. - A single time series (no space) would be specified with - dim[0] = 4 (for scalar data) or dim[0] = 5 (for vector data) - dim[1] = dim[2] = dim[3] = 1 - dim[4] = number of time points - pixdim[4] = time step - xyzt_units indicates units of pixdim[4] - dim[5] = number of values stored at each time point Bits 0..2 of xyzt_units specify the units of pixdim[1..3] (e.g., spatial units are values 1..7). Bits 3..5 of xyzt_units specify the units of pixdim[4] (e.g., temporal units are multiples of 8). This compression of 2 distinct concepts into 1 byte is due to the limited space available in the 348 byte ANALYZE 7.5 header. The macros XYZT_TO_SPACE and XYZT_TO_TIME can be used to mask off the undesired bits from the xyzt_units fields, leaving "pure" space and time codes. Inversely, the macro SPACE_TIME_TO_XYZT can be used to assemble a space code (0,1,2,...,7) with a time code (0,8,16,32,...,56) into the combined value for xyzt_units. Note that codes are provided to indicate the "time" axis units are actually frequency in Hertz (_HZ), in part-per-million (_PPM) or in radians-per-second (_RADS). The toffset field can be used to indicate a nonzero start point for the time axis. That is, time point #m is at t=toffset+m*pixdim[4] for m=0..dim[4]-1. -----------------------------------------------------------------------------*/ /*! \defgroup NIFTI1_UNITS \brief nifti1 units codes to describe the unit of measurement for each dimension of the dataset @{ */ /*! NIFTI code for unspecified units. */ #define NIFTI_UNITS_UNKNOWN 0 /** Space codes are multiples of 1. **/ /*! NIFTI code for meters. */ #define NIFTI_UNITS_METER 1 /*! NIFTI code for millimeters. */ #define NIFTI_UNITS_MM 2 /*! NIFTI code for micrometers. */ #define NIFTI_UNITS_MICRON 3 /** Time codes are multiples of 8. **/ /*! NIFTI code for seconds. */ #define NIFTI_UNITS_SEC 8 /*! NIFTI code for milliseconds. */ #define NIFTI_UNITS_MSEC 16 /*! NIFTI code for microseconds. */ #define NIFTI_UNITS_USEC 24 /*** These units are for spectral data: ***/ /*! NIFTI code for Hertz. */ #define NIFTI_UNITS_HZ 32 /*! NIFTI code for ppm. */ #define NIFTI_UNITS_PPM 40 /*! NIFTI code for radians per second. */ #define NIFTI_UNITS_RADS 48 /* @} */ #undef XYZT_TO_SPACE #undef XYZT_TO_TIME #define XYZT_TO_SPACE(xyzt) ( (xyzt) & 0x07 ) #define XYZT_TO_TIME(xyzt) ( (xyzt) & 0x38 ) #undef SPACE_TIME_TO_XYZT #define SPACE_TIME_TO_XYZT(ss,tt) ( (((char)(ss)) & 0x07) \ | (((char)(tt)) & 0x38) ) /*---------------------------------------------------------------------------*/ /* MRI-SPECIFIC SPATIAL AND TEMPORAL INFORMATION: --------------------------------------------- A few fields are provided to store some extra information that is sometimes important when storing the image data from an FMRI time series experiment. (After processing such data into statistical images, these fields are not likely to be useful.) { freq_dim } = These fields encode which spatial dimension (1,2, or 3) { phase_dim } = corresponds to which acquisition dimension for MRI data. { slice_dim } = Examples: Rectangular scan multi-slice EPI: freq_dim = 1 phase_dim = 2 slice_dim = 3 (or some permutation) Spiral scan multi-slice EPI: freq_dim = phase_dim = 0 slice_dim = 3 since the concepts of frequency- and phase-encoding directions don't apply to spiral scan slice_duration = If this is positive, AND if slice_dim is nonzero, indicates the amount of time used to acquire 1 slice. slice_duration*dim[slice_dim] can be less than pixdim[4] with a clustered acquisition method, for example. slice_code = If this is nonzero, AND if slice_dim is nonzero, AND if slice_duration is positive, indicates the timing pattern of the slice acquisition. The following codes are defined: NIFTI_SLICE_SEQ_INC == sequential increasing NIFTI_SLICE_SEQ_DEC == sequential decreasing NIFTI_SLICE_ALT_INC == alternating increasing NIFTI_SLICE_ALT_DEC == alternating decreasing NIFTI_SLICE_ALT_INC2 == alternating increasing #2 NIFTI_SLICE_ALT_DEC2 == alternating decreasing #2 { slice_start } = Indicates the start and end of the slice acquisition { slice_end } = pattern, when slice_code is nonzero. These values are present to allow for the possible addition of "padded" slices at either end of the volume, which don't fit into the slice timing pattern. If there are no padding slices, then slice_start=0 and slice_end=dim[slice_dim]-1 are the correct values. For these values to be meaningful, slice_start must be non-negative and slice_end must be greater than slice_start. Otherwise, they should be ignored. The following table indicates the slice timing pattern, relative to time=0 for the first slice acquired, for some sample cases. Here, dim[slice_dim]=7 (there are 7 slices, labeled 0..6), slice_duration=0.1, and slice_start=1, slice_end=5 (1 padded slice on each end). slice index SEQ_INC SEQ_DEC ALT_INC ALT_DEC ALT_INC2 ALT_DEC2 6 : n/a n/a n/a n/a n/a n/a n/a = not applicable 5 : 0.4 0.0 0.2 0.0 0.4 0.2 (slice time offset 4 : 0.3 0.1 0.4 0.3 0.1 0.0 doesn't apply to 3 : 0.2 0.2 0.1 0.1 0.3 0.3 slices outside 2 : 0.1 0.3 0.3 0.4 0.0 0.1 the range 1 : 0.0 0.4 0.0 0.2 0.2 0.4 slice_start .. 0 : n/a n/a n/a n/a n/a n/a slice_end) The SEQ slice_codes are sequential ordering (uncommon but not unknown), either increasing in slice number or decreasing (INC or DEC), as illustrated above. The ALT slice codes are alternating ordering. The 'standard' way for these to operate (without the '2' on the end) is for the slice timing to start at the edge of the slice_start .. slice_end group (at slice_start for INC and at slice_end for DEC). For the 'ALT_*2' slice_codes, the slice timing instead starts at the first slice in from the edge (at slice_start+1 for INC2 and at slice_end-1 for DEC2). This latter acquisition scheme is found on some Siemens scanners. The fields freq_dim, phase_dim, slice_dim are all squished into the single byte field dim_info (2 bits each, since the values for each field are limited to the range 0..3). This unpleasantness is due to lack of space in the 348 byte allowance. The macros DIM_INFO_TO_FREQ_DIM, DIM_INFO_TO_PHASE_DIM, and DIM_INFO_TO_SLICE_DIM can be used to extract these values from the dim_info byte. The macro FPS_INTO_DIM_INFO can be used to put these 3 values into the dim_info byte. -----------------------------------------------------------------------------*/ #undef DIM_INFO_TO_FREQ_DIM #undef DIM_INFO_TO_PHASE_DIM #undef DIM_INFO_TO_SLICE_DIM #define DIM_INFO_TO_FREQ_DIM(di) ( ((di) ) & 0x03 ) #define DIM_INFO_TO_PHASE_DIM(di) ( ((di) >> 2) & 0x03 ) #define DIM_INFO_TO_SLICE_DIM(di) ( ((di) >> 4) & 0x03 ) #undef FPS_INTO_DIM_INFO #define FPS_INTO_DIM_INFO(fd,pd,sd) ( ( ( ((char)(fd)) & 0x03) ) | \ ( ( ((char)(pd)) & 0x03) << 2 ) | \ ( ( ((char)(sd)) & 0x03) << 4 ) ) /*! \defgroup NIFTI1_SLICE_ORDER \brief nifti1 slice order codes, describing the acquisition order of the slices @{ */ #define NIFTI_SLICE_UNKNOWN 0 #define NIFTI_SLICE_SEQ_INC 1 #define NIFTI_SLICE_SEQ_DEC 2 #define NIFTI_SLICE_ALT_INC 3 #define NIFTI_SLICE_ALT_DEC 4 #define NIFTI_SLICE_ALT_INC2 5 /* 05 May 2005: RWCox */ #define NIFTI_SLICE_ALT_DEC2 6 /* 05 May 2005: RWCox */ /* @} */ /*---------------------------------------------------------------------------*/ /* UNUSED FIELDS: ------------- Some of the ANALYZE 7.5 fields marked as ++UNUSED++ may need to be set to particular values for compatibility with other programs. The issue of interoperability of ANALYZE 7.5 files is a murky one -- not all programs require exactly the same set of fields. (Unobscuring this murkiness is a principal motivation behind NIFTI-1.) Some of the fields that may need to be set for other (non-NIFTI aware) software to be happy are: extents dbh.h says this should be 16384 regular dbh.h says this should be the character 'r' glmin, } dbh.h says these values should be the min and max voxel glmax } values for the entire dataset It is best to initialize ALL fields in the NIFTI-1 header to 0 (e.g., with calloc()), then fill in what is needed. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* MISCELLANEOUS C MACROS -----------------------------------------------------------------------------*/ /*.................*/ /*! Given a nifti_1_header struct, check if it has a good magic number. Returns NIFTI version number (1..9) if magic is good, 0 if it is not. */ #define NIFTI_VERSION(h) \ ( ( (h).magic[0]=='n' && (h).magic[3]=='\0' && \ ( (h).magic[1]=='i' || (h).magic[1]=='+' ) && \ ( (h).magic[2]>='1' && (h).magic[2]<='9' ) ) \ ? (h).magic[2]-'0' : 0 ) /*.................*/ /*! Check if a nifti_1_header struct says if the data is stored in the same file or in a separate file. Returns 1 if the data is in the same file as the header, 0 if it is not. */ #define NIFTI_ONEFILE(h) ( (h).magic[1] == '+' ) /*.................*/ /*! Check if a nifti_1_header struct needs to be byte swapped. Returns 1 if it needs to be swapped, 0 if it does not. */ #define NIFTI_NEEDS_SWAP(h) ( (h).dim[0] < 0 || (h).dim[0] > 7 ) /*.................*/ /*! Check if a nifti_1_header struct contains a 5th (vector) dimension. Returns size of 5th dimension if > 1, returns 0 otherwise. */ #define NIFTI_5TH_DIM(h) ( ((h).dim[0]>4 && (h).dim[5]>1) ? (h).dim[5] : 0 ) /*****************************************************************************/ /*=================*/ #ifdef __cplusplus } #endif /*=================*/ #endif /* _NIFTI_HEADER_ */ nifti_clib-3.0.1/nifti2/nifti2.h000066400000000000000000000146671371325713600164020ustar00rootroot00000000000000/** \file nifti2.h \brief Header structure for NIFTI-2 format. */ #ifndef __NIFTI2_HEADER #define __NIFTI2_HEADER /*---------------------------------------------------------------------------*/ /* Changes to the header from NIFTI-1 to NIFTI-2 are intended to allow for larger and more accurate fields. The changes are as follows: - short dim[8] -> int64_t dim[8] - float intent_p1,2,3 -> double intent_p1,2,3 (3 fields) - float pixdim[8] -> double pixdim[8] - float vox_offset -> int64_t vox_offset - float scl_slope -> double scl_slope - float scl_inter -> double scl_inter - float cal_max -> double cal_max - float cal_min -> double cal_min - float slice_duration -> double slice_duration - float toffset -> double toffset - short slice_start -> int64_t slice_start - short slice_end -> int64_t slice_end - char slice_code -> int32_t slice_code - char xyzt_units -> int32_t xyzt_units - short intent_code -> int32_t intent_code - short qform_code -> int32_t qform_code - short sform_code -> int32_t sform_code - float quatern_b,c,d -> double quatern_b,c,d (3 fields) - float srow_x,y,z[4] -> double srow_x,y,z[4] (3 fields) - char magic[4] -> char magic[8] - char unused_str[15] -> padding added at the end of the header - previously unused fields have been removed: data_type, db_name, extents, session_error, regular, glmax, glmin - the field order has been changed, notably with magic after sizeof_hdr 2 Jan, 2014 [rickr] -----------------------------------------------------------------------------*/ #include /*=================*/ #ifdef __cplusplus extern "C" { #endif /*=================*/ /*! \struct nifti_2_header \brief Data structure defining the fields in the nifti2 header. This binary header should be found at the beginning of a valid NIFTI-2 header file. */ /* hopefully cross-platform solution to byte padding added by some compilers */ #pragma pack(push) #pragma pack(1) /*****************************/ /***********************/ /************/ struct nifti_2_header { /* NIFTI-2 usage */ /* NIFTI-1 usage */ /* offset */ /*****************************/ /***********************/ /************/ int32_t sizeof_hdr; /*!< MUST be 540 */ /* MUST be 348 */ /* 0 */ char magic[8]; /*!< MUST be valid signature */ /* char magic[4] */ /* 4 */ int16_t datatype; /*!< Defines data type! */ /* short datatype */ /* 12 */ int16_t bitpix; /*!< Number bits/voxel */ /* short bitpix */ /* 14 */ int64_t dim[8]; /*!< Data array dimensions */ /* short dim[8] */ /* 16 */ double intent_p1; /*!< 1st intent parameter */ /* float intent_p1 */ /* 80 */ double intent_p2; /*!< 2nd intent parameter */ /* float intent_p2 */ /* 88 */ double intent_p3; /*!< 3rd intent parameter */ /* float intent_p3 */ /* 96 */ double pixdim[8]; /*!< Grid spacings */ /* float pixdim[8] */ /* 104 */ int64_t vox_offset; /*!< Offset into .nii file */ /* float vox_offset */ /* 168 */ double scl_slope; /*!< Data scaling: slope */ /* float scl_slope */ /* 176 */ double scl_inter; /*!< Data scaling: offset */ /* float scl_inter */ /* 184 */ double cal_max; /*!< Max display intensity */ /* float cal_max */ /* 192 */ double cal_min; /*!< Min display intensity */ /* float cal_min */ /* 200 */ double slice_duration; /*!< Time for 1 slice */ /* float slice_duration*/ /* 208 */ double toffset; /*!< Time axis shift */ /* float toffset */ /* 216 */ int64_t slice_start; /*!< First slice index */ /* short slice_start */ /* 224 */ int64_t slice_end; /*!< Last slice index */ /* short slice_end */ /* 232 */ char descrip[80]; /*!< any text you like */ /* char descrip[80] */ /* 240 */ char aux_file[24]; /*!< auxiliary filename */ /* char aux_file[24] */ /* 320 */ int32_t qform_code; /*!< NIFTI_XFORM_* code */ /* short qform_code */ /* 344 */ int32_t sform_code; /*!< NIFTI_XFORM_* code */ /* short sform_code */ /* 348 */ double quatern_b; /*!< Quaternion b param */ /* float quatern_b */ /* 352 */ double quatern_c; /*!< Quaternion c param */ /* float quatern_c */ /* 360 */ double quatern_d; /*!< Quaternion d param */ /* float quatern_d */ /* 368 */ double qoffset_x; /*!< Quaternion x shift */ /* float qoffset_x */ /* 376 */ double qoffset_y; /*!< Quaternion y shift */ /* float qoffset_y */ /* 384 */ double qoffset_z; /*!< Quaternion z shift */ /* float qoffset_z */ /* 392 */ double srow_x[4]; /*!< 1st row affine transform*/ /* float srow_x[4] */ /* 400 */ double srow_y[4]; /*!< 2nd row affine transform*/ /* float srow_y[4] */ /* 432 */ double srow_z[4]; /*!< 3rd row affine transform*/ /* float srow_z[4] */ /* 464 */ int32_t slice_code; /*!< Slice timing order */ /* char slice_code */ /* 496 */ int32_t xyzt_units; /*!< Units of pixdim[1..4] */ /* char xyzt_units */ /* 500 */ int32_t intent_code; /*!< NIFTI_INTENT_* code */ /* short intent_code */ /* 504 */ char intent_name[16];/*!< name or meaning of data */ /* char intent_name[16]*/ /* 508 */ char dim_info; /*!< MRI slice ordering */ /* char dim_info */ /* 524 */ char unused_str[15]; /*!< unused, filled with \0 */ /* 525 */ }; /****** total bytes: 540 */ typedef struct nifti_2_header nifti_2_header; /* restore packing behavior */ #pragma pack(pop) /* base swap test on the suggested version check, rather than dim[0] swap4(348)==1543569408, swap4(540)==469893120 */ #define NIFTI2_NEEDS_SWAP(h) \ ((h).sizeof_hdr == 1543569408 || (h).sizeof_hdr == 469893120) /*=================*/ #ifdef __cplusplus } #endif /*=================*/ #endif /* __NIFTI2_HEADER */ nifti_clib-3.0.1/nifti2/nifti2_io.c000066400000000000000000012511761371325713600170630ustar00rootroot00000000000000#define _NIFTI2_IO_C_ #include "nifti2_io.h" /* typedefs, prototypes, macros, etc. */ #include "nifti2_io_version.h" /*****===================================================================*****/ /***** Sample functions to deal with NIFTI-1,2 and ANALYZE files *****/ /*****...................................................................*****/ /***** This code is released to the public domain. *****/ /*****...................................................................*****/ /***** Author: Robert W Cox, SSCC/DIRP/NIMH/NIH/DHHS/USA/EARTH *****/ /***** Date: August 2003 *****/ /*****...................................................................*****/ /***** Neither the National Institutes of Health (NIH), nor any of its *****/ /***** employees imply any warranty of usefulness of this software for *****/ /***** any purpose, and do not assume any liability for damages, *****/ /***** incidental or otherwise, caused by any use of this document. *****/ /*****===================================================================*****/ /** \file nifti1_io.c \brief main collection of nifti1 i/o routines - written by Bob Cox, SSCC NIMH - revised by Mark Jenkinson, FMRIB - revised by Rick Reynolds, SSCC, NIMH - revised by Kate Fissell, University of Pittsburgh The library history can be viewed via "nifti_tool -nifti_hist".
The library version can be viewed via "nifti_tool -nifti_ver". */ /*! global history and version strings, for printing */ static char const * const gni1_history[] = { "----------------------------------------------------------------------\n" "history (of nifti-1 library changes):\n" "\n", "0.0 August, 2003 [rwcox]\n" " (Robert W Cox of the National Institutes of Health, SSCC/DIRP/NIMH)\n" " - initial version\n" "\n", "0.1 July/August, 2004 [Mark Jenkinson]\n" " (FMRIB Centre, University of Oxford, UK)\n" " - Mainly adding low-level IO and changing things to allow gzipped\n" " files to be read and written\n" " - Full backwards compatability should have been maintained\n" "\n", "0.2 16 Nov 2004 [rickr]\n" " (Rick Reynolds of the National Institutes of Health, SSCC/DIRP/NIMH)\n" " - included Mark's changes in the AFNI distribution (including znzlib/)\n" " (HAVE_ZLIB is commented out for the standard distribution)\n" " - modified nifti_validfilename() and nifti_makebasename()\n" " - added nifti_find_file_extension()\n" "\n", "0.3 3 Dec 2004 [rickr]\n" " - note: header extensions are not yet checked for\n" " - added formatted history as global string, for printing\n" " - added nifti_disp_lib_hist(), to display the nifti library history\n" " - added nifti_disp_lib_version(), to display the nifti library history\n", " - re-wrote nifti_findhdrname()\n" " o used nifti_find_file_extension()\n" " o changed order of file tests (default is .nii, depends on input)\n" " o free hdrname on failure\n" " - made similar changes to nifti_findimgname()\n" " - check for NULL return from nifti_findhdrname() calls\n", " - removed most of ERREX() macros\n" " - modified nifti_image_read()\n" " o added debug info and error checking (on gni_debug > 0, only)\n" " o fail if workingname is NULL\n" " o check for failure to open header file\n" " o free workingname on failure\n" " o check for failure of nifti_image_load()\n" " o check for failure of nifti_convert_nhdr2nim()\n", " - changed nifti_image_load() to int, and check nifti_read_buffer return\n" " - changed nifti_read_buffer() to fail on short read, and to count float\n" " fixes (to print on debug)\n" " - changed nifti_image_infodump to print to stderr\n" " - updated function header comments, or moved comments above header\n" " - removed const keyword\n" " - added LNI_FERR() macro for error reporting on input files\n" "\n", "0.4 10 Dec 2004 [rickr] - added header extensions\n" " - in nifti1_io.h:\n" " o added num_ext and ext_list to the definition of nifti_image\n" " o made many functions static (more to follow)\n" " o added LNI_MAX_NIA_EXT_LEN, for max nifti_type 3 extension length\n", " - added __DATE__ to version output in nifti_disp_lib_version()\n" " - added nifti_disp_matrix_orient() to print orientation information\n" " - added '.nia' as a valid file extension in nifti_find_file_extension()\n" " - added much more debug output\n" " - in nifti_image_read(), in the case of an ASCII header, check for\n" " extensions after the end of the header\n", " - added nifti_read_extensions() function\n" " - added nifti_read_next_extension() function\n" " - added nifti_add_exten_to_list() function\n" " - added nifti_check_extension() function\n" " - added nifti_write_extensions() function\n" " - added nifti_extension_size() function\n" " - in nifti_set_iname_offest():\n" " o adjust offset by the extension size and the extender size\n", " o fixed the 'ceiling modulo 16' computation\n" " - in nifti_image_write_hdr_img2(): \n" " o added extension writing\n" " o check for NULL return from nifti_findimgname()\n" " - include number of extensions in nifti_image_to_ascii() output\n" " - in nifti_image_from_ascii():\n" " o return bytes_read as a parameter, computed from the final spos\n" " o extract num_ext from ASCII header\n" "\n", "0.5 14 Dec 2004 [rickr] - added sub-brick reading functions\n" " - added nifti_brick_list type to nifti1_io.h, along with new prototypes\n" " - added main nifti_image_read_bricks() function, with description\n" " - added nifti_image_load_bricks() - library function (requires nim)\n" " - added valid_nifti_brick_list() - library function\n" " - added free_NBL() - library function\n", " - added update_nifti_image_for_brick_list() for dimension update\n" " - added nifti_load_NBL_bricks(), nifti_alloc_NBL_mem(),\n" " nifti_copynsort() and force_positive() (static functions)\n" " - in nifti_image_read(), check for failed load only if read_data is set\n" " - broke most of nifti_image_load() into nifti_image_load_prep()\n" "\n", "0.6 15 Dec 2004 [rickr] - added sub-brick writing functionality\n" " - in nifti1_io.h, removed znzlib directory from include - all nifti\n" " library files are now under the nifti directory\n" " - nifti_read_extensions(): print no offset warning for nifti_type 3\n" " - nifti_write_all_data():\n" " o pass nifti_brick_list * NBL, for optional writing\n" " o if NBL, write each sub-brick, sequentially\n", " - nifti_set_iname_offset(): case 1 must have sizeof() cast to int\n" " - pass NBL to nifti_image_write_hdr_img2(), and allow NBL or data\n" " - added nifti_image_write_bricks() wrapper for ...write_hdr_img2()\n" " - included compression abilities\n" "\n", "0.7 16 Dec 2004 [rickr] - minor changes to extension reading\n" "\n", "0.8 21 Dec 2004 [rickr] - restrict extension reading, and minor changes\n" " - in nifti_image_read(), compute bytes for extensions (see remaining)\n" " - in nifti_read_extensions(), pass 'remain' as space for extensions,\n" " pass it to nifti_read_next_ext(), and update for each one read \n" " - in nifti_check_extension(), require (size <= remain)\n", " - in update_nifti_image_brick_list(), update nvox\n" " - in nifti_image_load_bricks(), make explicit check for nbricks <= 0\n" " - in int_force_positive(), check for (!list)\n" " - in swap_nifti_header(), swap sizeof_hdr, and reorder to struct order\n" " - change get_filesize functions to signed ( < 0 is no file or error )\n", " - in nifti_validfilename(), lose redundant (len < 0) check\n" " - make print_hex_vals() static\n" " - in disp_nifti_1_header, restrict string field widths\n" "\n", "0.9 23 Dec 2004 [rickr] - minor changes\n" " - broke ASCII header reading out of nifti_image_read(), into new\n" " functions has_ascii_header() and read_ascii_image()\n", " - check image_read failure and znzseek failure\n" " - altered some debug output\n" " - nifti_write_all_data() now returns an int\n" "\n", "0.10 29 Dec 2004 [rickr]\n" " - renamed nifti_valid_extension() to nifti_check_extension()\n" " - added functions nifti_makehdrname() and nifti_makeimgname()\n" " - added function valid_nifti_extensions()\n" " - in nifti_write_extensions(), check for validity before writing\n", " - rewrote nifti_image_write_hdr_img2():\n" " o set write_data and leave_open flags from write_opts\n" " o add debug print statements\n" " o use nifti_write_ascii_image() for the ascii case\n" " o rewrote the logic of all cases to be easier to follow\n", " - broke out code as nifti_write_ascii_image() function\n" " - added debug to top-level write functions, and free the znzFile\n" " - removed unused internal function nifti_image_open()\n" "\n", "0.11 30 Dec 2004 [rickr] - small mods\n" " - moved static function prototypes from header to C file\n" " - free extensions in nifti_image_free()\n" "\n", "1.0 07 Jan 2005 [rickr] - INITIAL RELEASE VERSION\n" " - added function nifti_set_filenames()\n" " - added function nifti_read_header()\n" " - added static function nhdr_looks_good()\n" " - added static function need_nhdr_swap()\n" " - exported nifti_add_exten_to_list symbol\n", " - fixed #bytes written in nifti_write_extensions()\n" " - only modify offset if it is too small (nifti_set_iname_offset)\n" " - added nifti_type 3 to nifti_makehdrname and nifti_makeimgname\n" " - added function nifti_set_filenames()\n" "\n", "1.1 07 Jan 2005 [rickr]\n" " - in nifti_read_header(), swap if needed\n" "\n", "1.2 07 Feb 2005 [kate fissell c/o rickr] \n" " - nifti1.h: added doxygen comments for main struct and #define groups\n" " - nifti1_io.h: added doxygen comments for file and nifti_image struct\n" " - nifti1_io.h: added doxygen comments for file and some functions\n" " - nifti1_io.c: changed nifti_copy_nim_info to use memcpy\n" "\n", "1.3 09 Feb 2005 [rickr]\n" " - nifti1.h: added doxygen comments for extension structs\n" " - nifti1_io.h: put most #defines in #ifdef _NIFTI1_IO_C_ block\n" " - added a doxygen-style description to every exported function\n" " - added doxygen-style comments within some functions\n" " - re-exported many znzFile functions that I had made static\n" " - re-added nifti_image_open (sorry, Mark)\n" " - every exported function now has 'nifti' in the name (19 functions)\n", " - made sure every alloc() has a failure test\n" " - added nifti_copy_extensions function, for use in nifti_copy_nim_info\n" " - nifti_is_gzfile: added initial strlen test\n" " - nifti_set_filenames: added set_byte_order parameter option\n" " (it seems appropriate to set the BO when new files are associated)\n" " - disp_nifti_1_header: prints to stdout (a.o.t. stderr), with fflush\n" "\n", "1.4 23 Feb 2005 [rickr] - sourceforge merge\n" " - merged into the nifti_io CVS directory structure at sourceforge.net\n" " - merged in 4 changes by Mark, and re-added his const keywords\n" " - cast some pointers to (void *) for -pedantic compile option\n" " - added nifti_free_extensions()\n" "\n", "1.5 02 Mar 2005 [rickr] - started nifti global options\n" " - gni_debug is now g_opts.debug\n" " - added validity check parameter to nifti_read_header\n" " - need_nhdr_swap no longer does test swaps on the stack\n" "\n", "1.6 05 April 2005 [rickr] - validation and collapsed_image_read\n" " - added nifti_read_collapsed_image(), an interface for reading partial\n" " datasets, specifying a subset of array indices\n" " - for read_collapsed_image, added static functions: rci_read_data(),\n" " rci_alloc_mem(), and make_pivot_list()\n", " - added nifti_nim_is_valid() to check for consistency (more to do)\n" " - added nifti_nim_has_valid_dims() to do many dimensions tests\n" "\n", "1.7 08 April 2005 [rickr]\n" " - added nifti_update_dims_from_array() - to update dimensions\n" " - modified nifti_makehdrname() and nifti_makeimgname():\n" " if prefix has a valid extension, use it (else make one up)\n" " - added nifti_get_intlist - for making an array of ints\n" " - fixed init of NBL->bsize in nifti_alloc_NBL_mem() {thanks, Bob}\n" "\n", "1.8 14 April 2005 [rickr]\n" " - added nifti_set_type_from_names(), for nifti_set_filenames()\n" " (only updates type if number of files does not match it)\n" " - added is_valid_nifti_type(), just to be sure\n" " - updated description of nifti_read_collapsed_image() for *data change\n" " (if *data is already set, assume memory exists for results)\n" " - modified rci_alloc_mem() to allocate only if *data is NULL\n" "\n", "1.9 19 April 2005 [rickr]\n" " - added extension codes NIFTI_ECODE_COMMENT and NIFTI_ECODE_XCEDE\n" " - added nifti_type codes NIFTI_MAX_ECODE and NIFTI_MAX_FTYPE\n" " - added nifti_add_extension() {exported}\n" " - added nifti_fill_extension() as a static function\n" " - added nifti_is_valid_ecode() {exported}\n", " - nifti_type values are now NIFTI_FTYPE_* file codes\n" " - in nifti_read_extensions(), decrement 'remain' by extender size, 4\n" " - in nifti_set_iname_offset(), case 1, update if offset differs\n" " - only output '-d writing nifti file' if debug > 1\n" "\n", "1.10 10 May 2005 [rickr]\n" " - files are read using ZLIB only if they end in '.gz'\n" "\n", "1.11 12 August 2005 [kate fissell]\n" " - Kate's 0.2 release packaging, for sourceforge\n" "\n", "1.12 17 August 2005 [rickr] - comment (doxygen) updates\n" " - updated comments for most functions (2 updates from Cinly Ooi)\n" " - added nifti_type_and_names_match()\n" "\n", "1.12a 24 August 2005 [rickr] - remove all tabs from Clibs/*/*.[ch]\n", "1.12b 25 August 2005 [rickr] - changes by Hans Johnson\n", "1.13 25 August 2005 [rickr]\n", " - finished changes by Hans for Insight\n" " - added const in all appropraite parameter locations (30-40)\n" " (any pointer referencing data that will not change)\n" " - shortened all string constants below 509 character limit\n" "1.14 28 October 2005 [HJohnson]\n", " - use nifti_set_filenames() in nifti_convert_nhdr2nim()\n" "1.15 02 November 2005 [rickr]\n", " - added skip_blank_ext to nifti_global_options\n" " - added nifti_set_skip_blank_ext(), to set option\n" " - if skip_blank_ext and no extensions, do not read/write extender\n" "1.16 18 November 2005 [rickr]\n", " - removed any test or access of dim[i], i>dim[0]\n" " - do not set pixdim for collapsed dims to 1.0, leave them as they are\n" " - added magic and dim[i] tests in nifti_hdr_looks_good()\n" " - added 2 size_t casts\n" "1.17 22 November 2005 [rickr]\n", " - in hdr->nim, for i > dim[0], pass 0 or 1, else set to 1\n" "1.18 02 March 2006 [rickr]\n", " - in nifti_alloc_NBL_mem(), fixed nt=0 case from 1.17 change\n" "1.19 23 May 2006 [HJohnson,rickr]\n", " - nifti_write_ascii_image(): free(hstr)\n" " - nifti_copy_extensions(): clear num_ext and ext_list\n" "1.20 27 Jun 2006 [rickr]\n", " - nifti_findhdrname(): fixed assign of efirst to match stated logic\n" " (problem found by Atle Bjørnerud)\n" "1.21 05 Sep 2006 [rickr] update for nifticlib-0.4 release\n", " - was reminded to actually add nifti_set_skip_blank_ext()\n" " - init g_opts.skip_blank_ext to 0\n" "1.22 01 Jun 2007 nifticlib-0.5 release\n", "1.23 05 Jun 2007 nifti_add_exten_to_list: revert on failure, free old list\n" "1.24 07 Jun 2007 nifti_copy_extensions: use esize-8 for data size\n" "1.25 12 Jun 2007 [rickr] EMPTY_IMAGE creation\n", " - added nifti_make_new_header() - to create from dims/dtype\n" " - added nifti_make_new_nim() - to create from dims/dtype/fill\n" " - added nifti_is_valid_datatype(), and more debug info\n", "1.26 27 Jul 2007 [rickr] handle single volumes > 2^31 bytes (but < 2^32)\n", "1.27 28 Jul 2007 [rickr] nim->nvox, NBL-bsize are now type size_t\n" "1.28 30 Jul 2007 [rickr] size_t updates\n", "1.29 08 Aug 2007 [rickr] for list, valid_nifti_brick_list requires 3 dims\n" "1.30 08 Nov 2007 [Yaroslav/rickr]\n" " - fix ARM struct alignment problem in byte-swapping routines\n", "1.31 29 Nov 2007 [rickr] for nifticlib-1.0.0\n" " - added nifti_datatype_to/from_string routines\n" " - added DT_RGBA32/NIFTI_TYPE_RGBA32 datatype macros (2304)\n" " - added NIFTI_ECODE_FREESURFER (14)\n", "1.32 08 Dec 2007 [rickr]\n" " - nifti_hdr_looks_good() allows ANALYZE headers (req. by V. Luccio)\n" " - added nifti_datatype_is_valid()\n", "1.33 05 Feb 2008 [hansj,rickr] - block nia.gz use\n" "1.34 13 Jun 2008 [rickr] - added nifti_compiled_with_zlib()\n" "1.35 03 Aug 2008 [rickr]\n", " - deal with swapping, so that CPU type does not affect output\n" " (motivated by C Burns)\n" " - added nifti_analyze75 structure and nifti_swap_as_analyze()\n" " - previous swap_nifti_header is saved as old_swap_nifti_header\n" " - also swap UNUSED fields in nifti_1_header struct\n", "1.36 07 Oct 2008 [rickr]\n", " - added nifti_NBL_matches_nim() check for write_bricks()\n" "1.37 10 Mar 2009 [rickr]\n", " - H Johnson cast updates (06 Feb)\n" " - added NIFTI_ECODE_PYPICKLE for PyNIfTI (06 Feb)\n" " - added NIFTI_ECODEs 18-28 for the LONI MiND group\n" "1.38 28 Apr 2009 [rickr]\n", " - uppercase extensions are now valid (requested by M. Coursolle)\n" " - nifti_set_allow_upper_fext controls this option (req by C. Ooi)\n" "1.39 23 Jun 2009 [rickr]: added 4 checks of alloc() returns\n", "1.40 16 Mar 2010 [rickr]: added NIFTI_ECODE_VOXBO for D. Kimberg\n", "1.41 28 Apr 2010 [rickr]: added NIFTI_ECODE_CARET for J. Harwell\n", "1.42 06 Jul 2010 [rickr]: trouble with large (gz) files\n", " - noted/investigated by M Hanke and Y Halchenko\n" " - fixed znzread/write, noting example by M Adler\n" " - changed nifti_swap_* routines/calls to take size_t (6)\n" "1.43 07 Jul 2010 [rickr]: fixed znzR/W to again return nmembers\n", "1.44 19 Jul 2013 [rickr]: ITK compatibility updates from H Johnson\n", "1.45 10 May 2019 [rickr]: added NIFTI_ECODE_QUANTIPHYSE\n", "1.46 26 Sep 2019 [rickr]:\n" " - nifti_read_ascii_image no longer closes fp or free's fname\n" "----------------------------------------------------------------------\n" }; /* rcr - todo - nifti_tool -copy_sform SFORM_DSET.nii -infile ORIG.nii -prefix PP -copy_orient SFORM_DSET.nii -infile ORIG.nii -prefix PP - check converting nim 2 n2hdr - update for n2 (and/or split from n1) - is_nifti_file (maybe use nifti_header_version), nifti_hdr_looks_good - extensions - nifti_make_new_n1_header: check that dims are small enough (<2^15) - nifti_convert_nim2nhdr: rename to nim2n1hdr and write nim2n2hdr (maybe have nifti_convert_nim2nhdr wrap current version) - nifti_set_iname_offset: n2 update via nifti_type - track use of nifti_type - nifti_image_write_hdr_img2: write nifti_2_header */ static char const * const gni2_history[] = { "----------------------------------------------------------------------\n" "history (of nifti-2 library changes):\n" "\n", "2.00 02 Jan, 2014 [rickr]\n" " Richard Reynolds of the National Institutes of Health, SSCC/DIRP/NIMH\n" " - initial version - change types to 64-bit based on new nifti_image\n", "2.01 04 Apr, 2014 [rickr]\n" " - added functionality for both nifti-1 and -2 headers\n" " (read/display/swap/convert2nim/make_new_n?_hdr)\n" " - still needs much nifti-2 functionality\n", "2.02 11 May, 2015 [rickr]\n" " - added to repository 28 Apr, 2015\n" " - nifti_read_header() now returns found header struct\n" "2.03 23 Jul, 2015 [rickr]\n" " - possibly alter dimensions on CIFTI read\n" " - return N-1 headers in unknown version cases\n", "2.04 05 Aug, 2015 [rickr]\n" " - have writing try NIFTI-2 if NIFTI-1 seems insufficient\n" "2.05 15 Apr, 2016 [rickr]\n" " - print int64_t using PRId64 macro, (ugly, but no warnings)\n" "2.06 01 Oct, 2018 [rickr]\n" " - errors should all mention NIFTI, slight additional clarity\n" "2.07 18 Dec, 2018 [hmjohnson]\n", " - added some const qualifiers\n" " - removed register keywords\n" " - fixed potential memory leaks in error conditions\n" " - appeased compilers\n" " - duped nifti1.h under nifti2, so directories do not cross reference\n" "2.08 02 Jan, 2019 [rickr]\n" " - fixed CIFTI extension reading if not first\n" " - re-allow reading of ASCII headers (not part of standard)\n" " - nifti_set_iname_offset() now takes nifti_ver, to adjust for size\n", "2.09 10 May, 2019 [rickr]: added NIFTI_ECODE_QUANTIPHYSE\n" "2.10 26 Sep, 2019 [rickr]: nifti_read_ascii_image no longer closes fp\n", "2.11 3 Oct, 2019 [rickr]: added nifti_[d]mat33_mul\n", "2.1.0 18 Jun, 2020 [leej3,hmjohnson,rickr]:\n" " - changed to more formal library versioning\n", "----------------------------------------------------------------------\n" }; static const char gni_version[] = NIFTI2_IO_SOURCE_VERSION " (18 Jun, 2020)"; /*! global nifti options structure - init with defaults */ /* see 'option accessor functions' */ static nifti_global_options g_opts = { 1, /* debug level */ 0, /* skip_blank_ext - skip extender if no extensions */ 1, /* allow_upper_fext - allow uppercase file extensions */ 0, /* alter_cifti - alter CIFTI dims to use nx,t,u,v*/ }; char nifti1_magic[4] = { 'n', '+', '1', '\0' }; char nifti2_magic[8] = { 'n', '+', '2', '\0', '\r', '\n', '\032', '\n' }; /*! global nifti types structure list (per type, ordered oldest to newest) */ static const nifti_type_ele nifti_type_list[] = { /* type nbyper swapsize name */ { 0, 0, 0, "DT_UNKNOWN" }, { 0, 0, 0, "DT_NONE" }, { 1, 0, 0, "DT_BINARY" }, /* not usable */ { 2, 1, 0, "DT_UNSIGNED_CHAR" }, { 2, 1, 0, "DT_UINT8" }, { 2, 1, 0, "NIFTI_TYPE_UINT8" }, { 4, 2, 2, "DT_SIGNED_SHORT" }, { 4, 2, 2, "DT_INT16" }, { 4, 2, 2, "NIFTI_TYPE_INT16" }, { 8, 4, 4, "DT_SIGNED_INT" }, { 8, 4, 4, "DT_INT32" }, { 8, 4, 4, "NIFTI_TYPE_INT32" }, { 16, 4, 4, "DT_FLOAT" }, { 16, 4, 4, "DT_FLOAT32" }, { 16, 4, 4, "NIFTI_TYPE_FLOAT32" }, { 32, 8, 4, "DT_COMPLEX" }, { 32, 8, 4, "DT_COMPLEX64" }, { 32, 8, 4, "NIFTI_TYPE_COMPLEX64" }, { 64, 8, 8, "DT_DOUBLE" }, { 64, 8, 8, "DT_FLOAT64" }, { 64, 8, 8, "NIFTI_TYPE_FLOAT64" }, { 128, 3, 0, "DT_RGB" }, { 128, 3, 0, "DT_RGB24" }, { 128, 3, 0, "NIFTI_TYPE_RGB24" }, { 255, 0, 0, "DT_ALL" }, { 256, 1, 0, "DT_INT8" }, { 256, 1, 0, "NIFTI_TYPE_INT8" }, { 512, 2, 2, "DT_UINT16" }, { 512, 2, 2, "NIFTI_TYPE_UINT16" }, { 768, 4, 4, "DT_UINT32" }, { 768, 4, 4, "NIFTI_TYPE_UINT32" }, { 1024, 8, 8, "DT_INT64" }, { 1024, 8, 8, "NIFTI_TYPE_INT64" }, { 1280, 8, 8, "DT_UINT64" }, { 1280, 8, 8, "NIFTI_TYPE_UINT64" }, { 1536, 16, 16, "DT_FLOAT128" }, { 1536, 16, 16, "NIFTI_TYPE_FLOAT128" }, { 1792, 16, 8, "DT_COMPLEX128" }, { 1792, 16, 8, "NIFTI_TYPE_COMPLEX128" }, { 2048, 32, 16, "DT_COMPLEX256" }, { 2048, 32, 16, "NIFTI_TYPE_COMPLEX256" }, { 2304, 4, 0, "DT_RGBA32" }, { 2304, 4, 0, "NIFTI_TYPE_RGBA32" }, }; /*---------------------------------------------------------------------------*/ /* prototypes for internal functions - not part of exported library */ /* extension routines */ static int nifti_read_extensions(nifti_image *nim, znzFile fp, int64_t remain); static int nifti_read_next_extension( nifti1_extension * nex, nifti_image *nim, int remain, znzFile fp ); static int nifti_check_extension(nifti_image *nim, int size,int code, int rem); static void update_nifti_image_for_brick_list(nifti_image * nim, int64_t nbricks); static int nifti_add_exten_to_list(nifti1_extension * new_ext, nifti1_extension ** list, int new_length); static int nifti_fill_extension(nifti1_extension * ext, const char * data, int len, int ecode); static void compute_strides(int64_t *strides,const int64_t *size,int nbyper); /* NBL routines */ static int nifti_load_NBL_bricks(nifti_image * nim , const int64_t * slist, const int64_t * sindex, nifti_brick_list * NBL, znzFile fp ); static int nifti_alloc_NBL_mem( nifti_image * nim, int64_t nbricks, nifti_brick_list * nbl); static int nifti_copynsort(int64_t nbricks, const int64_t *blist, int64_t **slist, int64_t **sindex); static int nifti_NBL_matches_nim(const nifti_image *nim, const nifti_brick_list *NBL); /* for nifti_read_collapsed_image: */ static int rci_read_data(nifti_image *nim, int *pivots, int64_t *prods, int nprods, const int64_t dims[], char *data, znzFile fp, int64_t base_offset); static int rci_alloc_mem(void **data, const int64_t prods[8], int nprods, int nbyper); static int make_pivot_list(nifti_image * nim, const int64_t dims[], int pivots[], int64_t prods[], int * nprods ); /* misc */ static int compare_strlist (const char * str, char ** strlist, int len); static int fileext_compare (const char * test_ext, const char * known_ext); static int fileext_n_compare (const char * test_ext, const char * known_ext, size_t maxlen); static int is_mixedcase (const char * str); static int is_uppercase (const char * str); static int make_lowercase (char * str); static int make_uppercase (char * str); static int need_nhdr_swap (short dim0, int hdrsize); static int print_hex_vals (const char * data, size_t nbytes, FILE * fp); static int unescape_string (char *str); /* string utility functions */ static char *escapize_string (const char *str); /* consider for export */ static int nifti_ext_type_index(nifti_image * nim, int ecode); /* internal I/O routines */ static znzFile nifti_image_load_prep( nifti_image *nim ); static int has_ascii_header(znzFile fp); /*---------------------------------------------------------------------------*/ /* for calling from some main program */ /*----------------------------------------------------------------------*/ /*! display the nifti library module history (via stdout) *//*--------------------------------------------------------------------*/ void nifti_disp_lib_hist( int ver ) { int c, len; switch ( ver ) { default: { fprintf(stderr,"** NIFTI disp_lib_list: bad ver %d\n", ver); break; } case 0: case 2: { len = sizeof(gni2_history)/sizeof(char *); for( c = 0; c < len; c++ ) fputs(gni2_history[c], stdout); break; } case 1: { len = sizeof(gni1_history)/sizeof(char *); for( c = 0; c < len; c++ ) fputs(gni1_history[c], stdout); break; } } } /*----------------------------------------------------------------------*/ /*! display the nifti library version (via stdout) *//*--------------------------------------------------------------------*/ void nifti_disp_lib_version( void ) { printf("%s, compiled %s\n", gni_version, __DATE__); } /*----------------------------------------------------------------------*/ /*! nifti_image_read_bricks - read nifti data as array of bricks * * 13 Dec 2004 [rickr] * * \param hname - filename of dataset to read (must be valid) * \param nbricks - number of sub-bricks to read * (if blist is valid, nbricks must be > 0) * \param blist - list of sub-bricks to read * (can be NULL; if NULL, read complete dataset) * \param NBL - pointer to empty nifti_brick_list struct * (must be a valid pointer) * * \return *
nim - same as nifti_image_read, but * nim->nt = NBL->nbricks (or nt*nu*nv*nw) * nim->nu,nv,nw = 1 * nim->data = NULL *
NBL - filled with data volumes * * By default, this function will read the nifti dataset and break the data * into a list of nt*nu*nv*nw sub-bricks, each having size nx*ny*nz elements. * That is to say, instead of reading the entire dataset as a single array, * break it up into sub-bricks (volumes), each of size nx*ny*nz elements. * * Note: in the returned nifti_image, nu, nv and nw will always be 1. The * intention of this function is to collapse the dataset into a single * array of volumes (of length nbricks or nt*nu*nv*nw). * * If 'blist' is valid, it is taken to be a list of sub-bricks, of length * 'nbricks'. The data will still be separated into sub-bricks of size * nx*ny*nz elements, but now 'nbricks' sub-bricks will be returned, of the * caller's choosing via 'blist'. * * E.g. consider a dataset with 12 sub-bricks (numbered 0..11), and the * following code: * *
 * { nifti_brick_list   NB_orig, NB_select;
 *   nifti_image      * nim_orig, * nim_select;
 *   int                blist[5] = { 7, 0, 5, 5, 9 };
 *
 *   nim_orig   = nifti_image_read_bricks("myfile.nii", 0, NULL,  &NB_orig);
 *   nim_select = nifti_image_read_bricks("myfile.nii", 5, blist, &NB_select);
 * }
 * 
* * Here, nim_orig gets the entire dataset, where NB_orig.nbricks = 12. But * nim_select has NB_select.nbricks = 5. * * Note that the first case is not quite the same as just calling the * nifti_image_read function, as here the data is separated into sub-bricks. * * Note that valid blist elements are in [0..nt*nu*nv*nw-1], * or written [ 0 .. (dim[4]*dim[5]*dim[6]*dim[7] - 1) ]. * * Note that, as is the case with all of the reading functions, the * data will be allocated, read in, and properly byte-swapped, if * necessary. * * \sa nifti_image_load_bricks, nifti_free_NBL, valid_nifti_brick_list, nifti_image_read *//*----------------------------------------------------------------------*/ nifti_image *nifti_image_read_bricks(const char * hname, int64_t nbricks, const int64_t * blist, nifti_brick_list * NBL) { nifti_image * nim; if( !hname || !NBL ){ fprintf(stderr,"** nifti_image_read_bricks: bad params (%p,%p)\n", hname, (void *)NBL); return NULL; } if( blist && nbricks <= 0 ){ /* use PRId64 for printing int64_t 14 Apr 2016 */ fprintf(stderr,"** nifti_image_read_bricks: bad nbricks, %" PRId64 "\n", nbricks); return NULL; } nim = nifti_image_read(hname, 0); /* read header, but not data */ if( !nim ) return NULL; /* errors were already printed */ /* if we fail, free image and return */ if( nifti_image_load_bricks(nim, nbricks, blist, NBL) <= 0 ){ nifti_image_free(nim); return NULL; } if( blist ) update_nifti_image_for_brick_list(nim, nbricks); return nim; } /*---------------------------------------------------------------------- * update_nifti_image_for_brick_list - update nifti_image * * When loading a specific brick list, the distinction between * nt, nu, nv and nw is lost. So put everything in t, and set * dim[0] = 4. *----------------------------------------------------------------------*/ static void update_nifti_image_for_brick_list( nifti_image * nim , int64_t nbricks ) { int64_t ndim; if( g_opts.debug > 2 ){ fprintf(stderr,"+d updating image dimensions for %" PRId64 " bricks in list\n", nbricks); fprintf(stderr," ndim = %" PRId64 "\n",nim->ndim); fprintf(stderr," nx,ny,nz,nt,nu,nv,nw: (%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ")\n", nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->nv, nim->nw); } nim->nt = nbricks; nim->nu = nim->nv = nim->nw = 1; nim->dim[4] = nbricks; nim->dim[5] = nim->dim[6] = nim->dim[7] = 1; /* compute nvox */ /* do not rely on dimensions above dim[0] 16 Nov 2005 [rickr] */ for( nim->nvox = 1, ndim = 1; ndim <= nim->dim[0]; ndim++ ) nim->nvox *= nim->dim[ndim]; /* update the dimensions to 4 or lower */ for( ndim = 4; (ndim > 1) && (nim->dim[ndim] <= 1); ndim-- ) ; if( g_opts.debug > 2 ){ fprintf(stderr,"+d ndim = %" PRId64 " -> %" PRId64 "\n",nim->ndim, ndim); fprintf(stderr," --> (%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ")\n", nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->nv, nim->nw); } nim->dim[0] = nim->ndim = ndim; } /*----------------------------------------------------------------------*/ /*! nifti_update_dims_from_array - update nx, ny, ... from nim->dim[] Fix all the dimension information, based on a new nim->dim[]. Note: we assume that dim[0] will not increase. Check for updates to pixdim[], dx,..., nx,..., nvox, ndim, dim[0]. *//*--------------------------------------------------------------------*/ int nifti_update_dims_from_array( nifti_image * nim ) { int c; int64_t ndim; if( !nim ){ fprintf(stderr,"** NIFTI update_dims: missing nim\n"); return 1; } if( g_opts.debug > 2 ){ fprintf(stderr,"+d updating image dimensions given nim->dim:"); for( c = 0; c < 8; c++ ) fprintf(stderr," %" PRId64, nim->dim[c]); fputc('\n',stderr); } /* verify dim[0] first */ if(nim->dim[0] < 1 || nim->dim[0] > 7){ fprintf(stderr,"** NIFTI: invalid dim[0], dim[] = "); for( c = 0; c < 8; c++ ) fprintf(stderr," %" PRId64, nim->dim[c]); fputc('\n',stderr); return 1; } /* set nx, ny ..., dx, dy, ..., one by one */ /* less than 1, set to 1, else copy */ if(nim->dim[1] < 1) nim->nx = nim->dim[1] = 1; else nim->nx = nim->dim[1]; nim->dx = nim->pixdim[1]; /* if undefined, or less than 1, set to 1 */ if(nim->dim[0] < 2 || (nim->dim[0] >= 2 && nim->dim[2] < 1)) nim->ny = nim->dim[2] = 1; else nim->ny = nim->dim[2]; /* copy delta values, in any case */ nim->dy = nim->pixdim[2]; if(nim->dim[0] < 3 || (nim->dim[0] >= 3 && nim->dim[3] < 1)) nim->nz = nim->dim[3] = 1; else /* just copy vals from arrays */ nim->nz = nim->dim[3]; nim->dz = nim->pixdim[3]; if(nim->dim[0] < 4 || (nim->dim[0] >= 4 && nim->dim[4] < 1)) nim->nt = nim->dim[4] = 1; else /* just copy vals from arrays */ nim->nt = nim->dim[4]; nim->dt = nim->pixdim[4]; if(nim->dim[0] < 5 || (nim->dim[0] >= 5 && nim->dim[5] < 1)) nim->nu = nim->dim[5] = 1; else /* just copy vals from arrays */ nim->nu = nim->dim[5]; nim->du = nim->pixdim[5]; if(nim->dim[0] < 6 || (nim->dim[0] >= 6 && nim->dim[6] < 1)) nim->nv = nim->dim[6] = 1; else /* just copy vals from arrays */ nim->nv = nim->dim[6]; nim->dv = nim->pixdim[6]; if(nim->dim[0] < 7 || (nim->dim[0] >= 7 && nim->dim[7] < 1)) nim->nw = nim->dim[7] = 1; else /* just copy vals from arrays */ nim->nw = nim->dim[7]; nim->dw = nim->pixdim[7]; for( c = 1, nim->nvox = 1; c <= nim->dim[0]; c++ ) nim->nvox *= nim->dim[c]; /* compute ndim, assuming it can be no larger than the old one */ for( ndim = nim->dim[0]; (ndim > 1) && (nim->dim[ndim] <= 1); ndim-- ) ; if( g_opts.debug > 2 ){ fprintf(stderr,"+d ndim = %" PRId64 " -> %" PRId64 "\n",nim->ndim, ndim); fprintf(stderr," --> (%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ")\n", nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->nv, nim->nw); } nim->dim[0] = nim->ndim = ndim; return 0; } /*----------------------------------------------------------------------*/ /*! Load the image data from disk into an already-prepared image struct. * * \param nim - initialized nifti_image, without data * \param nbricks - the length of blist (must be 0 if blist is NULL) * \param blist - an array of xyz volume indices to read (can be NULL) * \param NBL - pointer to struct where resulting data will be stored * * If blist is NULL, read all sub-bricks. * * \return the number of loaded bricks (NBL->nbricks), * 0 on failure, < 0 on error * * NOTE: it is likely that another function will copy the data pointers * out of NBL, in which case the only pointer the calling function * will want to free is NBL->bricks (not each NBL->bricks[i]). *//*--------------------------------------------------------------------*/ int nifti_image_load_bricks( nifti_image * nim , int64_t nbricks, const int64_t * blist, nifti_brick_list * NBL ) { int64_t * slist = NULL, * sindex = NULL; int rv; znzFile fp; /* we can have blist == NULL */ if( !nim || !NBL ){ fprintf(stderr,"** nifti_image_load_bricks, bad params (%p,%p)\n", (void *)nim, (void *)NBL); return -1; } if( blist && nbricks <= 0 ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d load_bricks: received blist with nbricks = " "%" PRId64 "," "ignoring blist\n", nbricks); blist = NULL; /* pretend nothing was passed */ } if( blist && ! valid_nifti_brick_list(nim, nbricks, blist, g_opts.debug>0) ) return -1; /* for efficiency, let's read the file in order */ if( blist && nifti_copynsort( nbricks, blist, &slist, &sindex ) != 0 ) return -1; /* open the file and position the FILE pointer */ fp = nifti_image_load_prep( nim ); if( !fp ){ if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_image_load_bricks, failed load_prep\n"); if( blist ){ free(slist); free(sindex); } return -1; } /* this will flag to allocate defaults */ if( !blist ) nbricks = 0; if( nifti_alloc_NBL_mem( nim, nbricks, NBL ) != 0 ){ if( blist ){ free(slist); free(sindex); } znzclose(fp); return -1; } rv = nifti_load_NBL_bricks(nim, slist, sindex, NBL, fp); if( rv != 0 ){ nifti_free_NBL( NBL ); /* failure! */ NBL->nbricks = 0; /* repetative, but clear */ } if( slist ){ free(slist); free(sindex); } znzclose(fp); return NBL->nbricks; } /*----------------------------------------------------------------------*/ /*! nifti_free_NBL - free all pointers and clear structure * * note: this does not presume to free the structure pointer *//*--------------------------------------------------------------------*/ void nifti_free_NBL( nifti_brick_list * NBL ) { int c; if( NBL->bricks ){ for( c = 0; c < NBL->nbricks; c++ ) if( NBL->bricks[c] ) free(NBL->bricks[c]); free(NBL->bricks); NBL->bricks = NULL; } NBL->bsize = NBL->nbricks = 0; } /*---------------------------------------------------------------------- * nifti_load_NBL_bricks - read the file data into the NBL struct * * return 0 on success, -1 on failure *----------------------------------------------------------------------*/ static int nifti_load_NBL_bricks( nifti_image * nim , const int64_t * slist, const int64_t * sindex, nifti_brick_list * NBL, znzFile fp ) { int64_t oposn, fposn; /* orig and current file positions */ int64_t rv, test; int64_t c; int64_t prev, isrc, idest; /* previous/current sub-brick, and new index */ test = znztell(fp); /* store current file position */ if( test < 0 ){ fprintf(stderr,"** NIFTI load bricks: ztell failed??\n"); return -1; } fposn = oposn = test; /* first, handle the default case, no passed blist */ if( !slist ){ for( c = 0; c < NBL->nbricks; c++ ) { rv = nifti_read_buffer(fp, NBL->bricks[c], NBL->bsize, nim); if( rv != NBL->bsize ){ fprintf(stderr,"** NIFTI load bricks: cannot read brick %" PRId64 " from '%s'\n", c, nim->iname ? nim->iname : nim->fname); return -1; } } if( g_opts.debug > 1 ) fprintf(stderr,"+d read %" PRId64 " default %" PRId64 "-byte bricks from file %s\n", NBL->nbricks, NBL->bsize, nim->iname ? nim->iname:nim->fname ); return 0; } if( !sindex ){ fprintf(stderr,"** NIFTI load_NBL_bricks: missing index list\n"); return -1; } prev = -1; /* use prev for previous sub-brick */ for( c = 0; c < NBL->nbricks; c++ ){ isrc = slist[c]; /* this is original brick index (c is new one) */ idest = sindex[c]; /* this is the destination index for this data */ /* if this sub-brick is not the previous, we must read from disk */ if( isrc != prev ){ /* if we are not looking at the correct sub-brick, scan forward */ if( fposn != (oposn + isrc*NBL->bsize) ){ fposn = oposn + isrc*NBL->bsize; /* rcr - znz functions need to handle 64-bit cases, */ /* see setting _FILE_OFFSET_BITS */ if( znzseek(fp, fposn, SEEK_SET) < 0 ){ fprintf(stderr,"** NIFTI: failed to locate brick %" PRId64 " in file '%s'\n", isrc, nim->iname ? nim->iname : nim->fname); return -1; } } /* only 10,000 lines later and we're actually reading something! */ rv = nifti_read_buffer(fp, NBL->bricks[idest], NBL->bsize, nim); if( rv != NBL->bsize ){ fprintf(stderr,"** NIFTI: failed to read brick %" PRId64 " from file '%s'\n", isrc, nim->iname ? nim->iname : nim->fname); if( g_opts.debug > 1 ) fprintf(stderr," (read %" PRId64 " of %" PRId64 " bytes)\n", rv, NBL->bsize); return -1; } fposn += NBL->bsize; } else { /* we have already read this sub-brick, just copy the previous one */ /* note that this works because they are sorted */ memcpy(NBL->bricks[idest], NBL->bricks[sindex[c-1]], NBL->bsize); } prev = isrc; /* in any case, note the now previous sub-brick */ } return 0; } /*---------------------------------------------------------------------- * nifti_alloc_NBL_mem - allocate memory for bricks * * return 0 on success, -1 on failure *----------------------------------------------------------------------*/ static int nifti_alloc_NBL_mem(nifti_image * nim, int64_t nbricks, nifti_brick_list * nbl) { int64_t c; /* if nbricks is not specified, use the default */ if( nbricks > 0 ) nbl->nbricks = nbricks; else { /* I missed this one with the 1.17 change 02 Mar 2006 [rickr] */ nbl->nbricks = 1; for( c = 4; c <= nim->ndim; c++ ) nbl->nbricks *= nim->dim[c]; } nbl->bsize = nim->nx * nim->ny * nim->nz * nim->nbyper; /* bytes */ nbl->bricks = (void **)malloc(nbl->nbricks * sizeof(void *)); if( ! nbl->bricks ){ fprintf(stderr,"** NIFTI NANM: failed to alloc %" PRId64 " void ptrs\n",nbricks); return -1; } for( c = 0; c < nbl->nbricks; c++ ){ nbl->bricks[c] = malloc(nbl->bsize); if( ! nbl->bricks[c] ){ fprintf(stderr,"** NIFTI NANM: failed to alloc %" PRId64 " bytes for brick %" PRId64 "\n", nbl->bsize, c); /* so free and clear everything before returning */ while( c > 0 ){ c--; free(nbl->bricks[c]); } free(nbl->bricks); nbl->bricks = NULL; nbl->bsize = nbl->nbricks = 0; return -1; } } if( g_opts.debug > 2 ) fprintf(stderr,"+d NANM: alloc'd %" PRId64 " bricks of %" PRId64 " bytes for NBL\n", nbl->nbricks, nbl->bsize); return 0; } /*---------------------------------------------------------------------- * nifti_copynsort - copy int list, and sort with indices * * 1. duplicate the incoming list * 2. create an sindex list, and init with 0..nbricks-1 * 3. do a slow insertion sort on the small slist, along with sindex list * 4. check results, just to be positive * * So slist is sorted, and sindex hold original positions. * * return 0 on success, -1 on failure *----------------------------------------------------------------------*/ static int nifti_copynsort(int64_t nbricks, const int64_t *blist, int64_t ** slist, int64_t ** sindex) { int64_t * stmp, * itmp; /* for ease of typing/reading */ int64_t c1, c2, spos, tmp; *slist = (int64_t *)malloc(nbricks * sizeof(int64_t)); *sindex = (int64_t *)malloc(nbricks * sizeof(int64_t)); if( !*slist || !*sindex ){ fprintf(stderr,"** NIFTI NCS: failed to alloc %" PRId64 " ints for sorting\n", nbricks); if(*slist) free(*slist); /* maybe one succeeded */ if(*sindex) free(*sindex); return -1; } /* init the lists */ for( c1 = 0; c1 < nbricks; c1++ ) { (*slist)[c1] = blist[c1]; (*sindex)[c1] = c1; } /* now actually sort slist */ stmp = *slist; itmp = *sindex; for( c1 = 0; c1 < nbricks-1; c1++ ) { /* find smallest value, init to current */ spos = c1; for( c2 = c1+1; c2 < nbricks; c2++ ) if( stmp[c2] < stmp[spos] ) spos = c2; if( spos != c1 ) /* swap: fine, don't maintain sub-order, see if I care */ { tmp = stmp[c1]; /* first swap the sorting values */ stmp[c1] = stmp[spos]; stmp[spos] = tmp; tmp = itmp[c1]; /* then swap the index values */ itmp[c1] = itmp[spos]; itmp[spos] = tmp; } } if( g_opts.debug > 2 ){ fprintf(stderr, "+d sorted indexing list:\n"); fprintf(stderr, " orig : "); for( c1 = 0; c1 < nbricks; c1++ ) fprintf(stderr," %" PRId64, blist[c1]); fprintf(stderr,"\n new : "); for( c1 = 0; c1 < nbricks; c1++ ) fprintf(stderr," %" PRId64, stmp[c1]); fprintf(stderr,"\n indices: "); for( c1 = 0; c1 < nbricks; c1++ ) fprintf(stderr," %" PRId64, itmp[c1]); fputc('\n', stderr); } /* check the sort (why not? I've got time...) */ for( c1 = 0; c1 < nbricks-1; c1++ ){ if( (stmp[c1] > stmp[c1+1]) || (blist[itmp[c1]] != stmp[c1]) ){ fprintf(stderr,"** NIFTI sorting screw-up, way to go, rick!\n"); free(stmp); free(itmp); *slist = NULL; *sindex = NULL; return -1; } } if( g_opts.debug > 2 ) fprintf(stderr,"-d sorting is okay\n"); return 0; } /*----------------------------------------------------------------------*/ /*! valid_nifti_brick_list - check sub-brick list for image * * This function verifies that nbricks and blist are appropriate * for use with this nim, based on the dimensions. * * \param nim nifti_image to check against * \param nbricks number of brick indices in blist * \param blist list of brick indices to check in nim * \param disp_error if this flag is set, report errors to user * * \return 1 if valid, 0 if not *//*--------------------------------------------------------------------*/ int valid_nifti_brick_list(nifti_image * nim , int64_t nbricks, const int64_t * blist, int disp_error) { int64_t c, nsubs; if( !nim ){ if( disp_error || g_opts.debug > 0 ) fprintf(stderr,"** valid_nifti_brick_list: missing nifti image\n"); return 0; } if( nbricks <= 0 || !blist ){ if( disp_error || g_opts.debug > 1 ) fprintf(stderr,"** valid_nifti_brick_list: no brick list to check\n"); return 0; } if( nim->dim[0] < 3 ){ if( disp_error || g_opts.debug > 1 ) fprintf(stderr,"** NIFTI: cannot read explict brick list from %" PRId64 "-D dataset\n", nim->dim[0]); return 0; } /* nsubs sub-brick is nt*nu*nv*nw */ for( c = 4, nsubs = 1; c <= nim->dim[0]; c++ ) nsubs *= nim->dim[c]; if( nsubs <= 0 ){ fprintf(stderr,"** NIFTI VNBL warning: bad dim list (%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ")\n", nim->dim[4], nim->dim[5], nim->dim[6], nim->dim[7]); return 0; } for( c = 0; c < nbricks; c++ ) if( (blist[c] < 0) || (blist[c] >= nsubs) ){ if( disp_error || g_opts.debug > 1 ) fprintf(stderr, "** NIFTI volume index %" PRId64 " (#%" PRId64 ")" " is out of range [0,%" PRId64 "]\n", blist[c], c, nsubs-1); return 0; } return 1; /* all is well */ } /*----------------------------------------------------------------------*/ /* verify that NBL struct is a valid data source for the image * * return 1 if so, 0 otherwise *//*--------------------------------------------------------------------*/ static int nifti_NBL_matches_nim(const nifti_image *nim, const nifti_brick_list *NBL) { int64_t volbytes = 0; /* bytes per volume */ int64_t nvols = 0; int ind, errs = 0; if( !nim || !NBL ) { if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_NBL_matches_nim: NULL pointer(s)\n"); return 0; } /* for nim, compute volbytes and nvols */ if( nim->ndim > 0 ) { /* first 3 indices are over a single volume */ volbytes = (int64_t)nim->nbyper; for( ind = 1; ind <= nim->ndim && ind < 4; ind++ ) volbytes *= nim->dim[ind]; for( ind = 4, nvols = 1; ind <= nim->ndim; ind++ ) nvols *= nim->dim[ind]; } if( volbytes != NBL->bsize ) { if( g_opts.debug > 1 ) fprintf(stderr,"** NIFTI NBL/nim mismatch, volbytes = %" PRId64 ", %" PRId64 "\n", NBL->bsize, volbytes); errs++; } if( nvols != NBL->nbricks ) { if( g_opts.debug > 1 ) fprintf(stderr,"** NIFTI NBL/nim mismatch, nvols = %" PRId64 ", %" PRId64 "\n", NBL->nbricks, nvols); errs++; } if( errs ) return 0; else if ( g_opts.debug > 2 ) fprintf(stderr,"-- nim/NBL agree: nvols = %" PRId64 ", nbytes = %" PRId64 "\n", nvols, volbytes); return 1; } /* end of new nifti_image_read_bricks() functionality */ /*----------------------------------------------------------------------*/ /*! display the orientation from the quaternian fields * * \param mesg if non-NULL, display this message first * \param mat the matrix to convert to "nearest" orientation * * \return -1 if results cannot be determined, 0 if okay *//*--------------------------------------------------------------------*/ int nifti_disp_matrix_orient( const char * mesg, nifti_dmat44 mat ) { int i, j, k; if ( mesg ) fputs( mesg, stderr ); /* use stdout? */ nifti_dmat44_to_orientation( mat, &i,&j,&k ); if ( i <= 0 || j <= 0 || k <= 0 ) return -1; /* so we have good codes */ fprintf(stderr, " 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; } /*----------------------------------------------------------------------*/ /*! duplicate the given string (alloc length+1) * * \return allocated pointer (or NULL on failure) *//*--------------------------------------------------------------------*/ char *nifti_strdup(const char *str) { char *dup; if( !str ) return NULL; /* allow calls passing NULL */ dup = (char *)malloc(strlen(str) + 1); /* check for failure */ if( dup ) strcpy(dup, str); else fprintf(stderr,"** nifti_strdup: failed to alloc %" PRId64 " bytes\n", (int64_t)(strlen(str)+1)); return dup; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI datatype. \param dt NIfTI-1 datatype \return pointer to static string holding the datatype name \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_DATATYPES group in nifti1.h *//*-------------------------------------------------------------------------*/ char const * nifti_datatype_string( int dt ) { switch( dt ){ case DT_UNKNOWN: return "UNKNOWN" ; case DT_BINARY: return "BINARY" ; case DT_INT8: return "INT8" ; case DT_UINT8: return "UINT8" ; case DT_INT16: return "INT16" ; case DT_UINT16: return "UINT16" ; case DT_INT32: return "INT32" ; case DT_UINT32: return "UINT32" ; case DT_INT64: return "INT64" ; case DT_UINT64: return "UINT64" ; case DT_FLOAT32: return "FLOAT32" ; case DT_FLOAT64: return "FLOAT64" ; case DT_FLOAT128: return "FLOAT128" ; case DT_COMPLEX64: return "COMPLEX64" ; case DT_COMPLEX128: return "COMPLEX128" ; case DT_COMPLEX256: return "COMPLEX256" ; case DT_RGB24: return "RGB24" ; case DT_RGBA32: return "RGBA32" ; default: break ; } return "**ILLEGAL**" ; } /*----------------------------------------------------------------------*/ /*! Determine if the datatype code dt is an integer type (1=YES, 0=NO). \return whether the given NIfTI-1 datatype code is valid \sa NIFTI1_DATATYPES group in nifti1.h *//*--------------------------------------------------------------------*/ int nifti_is_inttype( int dt ) { switch( dt ){ case DT_UNKNOWN: return 0 ; case DT_BINARY: return 0 ; case DT_INT8: return 1 ; case DT_UINT8: return 1 ; case DT_INT16: return 1 ; case DT_UINT16: return 1 ; case DT_INT32: return 1 ; case DT_UINT32: return 1 ; case DT_INT64: return 1 ; case DT_UINT64: return 1 ; case DT_FLOAT32: return 0 ; case DT_FLOAT64: return 0 ; case DT_FLOAT128: return 0 ; case DT_COMPLEX64: return 0 ; case DT_COMPLEX128: return 0 ; case DT_COMPLEX256: return 0 ; case DT_RGB24: return 1 ; case DT_RGBA32: return 1 ; default: break ; } return 0 ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI units type. \param uu NIfTI-1 unit code \return pointer to static string for the given unit type \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_UNITS group in nifti1.h *//*-------------------------------------------------------------------------*/ char const *nifti_units_string( int uu ) { switch( uu ){ case NIFTI_UNITS_METER: return "m" ; case NIFTI_UNITS_MM: return "mm" ; case NIFTI_UNITS_MICRON: return "um" ; case NIFTI_UNITS_SEC: return "s" ; case NIFTI_UNITS_MSEC: return "ms" ; case NIFTI_UNITS_USEC: return "us" ; case NIFTI_UNITS_HZ: return "Hz" ; case NIFTI_UNITS_PPM: return "ppm" ; case NIFTI_UNITS_RADS: return "rad/s" ; default: break ; } return "Unknown" ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI transform type. \param xx NIfTI-1 xform code \return pointer to static string describing xform code \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_XFORM_CODES group in nifti1.h *//*-------------------------------------------------------------------------*/ char const *nifti_xform_string( int xx ) { switch( xx ){ case NIFTI_XFORM_SCANNER_ANAT: return "Scanner Anat" ; case NIFTI_XFORM_ALIGNED_ANAT: return "Aligned Anat" ; case NIFTI_XFORM_TALAIRACH: return "Talairach" ; case NIFTI_XFORM_MNI_152: return "MNI_152" ; default: break ; } return "Unknown" ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI intent type. \param ii NIfTI-1 intent code \return pointer to static string describing code \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_INTENT_CODES group in nifti1.h *//*-------------------------------------------------------------------------*/ char const *nifti_intent_string( int ii ) { switch( ii ){ case NIFTI_INTENT_CORREL: return "Correlation statistic" ; case NIFTI_INTENT_TTEST: return "T-statistic" ; case NIFTI_INTENT_FTEST: return "F-statistic" ; case NIFTI_INTENT_ZSCORE: return "Z-score" ; case NIFTI_INTENT_CHISQ: return "Chi-squared distribution" ; case NIFTI_INTENT_BETA: return "Beta distribution" ; case NIFTI_INTENT_BINOM: return "Binomial distribution" ; case NIFTI_INTENT_GAMMA: return "Gamma distribution" ; case NIFTI_INTENT_POISSON: return "Poisson distribution" ; case NIFTI_INTENT_NORMAL: return "Normal distribution" ; case NIFTI_INTENT_FTEST_NONC: return "F-statistic noncentral" ; case NIFTI_INTENT_CHISQ_NONC: return "Chi-squared noncentral" ; case NIFTI_INTENT_LOGISTIC: return "Logistic distribution" ; case NIFTI_INTENT_LAPLACE: return "Laplace distribution" ; case NIFTI_INTENT_UNIFORM: return "Uniform distribition" ; case NIFTI_INTENT_TTEST_NONC: return "T-statistic noncentral" ; case NIFTI_INTENT_WEIBULL: return "Weibull distribution" ; case NIFTI_INTENT_CHI: return "Chi distribution" ; case NIFTI_INTENT_INVGAUSS: return "Inverse Gaussian distribution" ; case NIFTI_INTENT_EXTVAL: return "Extreme Value distribution" ; case NIFTI_INTENT_PVAL: return "P-value" ; case NIFTI_INTENT_LOGPVAL: return "Log P-value" ; case NIFTI_INTENT_LOG10PVAL: return "Log10 P-value" ; case NIFTI_INTENT_ESTIMATE: return "Estimate" ; case NIFTI_INTENT_LABEL: return "Label index" ; case NIFTI_INTENT_NEURONAME: return "NeuroNames index" ; case NIFTI_INTENT_GENMATRIX: return "General matrix" ; case NIFTI_INTENT_SYMMATRIX: return "Symmetric matrix" ; case NIFTI_INTENT_DISPVECT: return "Displacement vector" ; case NIFTI_INTENT_VECTOR: return "Vector" ; case NIFTI_INTENT_POINTSET: return "Pointset" ; case NIFTI_INTENT_TRIANGLE: return "Triangle" ; case NIFTI_INTENT_QUATERNION: return "Quaternion" ; case NIFTI_INTENT_DIMLESS: return "Dimensionless number" ; default: break ; } return "Unknown" ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI slice_code. \param ss NIfTI-1 slice order code \return pointer to static string describing code \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_SLICE_ORDER group in nifti1.h *//*-------------------------------------------------------------------------*/ char const *nifti_slice_string( int ss ) { switch( ss ){ case NIFTI_SLICE_SEQ_INC: return "sequential_increasing" ; case NIFTI_SLICE_SEQ_DEC: return "sequential_decreasing" ; case NIFTI_SLICE_ALT_INC: return "alternating_increasing" ; case NIFTI_SLICE_ALT_DEC: return "alternating_decreasing" ; case NIFTI_SLICE_ALT_INC2: return "alternating_increasing_2" ; case NIFTI_SLICE_ALT_DEC2: return "alternating_decreasing_2" ; default: break; } return "Unknown" ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI orientation. \param ii orientation code \return pointer to static string holding the orientation information \warning Do not free() or modify the return string! It points to static storage. \sa NIFTI_L2R in nifti1_io.h *//*-------------------------------------------------------------------------*/ char const *nifti_orientation_string( int ii ) { switch( ii ){ case NIFTI_L2R: return "Left-to-Right" ; case NIFTI_R2L: return "Right-to-Left" ; case NIFTI_P2A: return "Posterior-to-Anterior" ; case NIFTI_A2P: return "Anterior-to-Posterior" ; case NIFTI_I2S: return "Inferior-to-Superior" ; case NIFTI_S2I: return "Superior-to-Inferior" ; default: break; } return "Unknown" ; } /*--------------------------------------------------------------------------*/ /*! Given a datatype code, set number of bytes per voxel and the swapsize. \param datatype nifti1 datatype code \param nbyper pointer to return value: number of bytes per voxel \param swapsize pointer to return value: size of swap blocks \return appropriate values at nbyper and swapsize The swapsize is set to 0 if this datatype doesn't ever need swapping. \sa NIFTI1_DATATYPES in nifti1.h *//*------------------------------------------------------------------------*/ void nifti_datatype_sizes( int datatype , int *nbyper, int *swapsize ) { int nb=0, ss=0 ; switch( datatype ){ case DT_INT8: case DT_UINT8: nb = 1 ; ss = 0 ; break ; case DT_INT16: case DT_UINT16: nb = 2 ; ss = 2 ; break ; case DT_RGB24: nb = 3 ; ss = 0 ; break ; case DT_RGBA32: nb = 4 ; ss = 0 ; break ; case DT_INT32: case DT_UINT32: case DT_FLOAT32: nb = 4 ; ss = 4 ; break ; case DT_COMPLEX64: nb = 8 ; ss = 4 ; break ; case DT_FLOAT64: case DT_INT64: case DT_UINT64: nb = 8 ; ss = 8 ; break ; case DT_FLOAT128: nb = 16 ; ss = 16 ; break ; case DT_COMPLEX128: nb = 16 ; ss = 8 ; break ; case DT_COMPLEX256: nb = 32 ; ss = 16 ; break ; default: break; } ASSIF(nbyper,nb) ; ASSIF(swapsize,ss) ; } /*-----------------------------------------------------------------*/ /*! copy between float and double mat44 types 10 Jul, 2015 [rickr] */ int nifti_mat44_to_dmat44(mat44 * fm, nifti_dmat44 * dm) { int i, j; if( !dm || !fm ) return 1; for( i=0; i<4; i++ ) for( j=0; j<4; j++ ) dm->m[i][j] = (double)fm->m[i][j]; return 0; } int nifti_dmat44_to_mat44(nifti_dmat44 * dm, mat44 * fm) { int i, j; if( !dm || !fm ) return 1; for( i=0; i<4; i++ ) for( j=0; j<4; j++ ) fm->m[i][j] = (float)dm->m[i][j]; return 0; } /*---------------------------------------------------------------------------*/ /*! Given the quaternion parameters (etc.), compute a transformation matrix of doubles. See comments in nifti1.h for details. - qb,qc,qd = quaternion parameters - qx,qy,qz = offset parameters - dx,dy,dz = grid stepsizes (non-negative inputs are set to 1.0) - qfac = sign of dz step (< 0 is negative; >= 0 is positive)
   If qx=qy=qz=0, dx=dy=dz=1, then the output is a rotation matrix.
   For qfac >= 0, the rotation is proper.
   For qfac <  0, the rotation is improper.
   
\see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h \see nifti_mat44_to_quatern, nifti_make_orthog_mat44, nifti_mat44_to_orientation *//*-------------------------------------------------------------------------*/ nifti_dmat44 nifti_quatern_to_dmat44( double qb, double qc, double qd, double qx, double qy, double qz, double dx, double dy, double dz, double qfac ) { nifti_dmat44 R ; double a,b=qb,c=qc,d=qd , xd,yd,zd ; /* last row is always [ 0 0 0 1 ] */ R.m[3][0]=R.m[3][1]=R.m[3][2] = 0.0 ; R.m[3][3]= 1.0 ; /* compute a parameter from b,c,d */ a = 1.0l - (b*b + c*c + d*d) ; if( a < 1.e-7l ){ /* special case */ a = 1.0l / sqrt(b*b+c*c+d*d) ; b *= a ; c *= a ; d *= a ; /* normalize (b,c,d) vector */ a = 0.0l ; /* a = 0 ==> 180 degree rotation */ } else{ a = sqrt(a) ; /* angle = 2*arccos(a) */ } /* load rotation matrix, including scaling factors for voxel sizes */ xd = (dx > 0.0) ? dx : 1.0l ; /* make sure are positive */ yd = (dy > 0.0) ? dy : 1.0l ; zd = (dz > 0.0) ? dz : 1.0l ; if( qfac < 0.0 ) zd = -zd ; /* left handedness? */ R.m[0][0] = (a*a+b*b-c*c-d*d) * xd; R.m[0][1] = 2.0l * (b*c-a*d ) * yd ; R.m[0][2] = 2.0l * (b*d+a*c ) * zd ; R.m[1][0] = 2.0l * (b*c+a*d ) * xd ; R.m[1][1] = (a*a+c*c-b*b-d*d) * yd; R.m[1][2] = 2.0l * (c*d-a*b ) * zd ; R.m[2][0] = 2.0l * (b*d-a*c ) * xd ; R.m[2][1] = 2.0l * (c*d+a*b ) * yd ; R.m[2][2] = (a*a+d*d-c*c-b*b) * zd; /* load offsets */ R.m[0][3] = qx ; R.m[1][3] = qy ; R.m[2][3] = qz ; return R ; } /*---------------------------------------------------------------------------*/ /*! Given the quaternion parameters (etc.), compute a transformation matrix. See comments in nifti1.h for details. - qb,qc,qd = quaternion parameters - qx,qy,qz = offset parameters - dx,dy,dz = grid stepsizes (non-negative inputs are set to 1.0) - qfac = sign of dz step (< 0 is negative; >= 0 is positive)
   If qx=qy=qz=0, dx=dy=dz=1, then the output is a rotation matrix.
   For qfac >= 0, the rotation is proper.
   For qfac <  0, the rotation is improper.
   
\see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h \see nifti_mat44_to_quatern, nifti_make_orthog_mat44, nifti_mat44_to_orientation *//*-------------------------------------------------------------------------*/ mat44 nifti_quatern_to_mat44( float qb, float qc, float qd, float qx, float qy, float qz, float dx, float dy, float dz, float qfac ) { mat44 R ; double a,b=qb,c=qc,d=qd , xd,yd,zd ; /* last row is always [ 0 0 0 1 ] */ R.m[3][0]=R.m[3][1]=R.m[3][2] = 0.0f ; R.m[3][3]= 1.0f ; /* compute a parameter from b,c,d */ a = 1.0l - (b*b + c*c + d*d) ; if( a < 1.e-7l ){ /* special case */ a = 1.0l / sqrt(b*b+c*c+d*d) ; b *= a ; c *= a ; d *= a ; /* normalize (b,c,d) vector */ a = 0.0l ; /* a = 0 ==> 180 degree rotation */ } else{ a = sqrt(a) ; /* angle = 2*arccos(a) */ } /* load rotation matrix, including scaling factors for voxel sizes */ xd = (dx > 0.0) ? dx : 1.0l ; /* make sure are positive */ yd = (dy > 0.0) ? dy : 1.0l ; zd = (dz > 0.0) ? dz : 1.0l ; if( qfac < 0.0 ) zd = -zd ; /* left handedness? */ R.m[0][0] = (float)( (a*a+b*b-c*c-d*d) * xd) ; R.m[0][1] = 2.0l * (b*c-a*d ) * yd ; R.m[0][2] = 2.0l * (b*d+a*c ) * zd ; R.m[1][0] = 2.0l * (b*c+a*d ) * xd ; R.m[1][1] = (float)( (a*a+c*c-b*b-d*d) * yd) ; R.m[1][2] = 2.0l * (c*d-a*b ) * zd ; R.m[2][0] = 2.0l * (b*d-a*c ) * xd ; R.m[2][1] = 2.0l * (c*d+a*b ) * yd ; R.m[2][2] = (float)( (a*a+d*d-c*c-b*b) * zd) ; /* load offsets */ R.m[0][3] = qx ; R.m[1][3] = qy ; R.m[2][3] = qz ; return R ; } /*---------------------------------------------------------------------------*/ /*! Given the 3x4 upper corner of the matrix R, compute the quaternion parameters that fit it. - Any NULL pointer on input won't get assigned (e.g., if you don't want dx,dy,dz, just pass NULL in for those pointers). - If the 3 input matrix columns are NOT orthogonal, they will be orthogonalized prior to calculating the parameters, using the polar decomposition to find the orthogonal matrix closest to the column-normalized input matrix. - However, if the 3 input matrix columns are NOT orthogonal, then the matrix produced by nifti_quatern_to_dmat44 WILL have orthogonal columns, so it won't be the same as the matrix input here. This "feature" is because the NIFTI 'qform' transform is deliberately not fully general -- it is intended to model a volume with perpendicular axes. - If the 3 input matrix columns are not even linearly independent, you'll just have to take your luck, won't you? \see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h \see nifti_quatern_to_dmat44, nifti_make_orthog_dmat44, nifti_dmat44_to_orientation *//*-------------------------------------------------------------------------*/ void nifti_dmat44_to_quatern(nifti_dmat44 R , double *qb, double *qc, double *qd, double *qx, double *qy, double *qz, double *dx, double *dy, double *dz, double *qfac ) { double r11,r12,r13 , r21,r22,r23 , r31,r32,r33 ; double xd,yd,zd , a,b,c,d ; nifti_dmat33 P,Q ; /* offset outputs are read write out of input matrix */ ASSIF(qx,R.m[0][3]) ; ASSIF(qy,R.m[1][3]) ; ASSIF(qz,R.m[2][3]) ; /* load 3x3 matrix into local variables */ r11 = R.m[0][0] ; r12 = R.m[0][1] ; r13 = R.m[0][2] ; r21 = R.m[1][0] ; r22 = R.m[1][1] ; r23 = R.m[1][2] ; r31 = R.m[2][0] ; r32 = R.m[2][1] ; r33 = R.m[2][2] ; /* compute lengths of each column; these determine grid spacings */ xd = sqrt( r11*r11 + r21*r21 + r31*r31 ) ; yd = sqrt( r12*r12 + r22*r22 + r32*r32 ) ; zd = sqrt( r13*r13 + r23*r23 + r33*r33 ) ; /* if a column length is zero, patch the trouble */ if( xd == 0.0l ){ r11 = 1.0l ; r21 = r31 = 0.0l ; xd = 1.0l ; } if( yd == 0.0l ){ r22 = 1.0l ; r12 = r32 = 0.0l ; yd = 1.0l ; } if( zd == 0.0l ){ r33 = 1.0l ; r13 = r23 = 0.0l ; zd = 1.0l ; } /* assign the output lengths */ ASSIF(dx,xd) ; ASSIF(dy,yd) ; ASSIF(dz,zd) ; /* normalize the columns */ r11 /= xd ; r21 /= xd ; r31 /= xd ; r12 /= yd ; r22 /= yd ; r32 /= yd ; r13 /= zd ; r23 /= zd ; r33 /= zd ; /* At this point, the matrix has normal columns, but we have to allow for the fact that the hideous user may not have given us a matrix with orthogonal columns. So, now find the orthogonal matrix closest to the current matrix. One reason for using the polar decomposition to get this orthogonal matrix, rather than just directly orthogonalizing the columns, is so that inputting the inverse matrix to R will result in the inverse orthogonal matrix at this point. If we just orthogonalized the columns, this wouldn't necessarily hold. */ Q.m[0][0] = r11 ; Q.m[0][1] = r12 ; Q.m[0][2] = r13 ; /* load Q */ Q.m[1][0] = r21 ; Q.m[1][1] = r22 ; Q.m[1][2] = r23 ; Q.m[2][0] = r31 ; Q.m[2][1] = r32 ; Q.m[2][2] = r33 ; P = nifti_dmat33_polar(Q) ; /* P is orthog matrix closest to Q */ r11 = P.m[0][0] ; r12 = P.m[0][1] ; r13 = P.m[0][2] ; /* unload */ r21 = P.m[1][0] ; r22 = P.m[1][1] ; r23 = P.m[1][2] ; r31 = P.m[2][0] ; r32 = P.m[2][1] ; r33 = P.m[2][2] ; /* [ r11 r12 r13 ] */ /* at this point, the matrix [ r21 r22 r23 ] is orthogonal */ /* [ r31 r32 r33 ] */ /* compute the determinant to determine if it is proper */ zd = r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; /* should be -1 or 1 */ if( zd > 0 ){ /* proper */ ASSIF(qfac,1.0) ; } else { /* improper ==> flip 3rd column */ ASSIF(qfac,-1.0) ; r13 = -r13 ; r23 = -r23 ; r33 = -r33 ; } /* now, compute quaternion parameters */ a = r11 + r22 + r33 + 1.0l ; if( a > 0.5l ){ /* simplest case */ a = 0.5l * sqrt(a) ; b = 0.25l * (r32-r23) / a ; c = 0.25l * (r13-r31) / a ; d = 0.25l * (r21-r12) / a ; } else { /* trickier case */ xd = 1.0 + r11 - (r22+r33) ; /* 4*b*b */ yd = 1.0 + r22 - (r11+r33) ; /* 4*c*c */ zd = 1.0 + r33 - (r11+r22) ; /* 4*d*d */ if( xd > 1.0 ){ b = 0.5l * sqrt(xd) ; c = 0.25l* (r12+r21) / b ; d = 0.25l* (r13+r31) / b ; a = 0.25l* (r32-r23) / b ; } else if( yd > 1.0 ){ c = 0.5l * sqrt(yd) ; b = 0.25l* (r12+r21) / c ; d = 0.25l* (r23+r32) / c ; a = 0.25l* (r13-r31) / c ; } else { d = 0.5l * sqrt(zd) ; b = 0.25l* (r13+r31) / d ; c = 0.25l* (r23+r32) / d ; a = 0.25l* (r21-r12) / d ; } /* to be mathematically consistent, this would include a = -a */ if( a < 0.0l ){ b=-b ; c=-c ; d=-d; } } ASSIF(qb,b) ; ASSIF(qc,c) ; ASSIF(qd,d) ; } /*---------------------------------------------------------------------------*/ /*! Given the 3x4 upper corner of the matrix R, compute the quaternion parameters that fit it. - Any NULL pointer on input won't get assigned (e.g., if you don't want dx,dy,dz, just pass NULL in for those pointers). - If the 3 input matrix columns are NOT orthogonal, they will be orthogonalized prior to calculating the parameters, using the polar decomposition to find the orthogonal matrix closest to the column-normalized input matrix. - However, if the 3 input matrix columns are NOT orthogonal, then the matrix produced by nifti_quatern_to_mat44 WILL have orthogonal columns, so it won't be the same as the matrix input here. This "feature" is because the NIFTI 'qform' transform is deliberately not fully general -- it is intended to model a volume with perpendicular axes. - If the 3 input matrix columns are not even linearly independent, you'll just have to take your luck, won't you? \see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h \see nifti_quatern_to_mat44, nifti_make_orthog_mat44, nifti_mat44_to_orientation *//*-------------------------------------------------------------------------*/ void nifti_mat44_to_quatern( mat44 R , float *qb, float *qc, float *qd, float *qx, float *qy, float *qz, float *dx, float *dy, float *dz, float *qfac ) { double r11,r12,r13 , r21,r22,r23 , r31,r32,r33 ; double xd,yd,zd , a,b,c,d ; mat33 P,Q ; /* offset outputs are read write out of input matrix */ ASSIF(qx,R.m[0][3]) ; ASSIF(qy,R.m[1][3]) ; ASSIF(qz,R.m[2][3]) ; /* load 3x3 matrix into local variables */ r11 = R.m[0][0] ; r12 = R.m[0][1] ; r13 = R.m[0][2] ; r21 = R.m[1][0] ; r22 = R.m[1][1] ; r23 = R.m[1][2] ; r31 = R.m[2][0] ; r32 = R.m[2][1] ; r33 = R.m[2][2] ; /* compute lengths of each column; these determine grid spacings */ xd = sqrt( r11*r11 + r21*r21 + r31*r31 ) ; yd = sqrt( r12*r12 + r22*r22 + r32*r32 ) ; zd = sqrt( r13*r13 + r23*r23 + r33*r33 ) ; /* if a column length is zero, patch the trouble */ if( xd == 0.0l ){ r11 = 1.0l ; r21 = r31 = 0.0l ; xd = 1.0l ; } if( yd == 0.0l ){ r22 = 1.0l ; r12 = r32 = 0.0l ; yd = 1.0l ; } if( zd == 0.0l ){ r33 = 1.0l ; r13 = r23 = 0.0l ; zd = 1.0l ; } /* assign the output lengths */ ASSIF(dx,(float)xd) ; ASSIF(dy,(float)yd) ; ASSIF(dz,(float)zd) ; /* normalize the columns */ r11 /= xd ; r21 /= xd ; r31 /= xd ; r12 /= yd ; r22 /= yd ; r32 /= yd ; r13 /= zd ; r23 /= zd ; r33 /= zd ; /* At this point, the matrix has normal columns, but we have to allow for the fact that the hideous user may not have given us a matrix with orthogonal columns. So, now find the orthogonal matrix closest to the current matrix. One reason for using the polar decomposition to get this orthogonal matrix, rather than just directly orthogonalizing the columns, is so that inputting the inverse matrix to R will result in the inverse orthogonal matrix at this point. If we just orthogonalized the columns, this wouldn't necessarily hold. */ Q.m[0][0] = (float)r11 ; Q.m[0][1] = (float)r12 ; Q.m[0][2] = (float)r13 ; /* load Q */ Q.m[1][0] = (float)r21 ; Q.m[1][1] = (float)r22 ; Q.m[1][2] = (float)r23 ; Q.m[2][0] = (float)r31 ; Q.m[2][1] = (float)r32 ; Q.m[2][2] = (float)r33 ; P = nifti_mat33_polar(Q) ; /* P is orthog matrix closest to Q */ r11 = P.m[0][0] ; r12 = P.m[0][1] ; r13 = P.m[0][2] ; /* unload */ r21 = P.m[1][0] ; r22 = P.m[1][1] ; r23 = P.m[1][2] ; r31 = P.m[2][0] ; r32 = P.m[2][1] ; r33 = P.m[2][2] ; /* [ r11 r12 r13 ] */ /* at this point, the matrix [ r21 r22 r23 ] is orthogonal */ /* [ r31 r32 r33 ] */ /* compute the determinant to determine if it is proper */ zd = r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; /* should be -1 or 1 */ if( zd > 0 ){ /* proper */ ASSIF(qfac,1.0f) ; } else { /* improper ==> flip 3rd column */ ASSIF(qfac,-1.0f) ; r13 = -r13 ; r23 = -r23 ; r33 = -r33 ; } /* now, compute quaternion parameters */ a = r11 + r22 + r33 + 1.0l ; if( a > 0.5l ){ /* simplest case */ a = 0.5l * sqrt(a) ; b = 0.25l * (r32-r23) / a ; c = 0.25l * (r13-r31) / a ; d = 0.25l * (r21-r12) / a ; } else { /* trickier case */ xd = 1.0 + r11 - (r22+r33) ; /* 4*b*b */ yd = 1.0 + r22 - (r11+r33) ; /* 4*c*c */ zd = 1.0 + r33 - (r11+r22) ; /* 4*d*d */ if( xd > 1.0 ){ b = 0.5l * sqrt(xd) ; c = 0.25l* (r12+r21) / b ; d = 0.25l* (r13+r31) / b ; a = 0.25l* (r32-r23) / b ; } else if( yd > 1.0 ){ c = 0.5l * sqrt(yd) ; b = 0.25l* (r12+r21) / c ; d = 0.25l* (r23+r32) / c ; a = 0.25l* (r13-r31) / c ; } else { d = 0.5l * sqrt(zd) ; b = 0.25l* (r13+r31) / d ; c = 0.25l* (r23+r32) / d ; a = 0.25l* (r21-r12) / d ; } /* to be mathematically consistent, this would include a = -a */ if( a < 0.0l ){ b=-b ; c=-c ; d=-d; } } ASSIF(qb,(float)b) ; ASSIF(qc,(float)c) ; ASSIF(qd,(float)d) ; } /*---------------------------------------------------------------------------*/ /*! Compute the inverse of a bordered 4x4 matrix.
   - Some numerical code fragments were generated by Maple 8.
   - If a singular matrix is input, the output matrix will be all zero.
   - You can check for this by examining the [3][3] element, which will
     be 1.0 for the normal case and 0.0 for the bad case.

     The input matrix should have the form:
        [ r11 r12 r13 v1 ]
        [ r21 r22 r23 v2 ]
        [ r31 r32 r33 v3 ]
        [  0   0   0   1 ]
     
*//*-------------------------------------------------------------------------*/ nifti_dmat44 nifti_dmat44_inverse( nifti_dmat44 R ) { double r11,r12,r13,r21,r22,r23,r31,r32,r33,v1,v2,v3 , deti ; nifti_dmat44 Q ; /* INPUT MATRIX IS: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 v1 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 v2 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 v3 ] */ v1 = R.m[0][3]; v2 = R.m[1][3]; v3 = R.m[2][3]; /* [ 0 0 0 1 ] */ deti = r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; if( deti != 0.0l ) deti = 1.0l / deti ; Q.m[0][0] = deti*( r22*r33-r32*r23); Q.m[0][1] = deti*(-r12*r33+r32*r13); Q.m[0][2] = deti*( r12*r23-r22*r13); Q.m[0][3] = deti*(-r12*r23*v3+r12*v2*r33+r22*r13*v3 -r22*v1*r33-r32*r13*v2+r32*v1*r23); Q.m[1][0] = deti*(-r21*r33+r31*r23); Q.m[1][1] = deti*( r11*r33-r31*r13); Q.m[1][2] = deti*(-r11*r23+r21*r13); Q.m[1][3] = deti*( r11*r23*v3-r11*v2*r33-r21*r13*v3 +r21*v1*r33+r31*r13*v2-r31*v1*r23); Q.m[2][0] = deti*( r21*r32-r31*r22); Q.m[2][1] = deti*(-r11*r32+r31*r12); Q.m[2][2] = deti*( r11*r22-r21*r12); Q.m[2][3] = deti*(-r11*r22*v3+r11*r32*v2+r21*r12*v3 -r21*r32*v1-r31*r12*v2+r31*r22*v1); Q.m[3][0] = Q.m[3][1] = Q.m[3][2] = 0.0l ; Q.m[3][3] = (deti == 0.0l) ? 0.0l : 1.0l ; /* failure flag if deti == 0 */ return Q ; } /*---------------------------------------------------------------------------*/ /*! Compute the inverse of a bordered 4x4 matrix.
   - Some numerical code fragments were generated by Maple 8.
   - If a singular matrix is input, the output matrix will be all zero.
   - You can check for this by examining the [3][3] element, which will
     be 1.0 for the normal case and 0.0 for the bad case.

     The input matrix should have the form:
        [ r11 r12 r13 v1 ]
        [ r21 r22 r23 v2 ]
        [ r31 r32 r33 v3 ]
        [  0   0   0   1 ]
     
*//*-------------------------------------------------------------------------*/ mat44 nifti_mat44_inverse( mat44 R ) { double r11,r12,r13,r21,r22,r23,r31,r32,r33,v1,v2,v3 , deti ; mat44 Q ; /* INPUT MATRIX IS: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 v1 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 v2 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 v3 ] */ v1 = R.m[0][3]; v2 = R.m[1][3]; v3 = R.m[2][3]; /* [ 0 0 0 1 ] */ deti = r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; if( deti != 0.0l ) deti = 1.0l / deti ; Q.m[0][0] = (float)( deti*( r22*r33-r32*r23) ) ; Q.m[0][1] = (float)( deti*(-r12*r33+r32*r13) ) ; Q.m[0][2] = (float)( deti*( r12*r23-r22*r13) ) ; Q.m[0][3] = (float)( deti*(-r12*r23*v3+r12*v2*r33+r22*r13*v3 -r22*v1*r33-r32*r13*v2+r32*v1*r23) ) ; Q.m[1][0] = (float)( deti*(-r21*r33+r31*r23) ) ; Q.m[1][1] = (float)( deti*( r11*r33-r31*r13) ) ; Q.m[1][2] = (float)( deti*(-r11*r23+r21*r13) ) ; Q.m[1][3] = (float)( deti*( r11*r23*v3-r11*v2*r33-r21*r13*v3 +r21*v1*r33+r31*r13*v2-r31*v1*r23) ) ; Q.m[2][0] = (float)( deti*( r21*r32-r31*r22) ) ; Q.m[2][1] = (float)( deti*(-r11*r32+r31*r12) ) ; Q.m[2][2] = (float)( deti*( r11*r22-r21*r12) ) ; Q.m[2][3] = (float)( deti*(-r11*r22*v3+r11*r32*v2+r21*r12*v3 -r21*r32*v1-r31*r12*v2+r31*r22*v1) ) ; Q.m[3][0] = Q.m[3][1] = Q.m[3][2] = 0.0l ; Q.m[3][3] = (deti == 0.0l) ? 0.0l : 1.0l ; /* failure flag if deti == 0 */ return Q ; } /*---------------------------------------------------------------------------*/ /*! Input 9 floats and make an orthgonal nifti_dmat44 out of them. Each row is normalized, then nifti_mat33_polar() is used to orthogonalize them. If row #3 (r31,r32,r33) is input as zero, then it will be taken to be the cross product of rows #1 and #2. This function can be used to create a rotation matrix for transforming an oblique volume to anatomical coordinates. For this application: - row #1 (r11,r12,r13) is the direction vector along the image i-axis - row #2 (r21,r22,r23) is the direction vector along the image j-axis - row #3 (r31,r32,r33) is the direction vector along the slice direction (if available; otherwise enter it as 0's) The first 2 rows can be taken from the DICOM attribute (0020,0037) "Image Orientation (Patient)". After forming the rotation matrix, the complete affine transformation from (i,j,k) grid indexes to (x,y,z) spatial coordinates can be computed by multiplying each column by the appropriate grid spacing: - column #1 (R.m[0][0],R.m[1][0],R.m[2][0]) by delta-x - column #2 (R.m[0][1],R.m[1][1],R.m[2][1]) by delta-y - column #3 (R.m[0][2],R.m[1][2],R.m[2][2]) by delta-z and by then placing the center (x,y,z) coordinates of voxel (0,0,0) into the column #4 (R.m[0][3],R.m[1][3],R.m[2][3]). \sa nifti_quatern_to_dmat44, nifti_dmat44_to_quatern, nifti_dmat44_to_orientation *//*-------------------------------------------------------------------------*/ nifti_dmat44 nifti_make_orthog_dmat44( double r11, double r12, double r13 , double r21, double r22, double r23 , double r31, double r32, double r33 ) { nifti_dmat44 R ; nifti_dmat33 Q , P ; double val ; R.m[3][0] = R.m[3][1] = R.m[3][2] = 0.0l ; R.m[3][3] = 1.0l ; Q.m[0][0] = r11 ; Q.m[0][1] = r12 ; Q.m[0][2] = r13 ; /* load Q */ Q.m[1][0] = r21 ; Q.m[1][1] = r22 ; Q.m[1][2] = r23 ; Q.m[2][0] = r31 ; Q.m[2][1] = r32 ; Q.m[2][2] = r33 ; /* normalize row 1 */ val = Q.m[0][0]*Q.m[0][0] + Q.m[0][1]*Q.m[0][1] + Q.m[0][2]*Q.m[0][2] ; if( val > 0.0l ){ val = 1.0l / sqrt(val) ; Q.m[0][0] *= val ; Q.m[0][1] *= val ; Q.m[0][2] *= val ; } else { Q.m[0][0] = 1.0l ; Q.m[0][1] = 0.0l ; Q.m[0][2] = 0.0l ; } /* normalize row 2 */ val = Q.m[1][0]*Q.m[1][0] + Q.m[1][1]*Q.m[1][1] + Q.m[1][2]*Q.m[1][2] ; if( val > 0.0l ){ val = 1.0l / sqrt(val) ; Q.m[1][0] *= val ; Q.m[1][1] *= val ; Q.m[1][2] *= val ; } else { Q.m[1][0] = 0.0l ; Q.m[1][1] = 1.0l ; Q.m[1][2] = 0.0l ; } /* normalize row 3 */ val = Q.m[2][0]*Q.m[2][0] + Q.m[2][1]*Q.m[2][1] + Q.m[2][2]*Q.m[2][2] ; if( val > 0.0l ){ val = 1.0l / sqrt(val) ; Q.m[2][0] *= val ; Q.m[2][1] *= val ; Q.m[2][2] *= val ; } else { Q.m[2][0] = Q.m[0][1]*Q.m[1][2] - Q.m[0][2]*Q.m[1][1] ; /* cross */ Q.m[2][1] = Q.m[0][2]*Q.m[1][0] - Q.m[0][0]*Q.m[1][2] ; /* product */ Q.m[2][2] = Q.m[0][0]*Q.m[1][1] - Q.m[0][1]*Q.m[1][0] ; } P = nifti_dmat33_polar(Q) ; /* P is orthog matrix closest to Q */ R.m[0][0] = P.m[0][0] ; R.m[0][1] = P.m[0][1] ; R.m[0][2] = P.m[0][2] ; R.m[1][0] = P.m[1][0] ; R.m[1][1] = P.m[1][1] ; R.m[1][2] = P.m[1][2] ; R.m[2][0] = P.m[2][0] ; R.m[2][1] = P.m[2][1] ; R.m[2][2] = P.m[2][2] ; R.m[0][3] = R.m[1][3] = R.m[2][3] = 0.0f ; return R ; } /*---------------------------------------------------------------------------*/ /*! Input 9 floats and make an orthgonal mat44 out of them. Each row is normalized, then nifti_mat33_polar() is used to orthogonalize them. If row #3 (r31,r32,r33) is input as zero, then it will be taken to be the cross product of rows #1 and #2. This function can be used to create a rotation matrix for transforming an oblique volume to anatomical coordinates. For this application: - row #1 (r11,r12,r13) is the direction vector along the image i-axis - row #2 (r21,r22,r23) is the direction vector along the image j-axis - row #3 (r31,r32,r33) is the direction vector along the slice direction (if available; otherwise enter it as 0's) The first 2 rows can be taken from the DICOM attribute (0020,0037) "Image Orientation (Patient)". After forming the rotation matrix, the complete affine transformation from (i,j,k) grid indexes to (x,y,z) spatial coordinates can be computed by multiplying each column by the appropriate grid spacing: - column #1 (R.m[0][0],R.m[1][0],R.m[2][0]) by delta-x - column #2 (R.m[0][1],R.m[1][1],R.m[2][1]) by delta-y - column #3 (R.m[0][2],R.m[1][2],R.m[2][2]) by delta-z and by then placing the center (x,y,z) coordinates of voxel (0,0,0) into the column #4 (R.m[0][3],R.m[1][3],R.m[2][3]). \sa nifti_quatern_to_mat44, nifti_mat44_to_quatern, nifti_mat44_to_orientation *//*-------------------------------------------------------------------------*/ mat44 nifti_make_orthog_mat44( float r11, float r12, float r13 , float r21, float r22, float r23 , float r31, float r32, float r33 ) { mat44 R ; mat33 Q , P ; double val ; R.m[3][0] = R.m[3][1] = R.m[3][2] = 0.0l ; R.m[3][3] = 1.0l ; Q.m[0][0] = r11 ; Q.m[0][1] = r12 ; Q.m[0][2] = r13 ; /* load Q */ Q.m[1][0] = r21 ; Q.m[1][1] = r22 ; Q.m[1][2] = r23 ; Q.m[2][0] = r31 ; Q.m[2][1] = r32 ; Q.m[2][2] = r33 ; /* normalize row 1 */ val = Q.m[0][0]*Q.m[0][0] + Q.m[0][1]*Q.m[0][1] + Q.m[0][2]*Q.m[0][2] ; if( val > 0.0l ){ val = 1.0l / sqrt(val) ; Q.m[0][0] *= (float)val ; Q.m[0][1] *= (float)val ; Q.m[0][2] *= (float)val ; } else { Q.m[0][0] = 1.0l ; Q.m[0][1] = 0.0l ; Q.m[0][2] = 0.0l ; } /* normalize row 2 */ val = Q.m[1][0]*Q.m[1][0] + Q.m[1][1]*Q.m[1][1] + Q.m[1][2]*Q.m[1][2] ; if( val > 0.0l ){ val = 1.0l / sqrt(val) ; Q.m[1][0] *= (float)val ; Q.m[1][1] *= (float)val ; Q.m[1][2] *= (float)val ; } else { Q.m[1][0] = 0.0l ; Q.m[1][1] = 1.0l ; Q.m[1][2] = 0.0l ; } /* normalize row 3 */ val = Q.m[2][0]*Q.m[2][0] + Q.m[2][1]*Q.m[2][1] + Q.m[2][2]*Q.m[2][2] ; if( val > 0.0l ){ val = 1.0l / sqrt(val) ; Q.m[2][0] *= (float)val ; Q.m[2][1] *= (float)val ; Q.m[2][2] *= (float)val ; } else { Q.m[2][0] = Q.m[0][1]*Q.m[1][2] - Q.m[0][2]*Q.m[1][1] ; /* cross */ Q.m[2][1] = Q.m[0][2]*Q.m[1][0] - Q.m[0][0]*Q.m[1][2] ; /* product */ Q.m[2][2] = Q.m[0][0]*Q.m[1][1] - Q.m[0][1]*Q.m[1][0] ; } P = nifti_mat33_polar(Q) ; /* P is orthog matrix closest to Q */ R.m[0][0] = P.m[0][0] ; R.m[0][1] = P.m[0][1] ; R.m[0][2] = P.m[0][2] ; R.m[1][0] = P.m[1][0] ; R.m[1][1] = P.m[1][1] ; R.m[1][2] = P.m[1][2] ; R.m[2][0] = P.m[2][0] ; R.m[2][1] = P.m[2][1] ; R.m[2][2] = P.m[2][2] ; R.m[0][3] = R.m[1][3] = R.m[2][3] = 0.0f ; return R ; } /*----------------------------------------------------------------------*/ /*! compute the inverse of a 3x3 matrix *//*--------------------------------------------------------------------*/ nifti_dmat33 nifti_dmat33_inverse( nifti_dmat33 R ) /* inverse of 3x3 matrix */ { double r11,r12,r13,r21,r22,r23,r31,r32,r33 , deti ; nifti_dmat33 Q ; /* INPUT MATRIX: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 ] */ deti = r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; if( deti != 0.0l ) deti = 1.0l / deti ; Q.m[0][0] = deti*( r22*r33-r32*r23); Q.m[0][1] = deti*(-r12*r33+r32*r13); Q.m[0][2] = deti*( r12*r23-r22*r13); Q.m[1][0] = deti*(-r21*r33+r31*r23); Q.m[1][1] = deti*( r11*r33-r31*r13); Q.m[1][2] = deti*(-r11*r23+r21*r13); Q.m[2][0] = deti*( r21*r32-r31*r22); Q.m[2][1] = deti*(-r11*r32+r31*r12); Q.m[2][2] = deti*( r11*r22-r21*r12); return Q ; } /*----------------------------------------------------------------------*/ /*! compute the inverse of a 3x3 matrix *//*--------------------------------------------------------------------*/ mat33 nifti_mat33_inverse( mat33 R ) /* inverse of 3x3 matrix */ { double r11,r12,r13,r21,r22,r23,r31,r32,r33 , deti ; mat33 Q ; /* INPUT MATRIX: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 ] */ deti = r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; if( deti != 0.0l ) deti = 1.0l / deti ; Q.m[0][0] = (float)( deti*( r22*r33-r32*r23) ) ; Q.m[0][1] = (float)( deti*(-r12*r33+r32*r13) ) ; Q.m[0][2] = (float)( deti*( r12*r23-r22*r13) ) ; Q.m[1][0] = (float)( deti*(-r21*r33+r31*r23) ) ; Q.m[1][1] = (float)( deti*( r11*r33-r31*r13) ) ; Q.m[1][2] = (float)( deti*(-r11*r23+r21*r13) ) ; Q.m[2][0] = (float)( deti*( r21*r32-r31*r22) ) ; Q.m[2][1] = (float)( deti*(-r11*r32+r31*r12) ) ; Q.m[2][2] = (float)( deti*( r11*r22-r21*r12) ) ; return Q ; } /*----------------------------------------------------------------------*/ /*! compute the determinant of a 3x3 matrix *//*--------------------------------------------------------------------*/ double nifti_dmat33_determ( nifti_dmat33 R ) /* determinant of 3x3 matrix */ { double r11,r12,r13,r21,r22,r23,r31,r32,r33 ; /* INPUT MATRIX: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 ] */ return (r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13) ; } /*----------------------------------------------------------------------*/ /*! compute the determinant of a 3x3 matrix *//*--------------------------------------------------------------------*/ float nifti_mat33_determ( mat33 R ) /* determinant of 3x3 matrix */ { double r11,r12,r13,r21,r22,r23,r31,r32,r33 ; /* INPUT MATRIX: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 ] */ return (float)(r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13) ; } /*----------------------------------------------------------------------*/ /*! compute the max row norm of a 3x3 matrix *//*--------------------------------------------------------------------*/ double nifti_dmat33_rownorm( nifti_dmat33 A ) /* max row norm of 3x3 matrix */ { double r1,r2,r3 ; r1 = fabs(A.m[0][0])+fabs(A.m[0][1])+fabs(A.m[0][2]); r2 = fabs(A.m[1][0])+fabs(A.m[1][1])+fabs(A.m[1][2]); r3 = fabs(A.m[2][0])+fabs(A.m[2][1])+fabs(A.m[2][2]); if( r1 < r2 ) r1 = r2 ; if( r1 < r3 ) r1 = r3 ; return r1 ; } /*----------------------------------------------------------------------*/ /*! compute the max row norm of a 3x3 matrix *//*--------------------------------------------------------------------*/ float nifti_mat33_rownorm( mat33 A ) /* max row norm of 3x3 matrix */ { float r1,r2,r3 ; r1 = (float)( fabs(A.m[0][0])+fabs(A.m[0][1])+fabs(A.m[0][2]) ) ; r2 = (float)( fabs(A.m[1][0])+fabs(A.m[1][1])+fabs(A.m[1][2]) ) ; r3 = (float)( fabs(A.m[2][0])+fabs(A.m[2][1])+fabs(A.m[2][2]) ) ; if( r1 < r2 ) r1 = r2 ; if( r1 < r3 ) r1 = r3 ; return r1 ; } /*----------------------------------------------------------------------*/ /*! compute the max column norm of a 3x3 matrix *//*--------------------------------------------------------------------*/ double nifti_dmat33_colnorm( nifti_dmat33 A )/* max column norm of 3x3 matrix */ { double r1,r2,r3 ; r1 = fabs(A.m[0][0])+fabs(A.m[1][0])+fabs(A.m[2][0]); r2 = fabs(A.m[0][1])+fabs(A.m[1][1])+fabs(A.m[2][1]); r3 = fabs(A.m[0][2])+fabs(A.m[1][2])+fabs(A.m[2][2]); if( r1 < r2 ) r1 = r2 ; if( r1 < r3 ) r1 = r3 ; return r1 ; } /*----------------------------------------------------------------------*/ /*! compute the max column norm of a 3x3 matrix *//*--------------------------------------------------------------------*/ float nifti_mat33_colnorm( mat33 A ) /* max column norm of 3x3 matrix */ { float r1,r2,r3 ; r1 = (float)( fabs(A.m[0][0])+fabs(A.m[1][0])+fabs(A.m[2][0]) ) ; r2 = (float)( fabs(A.m[0][1])+fabs(A.m[1][1])+fabs(A.m[2][1]) ) ; r3 = (float)( fabs(A.m[0][2])+fabs(A.m[1][2])+fabs(A.m[2][2]) ) ; if( r1 < r2 ) r1 = r2 ; if( r1 < r3 ) r1 = r3 ; return r1 ; } /*----------------------------------------------------------------------*/ /*! multiply 2 3x3 matrices *//*--------------------------------------------------------------------*/ nifti_dmat33 nifti_dmat33_mul( nifti_dmat33 A , nifti_dmat33 B ) /* multiply 2 3x3 matrices */ { nifti_dmat33 C ; int i,j ; for( i=0 ; i < 3 ; i++ ) for( j=0 ; j < 3 ; j++ ) C.m[i][j] = A.m[i][0] * B.m[0][j] + A.m[i][1] * B.m[1][j] + A.m[i][2] * B.m[2][j] ; return C ; } /*----------------------------------------------------------------------*/ /*! multiply 2 3x3 matrices *//*--------------------------------------------------------------------*/ mat33 nifti_mat33_mul( mat33 A , mat33 B ) /* multiply 2 3x3 matrices */ { mat33 C ; int i,j ; for( i=0 ; i < 3 ; i++ ) for( j=0 ; j < 3 ; j++ ) C.m[i][j] = A.m[i][0] * B.m[0][j] + A.m[i][1] * B.m[1][j] + A.m[i][2] * B.m[2][j] ; return C ; } /*----------------------------------------------------------------------*/ /*! multiply 2 4x4 matrices *//*--------------------------------------------------------------------*/ nifti_dmat44 nifti_dmat44_mul( nifti_dmat44 A , nifti_dmat44 B ) { nifti_dmat44 C ; int i,j,k ; for( i=0 ; i < 4 ; i++ ) for( j=0 ; j < 4 ; j++ ) { C.m[i][j] = 0.0; for( k=0; k < 4; k++ ) C.m[i][j] += A.m[i][k] * B.m[k][j]; } return C ; } /*----------------------------------------------------------------------*/ /*! multiply 2 4x4 matrices *//*--------------------------------------------------------------------*/ mat44 nifti_mat44_mul( mat44 A , mat44 B ) { mat44 C ; int i,j,k ; for( i=0 ; i < 4 ; i++ ) for( j=0 ; j < 4 ; j++ ) { C.m[i][j] = 0.0; for( k=0; k < 4; k++ ) C.m[i][j] += A.m[i][k] * B.m[k][j]; } return C ; } /*---------------------------------------------------------------------------*/ /*! polar decomposition of a 3x3 matrix This finds the closest orthogonal matrix to input A (in both the Frobenius and L2 norms). Algorithm is that from NJ Higham, SIAM J Sci Stat Comput, 7:1160-1174. *//*-------------------------------------------------------------------------*/ nifti_dmat33 nifti_dmat33_polar( nifti_dmat33 A ) { nifti_dmat33 X , Y , Z ; double alp,bet,gam,gmi , dif=1.0 ; int k=0 ; X = A ; /* force matrix to be nonsingular */ gam = nifti_dmat33_determ(X) ; while( gam == 0.0 ){ /* perturb matrix */ gam = 0.00001 * ( 0.001 + nifti_dmat33_rownorm(X) ); X.m[0][0] += gam ; X.m[1][1] += gam ; X.m[2][2] += gam ; gam = nifti_dmat33_determ(X) ; } while(1){ Y = nifti_dmat33_inverse(X) ; if( dif > 0.3 ){ /* far from convergence */ alp = sqrt( nifti_dmat33_rownorm(X) * nifti_dmat33_colnorm(X) ); bet = sqrt( nifti_dmat33_rownorm(Y) * nifti_dmat33_colnorm(Y) ); gam = sqrt( bet / alp ); gmi = 1.0 / gam; } else { gam = gmi = 1.0f ; /* close to convergence */ } Z.m[0][0] = 0.5 * ( gam*X.m[0][0] + gmi*Y.m[0][0] ); Z.m[0][1] = 0.5 * ( gam*X.m[0][1] + gmi*Y.m[1][0] ); Z.m[0][2] = 0.5 * ( gam*X.m[0][2] + gmi*Y.m[2][0] ); Z.m[1][0] = 0.5 * ( gam*X.m[1][0] + gmi*Y.m[0][1] ); Z.m[1][1] = 0.5 * ( gam*X.m[1][1] + gmi*Y.m[1][1] ); Z.m[1][2] = 0.5 * ( gam*X.m[1][2] + gmi*Y.m[2][1] ); Z.m[2][0] = 0.5 * ( gam*X.m[2][0] + gmi*Y.m[0][2] ); Z.m[2][1] = 0.5 * ( gam*X.m[2][1] + gmi*Y.m[1][2] ); Z.m[2][2] = 0.5 * ( gam*X.m[2][2] + gmi*Y.m[2][2] ); dif = fabs(Z.m[0][0]-X.m[0][0])+fabs(Z.m[0][1]-X.m[0][1]) +fabs(Z.m[0][2]-X.m[0][2])+fabs(Z.m[1][0]-X.m[1][0]) +fabs(Z.m[1][1]-X.m[1][1])+fabs(Z.m[1][2]-X.m[1][2]) +fabs(Z.m[2][0]-X.m[2][0])+fabs(Z.m[2][1]-X.m[2][1]) +fabs(Z.m[2][2]-X.m[2][2]); k = k+1 ; if( k > 100 || dif < 3.e-6 ) break ; /* convergence or exhaustion */ X = Z ; } return Z ; } /*---------------------------------------------------------------------------*/ /*! polar decomposition of a 3x3 matrix This finds the closest orthogonal matrix to input A (in both the Frobenius and L2 norms). Algorithm is that from NJ Higham, SIAM J Sci Stat Comput, 7:1160-1174. *//*-------------------------------------------------------------------------*/ mat33 nifti_mat33_polar( mat33 A ) { mat33 X , Y , Z ; float alp,bet,gam,gmi , dif=1.0f ; int k=0 ; X = A ; /* force matrix to be nonsingular */ gam = nifti_mat33_determ(X) ; while( gam == 0.0 ){ /* perturb matrix */ gam = (float)( 0.00001 * ( 0.001 + nifti_mat33_rownorm(X) ) ) ; X.m[0][0] += gam ; X.m[1][1] += gam ; X.m[2][2] += gam ; gam = nifti_mat33_determ(X) ; } while(1){ Y = nifti_mat33_inverse(X) ; if( dif > 0.3 ){ /* far from convergence */ alp = (float)( sqrt( nifti_mat33_rownorm(X) * nifti_mat33_colnorm(X) ) ) ; bet = (float)( sqrt( nifti_mat33_rownorm(Y) * nifti_mat33_colnorm(Y) ) ) ; gam = (float)( sqrt( bet / alp ) ) ; gmi = (float)( 1.0 / gam ) ; } else { gam = gmi = 1.0f ; /* close to convergence */ } Z.m[0][0] = (float)( 0.5 * ( gam*X.m[0][0] + gmi*Y.m[0][0] ) ) ; Z.m[0][1] = (float)( 0.5 * ( gam*X.m[0][1] + gmi*Y.m[1][0] ) ) ; Z.m[0][2] = (float)( 0.5 * ( gam*X.m[0][2] + gmi*Y.m[2][0] ) ) ; Z.m[1][0] = (float)( 0.5 * ( gam*X.m[1][0] + gmi*Y.m[0][1] ) ) ; Z.m[1][1] = (float)( 0.5 * ( gam*X.m[1][1] + gmi*Y.m[1][1] ) ) ; Z.m[1][2] = (float)( 0.5 * ( gam*X.m[1][2] + gmi*Y.m[2][1] ) ) ; Z.m[2][0] = (float)( 0.5 * ( gam*X.m[2][0] + gmi*Y.m[0][2] ) ) ; Z.m[2][1] = (float)( 0.5 * ( gam*X.m[2][1] + gmi*Y.m[1][2] ) ) ; Z.m[2][2] = (float)( 0.5 * ( gam*X.m[2][2] + gmi*Y.m[2][2] ) ) ; dif = (float)( fabs(Z.m[0][0]-X.m[0][0])+fabs(Z.m[0][1]-X.m[0][1]) +fabs(Z.m[0][2]-X.m[0][2])+fabs(Z.m[1][0]-X.m[1][0]) +fabs(Z.m[1][1]-X.m[1][1])+fabs(Z.m[1][2]-X.m[1][2]) +fabs(Z.m[2][0]-X.m[2][0])+fabs(Z.m[2][1]-X.m[2][1]) +fabs(Z.m[2][2]-X.m[2][2]) ); k = k+1 ; if( k > 100 || dif < 3.e-6 ) break ; /* convergence or exhaustion */ X = Z ; } return Z ; } /*---------------------------------------------------------------------------*/ /*! compute the (closest) orientation from a 4x4 ijk->xyz tranformation matrix
   Input:  4x4 matrix that transforms (i,j,k) indexes to (x,y,z) coordinates,
           where +x=Right, +y=Anterior, +z=Superior.
           (Only the upper-left 3x3 corner of R is used herein.)
   Output: 3 orientation codes that correspond to the closest "standard"
           anatomical orientation of the (i,j,k) axes.
   Method: Find which permutation of (x,y,z) has the smallest angle to the
           (i,j,k) axes directions, which are the columns of the R matrix.
   Errors: The codes returned will be zero.

   For example, an axial volume might get return values of
     *icod = NIFTI_R2L   (i axis is mostly Right to Left)
     *jcod = NIFTI_P2A   (j axis is mostly Posterior to Anterior)
     *kcod = NIFTI_I2S   (k axis is mostly Inferior to Superior)
   
\see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h \see nifti_quatern_to_mat44, nifti_mat44_to_quatern, nifti_make_orthog_mat44 *//*-------------------------------------------------------------------------*/ void nifti_dmat44_to_orientation( nifti_dmat44 R , int *icod, int *jcod, int *kcod ) { double xi,xj,xk , yi,yj,yk , zi,zj,zk , val,detQ,detP ; nifti_dmat33 P , Q , M ; int i,j,k=0,p,q,r , ibest,jbest,kbest,pbest,qbest,rbest ; double vbest ; if( icod == NULL || jcod == NULL || kcod == NULL ) return ; /* bad */ *icod = *jcod = *kcod = 0 ; /* error returns, if sh*t happens */ /* load column vectors for each (i,j,k) direction from matrix */ /*-- i axis --*/ /*-- j axis --*/ /*-- k axis --*/ xi = R.m[0][0] ; xj = R.m[0][1] ; xk = R.m[0][2] ; yi = R.m[1][0] ; yj = R.m[1][1] ; yk = R.m[1][2] ; zi = R.m[2][0] ; zj = R.m[2][1] ; zk = R.m[2][2] ; /* normalize column vectors to get unit vectors along each ijk-axis */ /* normalize i axis */ val = sqrt( xi*xi + yi*yi + zi*zi ) ; if( val == 0.0 ) return ; /* stupid input */ xi /= val ; yi /= val ; zi /= val ; /* normalize j axis */ val = sqrt( xj*xj + yj*yj + zj*zj ) ; if( val == 0.0 ) return ; /* stupid input */ xj /= val ; yj /= val ; zj /= val ; /* orthogonalize j axis to i axis, if needed */ val = xi*xj + yi*yj + zi*zj ; /* dot product between i and j */ if( fabs(val) > 1.e-4 ){ xj -= val*xi ; yj -= val*yi ; zj -= val*zi ; val = sqrt( xj*xj + yj*yj + zj*zj ) ; /* must renormalize */ if( val == 0.0 ) return ; /* j was parallel to i? */ xj /= val ; yj /= val ; zj /= val ; } /* normalize k axis; if it is zero, make it the cross product i x j */ val = sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ){ xk = yi*zj-zi*yj; yk = zi*xj-zj*xi ; zk=xi*yj-yi*xj ; } else { xk /= val ; yk /= val ; zk /= val ; } /* orthogonalize k to i */ val = xi*xk + yi*yk + zi*zk ; /* dot product between i and k */ if( fabs(val) > 1.e-4 ){ xk -= val*xi ; yk -= val*yi ; zk -= val*zi ; val = sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ) return ; /* bad */ xk /= val ; yk /= val ; zk /= val ; } /* orthogonalize k to j */ val = xj*xk + yj*yk + zj*zk ; /* dot product between j and k */ if( fabs(val) > 1.e-4 ){ xk -= val*xj ; yk -= val*yj ; zk -= val*zj ; val = sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ) return ; /* bad */ xk /= val ; yk /= val ; zk /= val ; } Q.m[0][0] = xi ; Q.m[0][1] = xj ; Q.m[0][2] = xk ; Q.m[1][0] = yi ; Q.m[1][1] = yj ; Q.m[1][2] = yk ; Q.m[2][0] = zi ; Q.m[2][1] = zj ; Q.m[2][2] = zk ; /* at this point, Q is the rotation matrix from (i,j,k) to (x,y,z) axes */ detQ = nifti_dmat33_determ( Q ) ; if( detQ == 0.0 ) return ; /* shouldn't happen unless user is a DUFIS */ /* Build and test all possible +1/-1 coordinate permutation matrices P; then find the P such that the rotation matrix M=PQ is closest to the identity, in the sense of M having the smallest total rotation angle. */ /* Despite the formidable looking 6 nested loops, there are only 3*3*3*2*2*2 = 216 passes, which will run very quickly. */ vbest = -666.0 ; ibest=pbest=qbest=rbest=1 ; jbest=2 ; kbest=3 ; for( i=1 ; i <= 3 ; i++ ){ /* i = column number to use for row #1 */ for( j=1 ; j <= 3 ; j++ ){ /* j = column number to use for row #2 */ if( i == j ) continue ; for( k=1 ; k <= 3 ; k++ ){ /* k = column number to use for row #3 */ if( i == k || j == k ) continue ; P.m[0][0] = P.m[0][1] = P.m[0][2] = P.m[1][0] = P.m[1][1] = P.m[1][2] = P.m[2][0] = P.m[2][1] = P.m[2][2] = 0.0 ; for( p=-1 ; p <= 1 ; p+=2 ){ /* p,q,r are -1 or +1 */ for( q=-1 ; q <= 1 ; q+=2 ){ /* and go into rows #1,2,3 */ for( r=-1 ; r <= 1 ; r+=2 ){ P.m[0][i-1] = p ; P.m[1][j-1] = q ; P.m[2][k-1] = r ; detP = nifti_dmat33_determ(P) ; /* sign of permutation */ if( detP * detQ <= 0.0 ) continue ; /* doesn't match sign of Q */ M = nifti_dmat33_mul(P,Q) ; /* angle of M rotation = 2.0*acos(0.5*sqrt(1.0+trace(M))) */ /* we want largest trace(M) == smallest angle == M nearest to I */ val = M.m[0][0] + M.m[1][1] + M.m[2][2] ; /* trace */ if( val > vbest ){ vbest = val ; ibest = i ; jbest = j ; kbest = k ; pbest = p ; qbest = q ; rbest = r ; } }}}}}} /* At this point ibest is 1 or 2 or 3; pbest is -1 or +1; etc. The matrix P that corresponds is the best permutation approximation to Q-inverse; that is, P (approximately) takes (x,y,z) coordinates to the (i,j,k) axes. For example, the first row of P (which contains pbest in column ibest) determines the way the i axis points relative to the anatomical (x,y,z) axes. If ibest is 2, then the i axis is along the y axis, which is direction P2A (if pbest > 0) or A2P (if pbest < 0). So, using ibest and pbest, we can assign the output code for the i axis. Mutatis mutandis for the j and k axes, of course. */ switch( ibest*pbest ){ case 1: i = NIFTI_L2R ; break ; case -1: i = NIFTI_R2L ; break ; case 2: i = NIFTI_P2A ; break ; case -2: i = NIFTI_A2P ; break ; case 3: i = NIFTI_I2S ; break ; case -3: i = NIFTI_S2I ; break ; default: break; } switch( jbest*qbest ){ case 1: j = NIFTI_L2R ; break ; case -1: j = NIFTI_R2L ; break ; case 2: j = NIFTI_P2A ; break ; case -2: j = NIFTI_A2P ; break ; case 3: j = NIFTI_I2S ; break ; case -3: j = NIFTI_S2I ; break ; default: break; } switch( kbest*rbest ){ case 1: k = NIFTI_L2R ; break ; case -1: k = NIFTI_R2L ; break ; case 2: k = NIFTI_P2A ; break ; case -2: k = NIFTI_A2P ; break ; case 3: k = NIFTI_I2S ; break ; case -3: k = NIFTI_S2I ; break ; default: break; } *icod = i ; *jcod = j ; *kcod = k ; } /*---------------------------------------------------------------------------*/ /*! compute the (closest) orientation from a 4x4 ijk->xyz tranformation matrix
   Input:  4x4 matrix that transforms (i,j,k) indexes to (x,y,z) coordinates,
           where +x=Right, +y=Anterior, +z=Superior.
           (Only the upper-left 3x3 corner of R is used herein.)
   Output: 3 orientation codes that correspond to the closest "standard"
           anatomical orientation of the (i,j,k) axes.
   Method: Find which permutation of (x,y,z) has the smallest angle to the
           (i,j,k) axes directions, which are the columns of the R matrix.
   Errors: The codes returned will be zero.

   For example, an axial volume might get return values of
     *icod = NIFTI_R2L   (i axis is mostly Right to Left)
     *jcod = NIFTI_P2A   (j axis is mostly Posterior to Anterior)
     *kcod = NIFTI_I2S   (k axis is mostly Inferior to Superior)
   
\see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h \see nifti_quatern_to_mat44, nifti_mat44_to_quatern, nifti_make_orthog_mat44 *//*-------------------------------------------------------------------------*/ void nifti_mat44_to_orientation( mat44 R , int *icod, int *jcod, int *kcod ) { float xi,xj,xk , yi,yj,yk , zi,zj,zk , val,detQ,detP ; mat33 P , Q , M ; int i,j,k=0,p,q,r , ibest,jbest,kbest,pbest,qbest,rbest ; float vbest ; if( icod == NULL || jcod == NULL || kcod == NULL ) return ; /* bad */ *icod = *jcod = *kcod = 0 ; /* error returns, if sh*t happens */ /* load column vectors for each (i,j,k) direction from matrix */ /*-- i axis --*/ /*-- j axis --*/ /*-- k axis --*/ xi = R.m[0][0] ; xj = R.m[0][1] ; xk = R.m[0][2] ; yi = R.m[1][0] ; yj = R.m[1][1] ; yk = R.m[1][2] ; zi = R.m[2][0] ; zj = R.m[2][1] ; zk = R.m[2][2] ; /* normalize column vectors to get unit vectors along each ijk-axis */ /* normalize i axis */ val = (float)sqrt( xi*xi + yi*yi + zi*zi ) ; if( val == 0.0 ) return ; /* stupid input */ xi /= val ; yi /= val ; zi /= val ; /* normalize j axis */ val = (float)sqrt( xj*xj + yj*yj + zj*zj ) ; if( val == 0.0 ) return ; /* stupid input */ xj /= val ; yj /= val ; zj /= val ; /* orthogonalize j axis to i axis, if needed */ val = xi*xj + yi*yj + zi*zj ; /* dot product between i and j */ if( fabs(val) > 1.e-4 ){ xj -= val*xi ; yj -= val*yi ; zj -= val*zi ; val = (float)sqrt( xj*xj + yj*yj + zj*zj ) ; /* must renormalize */ if( val == 0.0 ) return ; /* j was parallel to i? */ xj /= val ; yj /= val ; zj /= val ; } /* normalize k axis; if it is zero, make it the cross product i x j */ val = (float)sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ){ xk = yi*zj-zi*yj; yk = zi*xj-zj*xi ; zk=xi*yj-yi*xj ; } else { xk /= val ; yk /= val ; zk /= val ; } /* orthogonalize k to i */ val = xi*xk + yi*yk + zi*zk ; /* dot product between i and k */ if( fabs(val) > 1.e-4 ){ xk -= val*xi ; yk -= val*yi ; zk -= val*zi ; val = (float)sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ) return ; /* bad */ xk /= val ; yk /= val ; zk /= val ; } /* orthogonalize k to j */ val = xj*xk + yj*yk + zj*zk ; /* dot product between j and k */ if( fabs(val) > 1.e-4 ){ xk -= val*xj ; yk -= val*yj ; zk -= val*zj ; val = (float)sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ) return ; /* bad */ xk /= val ; yk /= val ; zk /= val ; } Q.m[0][0] = xi ; Q.m[0][1] = xj ; Q.m[0][2] = xk ; Q.m[1][0] = yi ; Q.m[1][1] = yj ; Q.m[1][2] = yk ; Q.m[2][0] = zi ; Q.m[2][1] = zj ; Q.m[2][2] = zk ; /* at this point, Q is the rotation matrix from the (i,j,k) to (x,y,z) axes */ detQ = nifti_mat33_determ( Q ) ; if( detQ == 0.0 ) return ; /* shouldn't happen unless user is a DUFIS */ /* Build and test all possible +1/-1 coordinate permutation matrices P; then find the P such that the rotation matrix M=PQ is closest to the identity, in the sense of M having the smallest total rotation angle. */ /* Despite the formidable looking 6 nested loops, there are only 3*3*3*2*2*2 = 216 passes, which will run very quickly. */ vbest = -666.0f ; ibest=pbest=qbest=rbest=1 ; jbest=2 ; kbest=3 ; for( i=1 ; i <= 3 ; i++ ){ /* i = column number to use for row #1 */ for( j=1 ; j <= 3 ; j++ ){ /* j = column number to use for row #2 */ if( i == j ) continue ; for( k=1 ; k <= 3 ; k++ ){ /* k = column number to use for row #3 */ if( i == k || j == k ) continue ; P.m[0][0] = P.m[0][1] = P.m[0][2] = P.m[1][0] = P.m[1][1] = P.m[1][2] = P.m[2][0] = P.m[2][1] = P.m[2][2] = 0.0f ; for( p=-1 ; p <= 1 ; p+=2 ){ /* p,q,r are -1 or +1 */ for( q=-1 ; q <= 1 ; q+=2 ){ /* and go into rows #1,2,3 */ for( r=-1 ; r <= 1 ; r+=2 ){ P.m[0][i-1] = p ; P.m[1][j-1] = q ; P.m[2][k-1] = r ; detP = nifti_mat33_determ(P) ; /* sign of permutation */ if( detP * detQ <= 0.0 ) continue ; /* doesn't match sign of Q */ M = nifti_mat33_mul(P,Q) ; /* angle of M rotation = 2.0*acos(0.5*sqrt(1.0+trace(M))) */ /* we want largest trace(M) == smallest angle == M nearest to I */ val = M.m[0][0] + M.m[1][1] + M.m[2][2] ; /* trace */ if( val > vbest ){ vbest = val ; ibest = i ; jbest = j ; kbest = k ; pbest = p ; qbest = q ; rbest = r ; } }}}}}} /* At this point ibest is 1 or 2 or 3; pbest is -1 or +1; etc. The matrix P that corresponds is the best permutation approximation to Q-inverse; that is, P (approximately) takes (x,y,z) coordinates to the (i,j,k) axes. For example, the first row of P (which contains pbest in column ibest) determines the way the i axis points relative to the anatomical (x,y,z) axes. If ibest is 2, then the i axis is along the y axis, which is direction P2A (if pbest > 0) or A2P (if pbest < 0). So, using ibest and pbest, we can assign the output code for the i axis. Mutatis mutandis for the j and k axes, of course. */ switch( ibest*pbest ){ case 1: i = NIFTI_L2R ; break ; case -1: i = NIFTI_R2L ; break ; case 2: i = NIFTI_P2A ; break ; case -2: i = NIFTI_A2P ; break ; case 3: i = NIFTI_I2S ; break ; case -3: i = NIFTI_S2I ; break ; default: break; } switch( jbest*qbest ){ case 1: j = NIFTI_L2R ; break ; case -1: j = NIFTI_R2L ; break ; case 2: j = NIFTI_P2A ; break ; case -2: j = NIFTI_A2P ; break ; case 3: j = NIFTI_I2S ; break ; case -3: j = NIFTI_S2I ; break ; default: break; } switch( kbest*rbest ){ case 1: k = NIFTI_L2R ; break ; case -1: k = NIFTI_R2L ; break ; case 2: k = NIFTI_P2A ; break ; case -2: k = NIFTI_A2P ; break ; case 3: k = NIFTI_I2S ; break ; case -3: k = NIFTI_S2I ; break ; default: break; } *icod = i ; *jcod = j ; *kcod = k ; } /*---------------------------------------------------------------------------*/ /* Routines to swap byte arrays in various ways: - 2 at a time: ab -> ba [short] - 4 at a time: abcd -> dcba [int, float] - 8 at a time: abcdDCBA -> ABCDdcba [long long, double] - 16 at a time: abcdefghHGFEDCBA -> ABCDEFGHhgfedcba [long double] -----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /*! swap each byte pair from the given list of n pairs * * Due to alignment of structures at some architectures (e.g. on ARM), * stick to char varaibles. * Fixes http://bugs.debian.org/446893 Yaroslav * *//*--------------------------------------------------------------------*/ void nifti_swap_2bytes( int64_t n , void *ar ) /* 2 bytes at a time */ { int64_t ii ; unsigned char * cp1 = (unsigned char *)ar, * cp2 ; unsigned char tval; for( ii=0 ; ii < n ; ii++ ){ cp2 = cp1 + 1; tval = *cp1; *cp1 = *cp2; *cp2 = tval; cp1 += 2; } } /*----------------------------------------------------------------------*/ /*! swap 4 bytes at a time from the given list of n sets of 4 bytes *//*--------------------------------------------------------------------*/ void nifti_swap_4bytes( int64_t n , void *ar ) /* 4 bytes at a time */ { int64_t ii ; unsigned char * cp0 = (unsigned char *)ar, * cp1, * cp2 ; unsigned char tval ; for( ii=0 ; ii < n ; ii++ ){ cp1 = cp0; cp2 = cp0+3; tval = *cp1; *cp1 = *cp2; *cp2 = tval; cp1++; cp2--; tval = *cp1; *cp1 = *cp2; *cp2 = tval; cp0 += 4; } } /*----------------------------------------------------------------------*/ /*! swap 8 bytes at a time from the given list of n sets of 8 bytes * * perhaps use this style for the general Nbytes, as Yaroslav suggests *//*--------------------------------------------------------------------*/ void nifti_swap_8bytes( int64_t n , void *ar ) /* 8 bytes at a time */ { int64_t ii ; unsigned char * cp0 = (unsigned char *)ar, * cp1, * cp2 ; unsigned char tval ; for( ii=0 ; ii < n ; ii++ ){ cp1 = cp0; cp2 = cp0+7; while ( cp2 > cp1 ) /* unroll? */ { tval = *cp1 ; *cp1 = *cp2 ; *cp2 = tval ; cp1++; cp2--; } cp0 += 8; } } /*----------------------------------------------------------------------*/ /*! swap 16 bytes at a time from the given list of n sets of 16 bytes *//*--------------------------------------------------------------------*/ void nifti_swap_16bytes( int64_t n , void *ar ) /* 16 bytes at a time */ { int64_t ii ; unsigned char * cp0 = (unsigned char *)ar, * cp1, * cp2 ; unsigned char tval ; for( ii=0 ; ii < n ; ii++ ){ cp1 = cp0; cp2 = cp0+15; while ( cp2 > cp1 ) { tval = *cp1 ; *cp1 = *cp2 ; *cp2 = tval ; cp1++; cp2--; } cp0 += 16; } } #if 0 /* not important: save for version update 6 Jul 2010 [rickr] */ /*----------------------------------------------------------------------*/ /*! generic: swap siz bytes at a time from the given list of n sets *//*--------------------------------------------------------------------*/ void nifti_swap_bytes( int64_t n , int siz , void *ar ) { int64_t ii ; unsigned char * cp0 = (unsigned char *)ar, * cp1, * cp2 ; unsigned char tval ; for( ii=0 ; ii < n ; ii++ ){ cp1 = cp0; cp2 = cp0+(siz-1); while ( cp2 > cp1 ) { tval = *cp1 ; *cp1 = *cp2 ; *cp2 = tval ; cp1++; cp2--; } cp0 += siz; } return ; } #endif /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /*! based on siz, call the appropriate nifti_swap_Nbytes() function *//*--------------------------------------------------------------------*/ void nifti_swap_Nbytes( int64_t n , int siz , void *ar ) /* subsuming case */ { switch( siz ){ case 2: nifti_swap_2bytes ( n , ar ) ; break ; case 4: nifti_swap_4bytes ( n , ar ) ; break ; case 8: nifti_swap_8bytes ( n , ar ) ; break ; case 16: nifti_swap_16bytes( n , ar ) ; break ; default: /* nifti_swap_bytes ( n , siz, ar ) ; */ fprintf(stderr,"** NIfTI: cannot swap in %d byte blocks\n", siz); break ; } } /*-------------------------------------------------------------------------*/ /*! Byte swap NIFTI file header, depending on the version. *//*---------------------------------------------------------------------- */ void swap_nifti_header( void * hdr , int ni_ver ) { if( g_opts.debug > 1 ) fprintf(stderr,"++ swapping NIFTI header via ni_ver %d\n", ni_ver); if ( ni_ver == 0 ) nifti_swap_as_analyze((nifti_analyze75 *)hdr); else if( ni_ver == 1 ) nifti_swap_as_nifti1((nifti_1_header *)hdr); else if( ni_ver == 2 ) nifti_swap_as_nifti2((nifti_2_header *)hdr); else if( ni_ver >= 0 && ni_ver <= 9 ) { fprintf(stderr,"** swap_nifti_header: not ready for version %d\n",ni_ver); } else { fprintf(stderr,"** swap_nifti_header: illegal version %d\n", ni_ver); } } /*-------------------------------------------------------------------------*/ /*! Byte swap NIFTI-2 file header. *//*---------------------------------------------------------------------- */ void nifti_swap_as_nifti2( nifti_2_header * h ) { if ( ! h ) { fprintf(stderr,"** nifti_swap_as_nifti2: NULL pointer\n"); return; } nifti_swap_4bytes(1, &h->sizeof_hdr); nifti_swap_2bytes(1, &h->datatype); nifti_swap_2bytes(1, &h->bitpix); nifti_swap_8bytes(8, h->dim); nifti_swap_8bytes(1, &h->intent_p1); nifti_swap_8bytes(1, &h->intent_p2); nifti_swap_8bytes(1, &h->intent_p3); nifti_swap_8bytes(8, h->pixdim); nifti_swap_8bytes(1, &h->vox_offset); nifti_swap_8bytes(1, &h->scl_slope); nifti_swap_8bytes(1, &h->scl_inter); nifti_swap_8bytes(1, &h->cal_max); nifti_swap_8bytes(1, &h->cal_min); nifti_swap_8bytes(1, &h->slice_duration); nifti_swap_8bytes(1, &h->toffset); nifti_swap_8bytes(1, &h->slice_start); nifti_swap_8bytes(1, &h->slice_end); nifti_swap_4bytes(1, &h->qform_code); nifti_swap_4bytes(1, &h->sform_code); nifti_swap_8bytes(1, &h->quatern_b); nifti_swap_8bytes(1, &h->quatern_c); nifti_swap_8bytes(1, &h->quatern_d); nifti_swap_8bytes(1, &h->qoffset_x); nifti_swap_8bytes(1, &h->qoffset_y); nifti_swap_8bytes(1, &h->qoffset_z); nifti_swap_8bytes(4, h->srow_x); nifti_swap_8bytes(4, h->srow_y); nifti_swap_8bytes(4, h->srow_z); nifti_swap_4bytes(1, &h->slice_code); nifti_swap_4bytes(1, &h->xyzt_units); nifti_swap_4bytes(1, &h->intent_code); } /*-------------------------------------------------------------------------*/ /*! Byte swap NIFTI-1 file header in various places and ways. * return 0 on success *//*---------------------------------------------------------------------- */ void nifti_swap_as_nifti1( nifti_1_header * h ) { if ( ! h ) { fprintf(stderr,"** nifti_swap_as_nifti1: NULL pointer\n"); return; } nifti_swap_4bytes(1, &h->sizeof_hdr); nifti_swap_4bytes(1, &h->extents); nifti_swap_2bytes(1, &h->session_error); nifti_swap_2bytes(8, h->dim); nifti_swap_4bytes(1, &h->intent_p1); nifti_swap_4bytes(1, &h->intent_p2); nifti_swap_4bytes(1, &h->intent_p3); nifti_swap_2bytes(1, &h->intent_code); nifti_swap_2bytes(1, &h->datatype); nifti_swap_2bytes(1, &h->bitpix); nifti_swap_2bytes(1, &h->slice_start); nifti_swap_4bytes(8, h->pixdim); nifti_swap_4bytes(1, &h->vox_offset); nifti_swap_4bytes(1, &h->scl_slope); nifti_swap_4bytes(1, &h->scl_inter); nifti_swap_2bytes(1, &h->slice_end); nifti_swap_4bytes(1, &h->cal_max); nifti_swap_4bytes(1, &h->cal_min); nifti_swap_4bytes(1, &h->slice_duration); nifti_swap_4bytes(1, &h->toffset); nifti_swap_4bytes(1, &h->glmax); nifti_swap_4bytes(1, &h->glmin); nifti_swap_2bytes(1, &h->qform_code); nifti_swap_2bytes(1, &h->sform_code); nifti_swap_4bytes(1, &h->quatern_b); nifti_swap_4bytes(1, &h->quatern_c); nifti_swap_4bytes(1, &h->quatern_d); nifti_swap_4bytes(1, &h->qoffset_x); nifti_swap_4bytes(1, &h->qoffset_y); nifti_swap_4bytes(1, &h->qoffset_z); nifti_swap_4bytes(4, h->srow_x); nifti_swap_4bytes(4, h->srow_y); nifti_swap_4bytes(4, h->srow_z); } /*-------------------------------------------------------------------------*/ /*! Byte swap as an ANALYZE 7.5 header * * return non-zero on failure *//*---------------------------------------------------------------------- */ void nifti_swap_as_analyze( nifti_analyze75 * h ) { if ( ! h ) { fprintf(stderr,"** nifti_swap_as_analyze: NULL pointer\n"); return; } nifti_swap_4bytes(1, &h->sizeof_hdr); nifti_swap_4bytes(1, &h->extents); nifti_swap_2bytes(1, &h->session_error); nifti_swap_2bytes(8, h->dim); nifti_swap_2bytes(1, &h->unused8); nifti_swap_2bytes(1, &h->unused9); nifti_swap_2bytes(1, &h->unused10); nifti_swap_2bytes(1, &h->unused11); nifti_swap_2bytes(1, &h->unused12); nifti_swap_2bytes(1, &h->unused13); nifti_swap_2bytes(1, &h->unused14); nifti_swap_2bytes(1, &h->datatype); nifti_swap_2bytes(1, &h->bitpix); nifti_swap_2bytes(1, &h->dim_un0); nifti_swap_4bytes(8, h->pixdim); nifti_swap_4bytes(1, &h->vox_offset); nifti_swap_4bytes(1, &h->funused1); nifti_swap_4bytes(1, &h->funused2); nifti_swap_4bytes(1, &h->funused3); nifti_swap_4bytes(1, &h->cal_max); nifti_swap_4bytes(1, &h->cal_min); nifti_swap_4bytes(1, &h->compressed); nifti_swap_4bytes(1, &h->verified); nifti_swap_4bytes(1, &h->glmax); nifti_swap_4bytes(1, &h->glmin); nifti_swap_4bytes(1, &h->views); nifti_swap_4bytes(1, &h->vols_added); nifti_swap_4bytes(1, &h->start_field); nifti_swap_4bytes(1, &h->field_skip); nifti_swap_4bytes(1, &h->omax); nifti_swap_4bytes(1, &h->omin); nifti_swap_4bytes(1, &h->smax); nifti_swap_4bytes(1, &h->smin); } /*-------------------------------------------------------------------------*/ /*! OLD VERSION of swap_nifti_header (left for undo/compare operations) Byte swap NIFTI-1 file header in various places and ways. If is_nifti is nonzero, will also swap the NIFTI-specific components of the header; otherwise, only the components common to NIFTI and ANALYZE will be swapped. *//*---------------------------------------------------------------------- */ void old_swap_nifti_header( nifti_1_header *h , int is_nifti ) { /* this stuff is always present, for ANALYZE and NIFTI */ swap_4(h->sizeof_hdr) ; nifti_swap_2bytes( 8 , h->dim ) ; nifti_swap_4bytes( 8 , h->pixdim ) ; swap_2(h->datatype) ; swap_2(h->bitpix) ; swap_4(h->vox_offset); swap_4(h->cal_max); swap_4(h->cal_min); /* this stuff is NIFTI specific */ if( is_nifti ){ swap_4(h->intent_p1); swap_4(h->intent_p2); swap_4(h->intent_p3); swap_2(h->intent_code); swap_2(h->slice_start); swap_2(h->slice_end); swap_4(h->scl_slope); swap_4(h->scl_inter); swap_4(h->slice_duration); swap_4(h->toffset); swap_2(h->qform_code); swap_2(h->sform_code); swap_4(h->quatern_b); swap_4(h->quatern_c); swap_4(h->quatern_d); swap_4(h->qoffset_x); swap_4(h->qoffset_y); swap_4(h->qoffset_z); nifti_swap_4bytes(4,h->srow_x); nifti_swap_4bytes(4,h->srow_y); nifti_swap_4bytes(4,h->srow_z); } } #define USE_STAT #ifdef USE_STAT /*---------------------------------------------------------------------------*/ /* Return the file length (0 if file not found or has no contents). This is a Unix-specific function, since it uses stat(). -----------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------*/ /*! return the size of a file, in bytes \return size of file on success, -1 on error or no file changed to return int, -1 means no file or error 20 Dec 2004 [rickr] *//*-------------------------------------------------------------------------*/ int64_t nifti_get_filesize( const char *pathname ) { struct stat buf ; int ii ; if( pathname == NULL || *pathname == '\0' ) return -1 ; ii = stat( pathname , &buf ); if( ii != 0 ) return -1 ; return buf.st_size ; } #else /*---------- non-Unix version of the above, less efficient -----------*/ int64_t nifti_get_filesize( const char *pathname ) { znzFile fp ; int64_t len ; if( pathname == NULL || *pathname == '\0' ) return -1 ; fp = znzopen(pathname,"rb",0); if( znz_isnull(fp) ) return -1 ; znzseek(fp,0L,SEEK_END) ; len = znztell(fp) ; znzclose(fp) ; return len ; } #endif /* USE_STAT */ /*----------------------------------------------------------------------*/ /*! return the total volume size, in bytes This is computed as nvox * nbyper. *//*--------------------------------------------------------------------*/ int64_t nifti_get_volsize(const nifti_image *nim) { return (int64_t)nim->nbyper * nim->nvox ; /* total bytes */ } /*--------------------------------------------------------------------------*/ /* Support functions for filenames in read and write - allows for gzipped files */ /*----------------------------------------------------------------------*/ /*! simple check for file existence \return 1 on existence, 0 otherwise *//*--------------------------------------------------------------------*/ int nifti_fileexists(const char* fname) { znzFile fp; fp = znzopen( fname , "rb" , nifti_is_gzfile(fname) ) ; if( !znz_isnull(fp) ) { znzclose(fp); return 1; } return 0; /* fp is NULL */ } /*----------------------------------------------------------------------*/ /*! return whether the filename is valid Note: uppercase extensions are now valid. 27 Apr 2009 [rickr] The name is considered valid if the file basename has length greater than zero, AND one of the valid nifti extensions is provided. fname input | return | =============================== "myimage" | 0 | "myimage.tif" | 0 | "myimage.tif.gz" | 0 | "myimage.nii" | 1 | ".nii" | 0 | ".myhiddenimage" | 0 | ".myhiddenimage.nii" | 1 | *//*--------------------------------------------------------------------*/ int nifti_is_complete_filename(const char* fname) { const char * ext; /* check input file(s) for sanity */ if( fname == NULL || *fname == '\0' ){ if ( g_opts.debug > 1 ) fprintf(stderr,"-- empty filename in nifti_validfilename()\n"); return 0; } ext = nifti_find_file_extension(fname); if ( ext == NULL ) { /*Invalid extension given */ if ( g_opts.debug > 0 ) fprintf(stderr,"-- no nifti valid extension for filename '%s'\n", fname); return 0; } if ( ext && ext == fname ) { /* then no filename prefix */ if ( g_opts.debug > 0 ) fprintf(stderr,"-- no prefix for filename '%s'\n", fname); return 0; } return 1; } /*----------------------------------------------------------------------*/ /*! return whether the filename is valid Allow uppercase extensions as valid. 27 Apr 2009 [rickr] Any .gz extension case must match the base extension case. The name is considered valid if its length is positive, excluding any nifti filename extension. fname input | return | result of nifti_makebasename ==================================================================== "myimage" | 1 | "myimage" "myimage.tif" | 1 | "myimage.tif" "myimage.tif.gz" | 1 | "myimage.tif" "myimage.nii" | 1 | "myimage" ".nii" | 0 | ".myhiddenimage" | 1 | ".myhiddenimage" ".myhiddenimage.nii | 1 | ".myhiddenimage" *//*--------------------------------------------------------------------*/ int nifti_validfilename(const char* fname) { const char * ext; /* check input file(s) for sanity */ if( fname == NULL || *fname == '\0' ){ if ( g_opts.debug > 1 ) fprintf(stderr,"-- empty filename in nifti_validfilename()\n"); return 0; } ext = nifti_find_file_extension(fname); if ( ext && ext == fname ) { /* then no filename prefix */ if ( g_opts.debug > 0 ) fprintf(stderr,"-- no prefix for filename '%s'\n", fname); return 0; } return 1; } /*----------------------------------------------------------------------*/ /*! check the end of the filename for a valid nifti extension Valid extensions are currently .nii, .hdr, .img, .nia, or any of them followed by .gz. Note that '.' is part of the extension. Uppercase extensions are also valid, but not mixed case. \return a pointer to the extension substring within the original function input parameter name, or NULL if not found. \caution Note that if the input parameter is is immutabale (i.e. a const char *) then this function performs an implicit casting away of the mutability constraint and the return parameter will appear as a mutable even though it is part of the immuttable string. *//*--------------------------------------------------------------------*/ char * nifti_find_file_extension( const char * name ) { const char * ext; char extcopy[8]; int len; char extnii[8] = ".nii"; /* modifiable, for possible uppercase */ char exthdr[8] = ".hdr"; /* (leave space for .gz) */ char extimg[8] = ".img"; char extnia[8] = ".nia"; char extgz[4] = ".gz"; char * elist[4] = { NULL, NULL, NULL, NULL}; /* stupid compiler... */ elist[0] = extnii; elist[1] = exthdr; elist[2] = extimg; elist[3] = extnia; if ( ! name ) return NULL; len = (int)strlen(name); if ( len < 4 ) return NULL; ext = name + len - 4; /* make manipulation copy, and possibly convert to lowercase */ strcpy(extcopy, ext); if( g_opts.allow_upper_fext ) make_lowercase(extcopy); /* if it look like a basic extension, fail or return it */ if( compare_strlist(extcopy, elist, 4) >= 0 ) { if( is_mixedcase(ext) ) { fprintf(stderr,"** NIFTI: mixed case extension '%s' is not valid\n", ext); return NULL; } else return (char *)ext; /* Cast away the constness of the input parameter */ } #ifdef HAVE_ZLIB if ( len < 7 ) return NULL; ext = name + len - 7; /* make manipulation copy, and possibly convert to lowercase */ strcpy(extcopy, ext); if( g_opts.allow_upper_fext ) make_lowercase(extcopy); /* go after .gz extensions using the modifiable strings */ strcat(elist[0], extgz); strcat(elist[1], extgz); strcat(elist[2], extgz); if( compare_strlist(extcopy, elist, 3) >= 0 ) { if( is_mixedcase(ext) ) { fprintf(stderr,"** NIFTI: mixed case extension '%s' is not valid\n", ext); return NULL; } else return (char *)ext; /* Cast away the constness of the input parameter */ } #endif if( g_opts.debug > 1 ) fprintf(stderr,"** find_file_ext: failed for name '%s'\n", name); return NULL; } /*----------------------------------------------------------------------*/ /*! return whether the filename ends in ".gz" *//*--------------------------------------------------------------------*/ int nifti_is_gzfile(const char* fname) { /* return true if the filename ends with .gz */ if (fname == NULL) { return 0; } #ifdef HAVE_ZLIB { /* just so len doesn't generate compile warning */ int len; len = (int)strlen(fname); if (len < 3) return 0; /* so we don't search before the name */ if (fileext_compare(fname + strlen(fname) - 3,".gz")==0) { return 1; } } #endif return 0; } /*----------------------------------------------------------------------*/ /*! return whether the given library was compiled with HAVE_ZLIB set *//*--------------------------------------------------------------------*/ int nifti_compiled_with_zlib(void) { #ifdef HAVE_ZLIB return 1; #else return 0; #endif } /*----------------------------------------------------------------------*/ /*! duplicate the filename, while clearing any extension This allocates memory for basename which should eventually be freed. *//*--------------------------------------------------------------------*/ char * nifti_makebasename(const char* fname) { char *basename; const char *ext; basename=nifti_strdup(fname); ext = nifti_find_file_extension(basename); if ( ext ) { basename[strlen(basename)-strlen(ext)] = '\0'; /* clear out extension */ } return basename; /* in either case */ } /*----------------------------------------------------------------------*/ /* option accessor functions */ /*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /*! set nifti's global debug level, for status reporting - 0 : quiet, nothing is printed to the terminal, but errors - 1 : normal execution (the default) - 2, 3 : more details *//*--------------------------------------------------------------------*/ void nifti_set_debug_level( int level ) { g_opts.debug = level; } /*----------------------------------------------------------------------*/ /*! set nifti's global skip_blank_ext flag 5 Sep 2006 [rickr] explicitly set to 0 or 1 *//*--------------------------------------------------------------------*/ void nifti_set_skip_blank_ext( int skip ) { g_opts.skip_blank_ext = skip ? 1 : 0; } /*----------------------------------------------------------------------*/ /*! set nifti's global allow_upper_fext flag 28 Apr 2009 [rickr] explicitly set to 0 or 1 *//*--------------------------------------------------------------------*/ void nifti_set_allow_upper_fext( int allow ) { g_opts.allow_upper_fext = allow ? 1 : 0; } /*----------------------------------------------------------------------*/ /*! get nifti's global alter_cifti flag 22 Jul 2015 [rickr] *//*--------------------------------------------------------------------*/ int nifti_get_alter_cifti( void ) { return g_opts.alter_cifti; } /*----------------------------------------------------------------------*/ /*! set nifti's global alter_cifti flag 22 Jul 2015 [rickr] explicitly set to 0 or 1 *//*--------------------------------------------------------------------*/ void nifti_set_alter_cifti( int alter_cifti ) { g_opts.alter_cifti = alter_cifti ? 1 : 0; } /*----------------------------------------------------------------------*/ /*! check current directory for existing header file \return filename of header on success and NULL if no appropriate file could be found If fname has an uppercase extension, check for uppercase files. NB: it allocates memory for hdrname which should be freed when no longer required *//*-------------------------------------------------------------------*/ char * nifti_findhdrname(const char* fname) { char *basename, *hdrname; const char *ext; char elist[2][5] = { ".hdr", ".nii" }; char extzip[4] = ".gz"; int efirst = 1; /* init to .nii extension */ int eisupper = 0; /* init to lowercase extensions */ /**- check input file(s) for sanity */ if( !nifti_validfilename(fname) ) return NULL; basename = nifti_makebasename(fname); if( !basename ) return NULL; /* only on string alloc failure */ /**- return filename if it has a valid extension and exists (except if it is an .img file (and maybe .gz)) */ ext = nifti_find_file_extension(fname); if( ext ) eisupper = is_uppercase(ext); /* do we look for uppercase? */ /* if the file exists and is a valid header name (not .img), return it */ if ( ext && nifti_fileexists(fname) ) { /* allow for uppercase extension */ if ( fileext_n_compare(ext,".img",4) != 0 ){ hdrname = nifti_strdup(fname); free(basename); return hdrname; } else efirst = 0; /* note for below */ } /* So the requested name is a basename, contains .img, or does not exist. */ /* In any case, use basename. */ /**- if .img, look for .hdr, .hdr.gz, .nii, .nii.gz, in that order */ /**- else, look for .nii, .nii.gz, .hdr, .hdr.gz, in that order */ /* if we get more extension choices, this could be a loop */ /* note: efirst is 0 in the case of ".img" */ /* if the user passed an uppercase entension (.IMG), search for uppercase */ if( eisupper ) { make_uppercase(elist[0]); make_uppercase(elist[1]); make_uppercase(extzip); } hdrname = (char *)calloc(sizeof(char),strlen(basename)+8); if( !hdrname ){ fprintf(stderr,"** nifti_findhdrname: failed to alloc hdrname\n"); free(basename); return NULL; } strcpy(hdrname,basename); strcat(hdrname,elist[efirst]); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #ifdef HAVE_ZLIB strcat(hdrname,extzip); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #endif /* okay, try the other possibility */ efirst = 1 - efirst; strcpy(hdrname,basename); strcat(hdrname,elist[efirst]); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #ifdef HAVE_ZLIB strcat(hdrname,extzip); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #endif /**- if nothing has been found, return NULL */ free(basename); free(hdrname); return NULL; } /*------------------------------------------------------------------------*/ /*! check current directory for existing image file \param fname filename to check for \nifti_type nifti_type for dataset - this determines whether to first check for ".nii" or ".img" (since both may exist) \return filename of data/img file on success and NULL if no appropriate file could be found If fname has a valid, uppercase extension, apply all extensions as uppercase. NB: it allocates memory for the image filename, which should be freed when no longer required *//*---------------------------------------------------------------------*/ char * nifti_findimgname(const char* fname , int nifti_type) { /* store all extensions as strings, in case we need to go uppercase */ char *basename, *imgname, elist[2][5] = { ".nii", ".img" }; char extzip[4] = ".gz"; char extnia[5] = ".nia"; const char *ext; int first; /* first extension to use */ /* check input file(s) for sanity */ if( !nifti_validfilename(fname) ) return NULL; basename = nifti_makebasename(fname); imgname = (char *)calloc(sizeof(char),strlen(basename)+8); if( !imgname ){ fprintf(stderr,"** nifti_findimgname: failed to alloc imgname\n"); free(basename); return NULL; } /* if we are looking for uppercase, apply the fact now */ ext = nifti_find_file_extension(fname); if( ext && is_uppercase(ext) ) { make_uppercase(elist[0]); make_uppercase(elist[1]); make_uppercase(extzip); make_uppercase(extnia); } /* only valid extension for ASCII type is .nia, handle first */ if( nifti_type == NIFTI_FTYPE_ASCII ){ strcpy(imgname,basename); strcat(imgname,extnia); if (nifti_fileexists(imgname)) { free(basename); return imgname; } } else { /**- test for .nii and .img (don't assume input type from image type) */ /**- if nifti_type = 1, check for .nii first, else .img first */ /* if we get 3 or more extensions, can make a loop here... */ if (nifti_type == NIFTI_FTYPE_NIFTI1_1) first = 0; /* should match .nii */ else first = 1; /* should match .img */ strcpy(imgname,basename); strcat(imgname,elist[first]); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #ifdef HAVE_ZLIB /* then also check for .gz */ strcat(imgname,extzip); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #endif /* failed to find image file with expected extension, try the other */ strcpy(imgname,basename); strcat(imgname,elist[1-first]); /* can do this with only 2 choices */ if (nifti_fileexists(imgname)) { free(basename); return imgname; } #ifdef HAVE_ZLIB /* then also check for .gz */ strcat(imgname,extzip); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #endif } /**- if nothing has been found, return NULL */ free(basename); free(imgname); return NULL; } /*----------------------------------------------------------------------*/ /*! creates a filename for storing the header, based on nifti_type \param prefix - this will be copied before the suffix is added \param nifti_type - determines the extension, unless one is in prefix \param check - check for existence (fail condition) \param comp - add .gz for compressed name Note that if prefix provides a file suffix, nifti_type is not used. NB: this allocates memory which should be freed \sa nifti_set_filenames *//*-------------------------------------------------------------------*/ char * nifti_makehdrname(const char * prefix, int nifti_type, int check, int comp) { char * iname; const char * ext; char extnii[5] = ".nii"; /* modifiable, for possible uppercase */ char exthdr[5] = ".hdr"; char extimg[5] = ".img"; char extnia[5] = ".nia"; char extgz[5] = ".gz"; if( !nifti_validfilename(prefix) ) return NULL; /* add space for extension, optional ".gz", and null char */ iname = (char *)calloc(sizeof(char),strlen(prefix)+8); if( !iname ){ fprintf(stderr,"** NIFTI small malloc failure!\n"); return NULL; } strcpy(iname, prefix); /* use any valid extension */ if( (ext = nifti_find_file_extension(iname)) != NULL ){ /* if uppercase, convert all extensions */ if( is_uppercase(ext) ) { make_uppercase(extnii); make_uppercase(exthdr); make_uppercase(extimg); make_uppercase(extnia); make_uppercase(extgz); } if( strncmp(ext,extimg,4) == 0 ) { memcpy(&(iname[strlen(iname)-strlen(ext)]),exthdr,4); /* then convert img name to hdr */ } } /* otherwise, make one up */ else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcat(iname, extnii); else if( nifti_type == NIFTI_FTYPE_ASCII ) strcat(iname, extnia); else strcat(iname, exthdr); #ifdef HAVE_ZLIB /* if compression is requested, make sure of suffix */ if( comp && (!ext || !strstr(iname,extgz)) ) strcat(iname,extgz); #endif /* check for existence failure */ if( check && nifti_fileexists(iname) ){ fprintf(stderr,"** failure: NIFTI header file '%s' already exists\n", iname); free(iname); return NULL; } if(g_opts.debug > 2) fprintf(stderr,"+d made header filename '%s'\n", iname); return iname; } /*----------------------------------------------------------------------*/ /*! creates a filename for storing the image, based on nifti_type \param prefix - this will be copied before the suffix is added \param nifti_type - determines the extension, unless provided by prefix \param check - check for existence (fail condition) \param comp - add .gz for compressed name Note that if prefix provides a file suffix, nifti_type is not used. NB: it allocates memory which should be freed \sa nifti_set_filenames *//*-------------------------------------------------------------------*/ char * nifti_makeimgname(const char * prefix, int nifti_type, int check, int comp) { char * iname; const char * ext; char extnii[5] = ".nii"; /* modifiable, for possible uppercase */ char exthdr[5] = ".hdr"; char extimg[5] = ".img"; char extnia[5] = ".nia"; char extgz[5] = ".gz"; if( !nifti_validfilename(prefix) ) return NULL; /* add space for extension, optional ".gz", and null char */ iname = (char *)calloc(sizeof(char),strlen(prefix)+8); if( !iname ){ fprintf(stderr,"** NIFTI: small malloc failure!\n"); return NULL; } strcpy(iname, prefix); /* use any valid extension */ if( (ext = nifti_find_file_extension(iname)) != NULL ){ /* if uppercase, convert all extensions */ if( is_uppercase(ext) ) { make_uppercase(extnii); make_uppercase(exthdr); make_uppercase(extimg); make_uppercase(extnia); make_uppercase(extgz); } if( strncmp(ext,exthdr,4) == 0 ) { memcpy(&(iname[strlen(iname)-strlen(ext)]),extimg,4); /* then convert hdr name to img */ } } /* otherwise, make one up */ else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcat(iname, extnii); else if( nifti_type == NIFTI_FTYPE_ASCII ) strcat(iname, extnia); else strcat(iname, extimg); #ifdef HAVE_ZLIB /* if compression is requested, make sure of suffix */ if( comp && (!ext || !strstr(iname,extgz)) ) strcat(iname,extgz); #endif /* check for existence failure */ if( check && nifti_fileexists(iname) ){ fprintf(stderr,"** NIFTI failure: image file '%s' already exists\n", iname); free(iname); return NULL; } if( g_opts.debug > 2 ) fprintf(stderr,"+d made image filename '%s'\n",iname); return iname; } /*----------------------------------------------------------------------*/ /*! create and set new filenames, based on prefix and image type \param nim pointer to nifti_image in which to set filenames \param prefix (required) prefix for output filenames \param check check for previous existence of filename (existence is an error condition) \param set_byte_order flag to set nim->byteorder here (this is probably a logical place to do so) \return 0 on successful update \warning this will free() any existing names and create new ones \sa nifti_makeimgname, nifti_makehdrname, nifti_type_and_names_match *//*--------------------------------------------------------------------*/ int nifti_set_filenames( nifti_image * nim, const char * prefix, int check, int set_byte_order ) { int comp = nifti_is_gzfile(prefix); if( !nim || !prefix ){ fprintf(stderr,"** nifti_set_filenames, bad params %p, %p\n", (void *)nim,prefix); return -1; } if( g_opts.debug > 1 ) fprintf(stderr,"+d modifying output filenames using prefix %s\n", prefix); /* set and test output filenames */ if( nim->fname ) free(nim->fname); if( nim->iname ) free(nim->iname); nim->iname = NULL; nim->fname = nifti_makehdrname(prefix, nim->nifti_type, check, comp); if( nim->fname ) nim->iname = nifti_makeimgname(prefix, nim->nifti_type, check, comp); if( !nim->fname || !nim->iname ) return -1; /* failure */ if( set_byte_order ) nim->byteorder = nifti_short_order() ; if( nifti_set_type_from_names(nim) < 0 ) return -1; if( g_opts.debug > 2 ) fprintf(stderr,"+d have new filenames %s and %s\n",nim->fname,nim->iname); return 0; } /*--------------------------------------------------------------------------*/ /*! check whether nifti_type matches fname and iname for the nifti_image - if type 0 or 2, expect .hdr/.img pair - if type 1, expect .nii (and names must match) \param nim given nifti_image \param show_warn if set, print a warning message for any mis-match \return - 1 if the values seem to match - 0 if there is a mis-match - -1 if there is not sufficient information to create file(s) \sa NIFTI_FTYPE_* codes in nifti1_io.h \sa nifti_set_type_from_names, is_valid_nifti_type *//*------------------------------------------------------------------------*/ int nifti_type_and_names_match( nifti_image * nim, int show_warn ) { char func[] = "nifti_type_and_names_match"; const char * ext_h; /* header filename extension */ const char * ext_i; /* image filename extension */ int errs = 0; /* error counter */ /* sanity checks */ if( !nim ){ if( show_warn ) fprintf(stderr,"** %s: missing nifti_image\n", func); return -1; } if( !nim->fname ){ if( show_warn ) fprintf(stderr,"** %s: missing header filename\n", func); errs++; } if( !nim->iname ){ if( show_warn ) fprintf(stderr,"** %s: missing image filename\n", func); errs++; } if( !is_valid_nifti_type(nim->nifti_type) ){ if( show_warn ) fprintf(stderr,"** %s: bad nifti_type %d\n", func, nim->nifti_type); errs++; } if( errs ) return -1; /* then do not proceed */ /* get pointers to extensions */ ext_h = nifti_find_file_extension( nim->fname ); ext_i = nifti_find_file_extension( nim->iname ); /* check for filename extensions */ if( !ext_h ){ if( show_warn ) fprintf(stderr,"-d missing NIFTI extension in header filename, %s\n", nim->fname); errs++; } if( !ext_i ){ if( show_warn ) fprintf(stderr,"-d missing NIFTI extension in image filename, %s\n", nim->iname); errs++; } if( errs ) return 0; /* do not proceed, but this is just a mis-match */ /* general tests */ if( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ){ /* .nii */ if( fileext_n_compare(ext_h,".nii",4) ) { if( show_warn ) fprintf(stderr, "-d NIFTI_FTYPE 1, but no .nii extension in header filename, %s\n", nim->fname); errs++; } if( fileext_n_compare(ext_i,".nii",4) ) { if( show_warn ) fprintf(stderr, "-d NIFTI_FTYPE 1, but no .nii extension in image filename, %s\n", nim->iname); errs++; } if( strcmp(nim->fname, nim->iname) != 0 ){ if( show_warn ) fprintf(stderr, "-d NIFTI_FTYPE 1, but header and image filenames differ: %s, %s\n", nim->fname, nim->iname); errs++; } } else if( (nim->nifti_type == NIFTI_FTYPE_NIFTI1_2) || /* .hdr/.img */ (nim->nifti_type == NIFTI_FTYPE_ANALYZE) ) { if( fileext_n_compare(ext_h,".hdr",4) != 0 ){ if( show_warn ) fprintf(stderr,"-d no '.hdr' extension, but NIFTI type is %d, %s\n", nim->nifti_type, nim->fname); errs++; } if( fileext_n_compare(ext_i,".img",4) != 0 ){ if( show_warn ) fprintf(stderr,"-d no '.img' extension, but NIFTI type is %d, %s\n", nim->nifti_type, nim->iname); errs++; } } /* ignore any other nifti_type */ if( errs ) return 0; /* types do not match */ return 1; } /* like strcmp, but also check against capitalization of known_ext * (test as local string, with max length 7) */ static int fileext_compare(const char * test_ext, const char * known_ext) { char caps[8] = ""; size_t c,len; /* if equal, don't need to check case (store to avoid multiple calls) */ const int cmp = strcmp(test_ext, known_ext); if( cmp == 0 ) return cmp; /* if anything odd, use default */ if( !test_ext || !known_ext ) return cmp; len = strlen(known_ext); if( len > 7 ) return cmp; /* if here, strings are different but need to check upper-case */ for(c = 0; c < len; c++ ) caps[c] = toupper((int) known_ext[c]); caps[c] = '\0'; return strcmp(test_ext, caps); } /* like strncmp, but also check against capitalization of known_ext * (test as local string, with max length 7) */ static int fileext_n_compare(const char * test_ext, const char * known_ext, size_t maxlen) { char caps[8] = ""; size_t c,len; /* if equal, don't need to check case (store to avoid multiple calls) */ const int cmp = strncmp(test_ext, known_ext, maxlen); if( cmp == 0 ) return cmp; /* if anything odd, use default */ if( !test_ext || !known_ext ) return cmp; len = strlen(known_ext); if( len > maxlen ) len = maxlen; /* ignore anything past maxlen */ if( len > 7 ) return cmp; /* if here, strings are different but need to check upper-case */ for(c = 0; c < len; c++ ) caps[c] = toupper((int) known_ext[c]); caps[c] = '\0'; return strncmp(test_ext, caps, maxlen); } /* return 1 if there are uppercase but no lowercase */ static int is_uppercase(const char * str) { size_t c; int hasupper = 0; if( !str || !*str ) return 0; for(c = 0; c < strlen(str); c++ ) { if( islower((int) str[c]) ) return 0; if( !hasupper && isupper((int) str[c]) ) hasupper = 1; } return hasupper; } /* return 1 if there are both uppercase and lowercase characters */ static int is_mixedcase(const char * str) { size_t c; int hasupper = 0, haslower = 0; if( !str || !*str ) return 0; for(c = 0; c < strlen(str); c++ ) { if( !haslower && islower((int) str[c]) ) haslower = 1; if( !hasupper && isupper((int) str[c]) ) hasupper = 1; if( haslower && hasupper ) return 1; } return 0; } /* convert any lowercase chars to uppercase */ static int make_uppercase(char * str) { size_t c; if( !str || !*str ) return 0; for(c = 0; c < strlen(str); c++ ) if( islower((int) str[c]) ) str[c] = toupper((int) str[c]); return 0; } /* convert any uppercase chars to lowercase */ static int make_lowercase(char * str) { size_t c; if( !str || !*str ) return 0; for(c = 0; c < strlen(str); c++ ) if( isupper((int) str[c]) ) str[c] = tolower((int) str[c]); return 0; } /* run strcmp against of list of strings * return index of equality, if found * else return -1 */ static int compare_strlist(const char * str, char ** strlist, int len) { int c; if( len <= 0 || !str || !strlist ) return -1; for( c = 0; c < len; c++ ) if( strlist[c] && !strcmp(str, strlist[c]) ) return c; return -1; } /*--------------------------------------------------------------------------*/ /*! check whether the given type is on the "approved" list The code is valid if it is non-negative, and does not exceed NIFTI_MAX_FTYPE. \return 1 if nifti_type is valid, 0 otherwise \sa NIFTI_FTYPE_* codes in nifti1_io.h *//*------------------------------------------------------------------------*/ int is_valid_nifti_type( int nifti_type ) { if( nifti_type >= NIFTI_FTYPE_ANALYZE && /* smallest type, 0 */ nifti_type <= NIFTI_MAX_FTYPE ) return 1; return 0; } /*--------------------------------------------------------------------------*/ /*! check whether the given type is on the "approved" list The type is explicitly checked against the NIFTI_TYPE_* list in nifti1.h. \return 1 if dtype is valid, 0 otherwise \sa NIFTI_TYPE_* codes in nifti1.h *//*------------------------------------------------------------------------*/ int nifti_is_valid_datatype( int dtype ) { if( dtype == NIFTI_TYPE_UINT8 || dtype == NIFTI_TYPE_INT16 || dtype == NIFTI_TYPE_INT32 || dtype == NIFTI_TYPE_FLOAT32 || dtype == NIFTI_TYPE_COMPLEX64 || dtype == NIFTI_TYPE_FLOAT64 || dtype == NIFTI_TYPE_RGB24 || dtype == NIFTI_TYPE_RGBA32 || dtype == NIFTI_TYPE_INT8 || dtype == NIFTI_TYPE_UINT16 || dtype == NIFTI_TYPE_UINT32 || dtype == NIFTI_TYPE_INT64 || dtype == NIFTI_TYPE_UINT64 || dtype == NIFTI_TYPE_FLOAT128 || dtype == NIFTI_TYPE_COMPLEX128 || dtype == NIFTI_TYPE_COMPLEX256 ) return 1; return 0; } /*--------------------------------------------------------------------------*/ /*! set the nifti_type field based on fname and iname Note that nifti_type is changed only when it does not match the filenames. \return 0 on success, -1 on error \sa is_valid_nifti_type, nifti_type_and_names_match *//*------------------------------------------------------------------------*/ int nifti_set_type_from_names( nifti_image * nim ) { /* error checking first */ if( !nim ){ fprintf(stderr,"** NSTFN: no nifti_image\n"); return -1; } if( !nim->fname || !nim->iname ){ fprintf(stderr,"** NIFTI_STFN: NULL filename(s) fname @ %p, iname @ %p\n", nim->fname, nim->iname); return -1; } if( ! nifti_validfilename ( nim->fname ) || ! nifti_validfilename ( nim->iname ) || ! nifti_find_file_extension( nim->fname ) || ! nifti_find_file_extension( nim->iname ) ) { fprintf(stderr,"** NIFTI_STFN: invalid filename(s) " "fname='%s', iname='%s'\n", nim->fname, nim->iname); return -1; } if( g_opts.debug > 2 ) fprintf(stderr,"-d verify nifti_type from filenames: %d",nim->nifti_type); /* type should be NIFTI_FTYPE_ASCII if extension is .nia */ if( (fileext_compare(nifti_find_file_extension(nim->fname),".nia")==0)){ nim->nifti_type = NIFTI_FTYPE_ASCII; } else { /* not too picky here, do what must be done, and then verify */ if( strcmp(nim->fname, nim->iname) == 0 ) /* one file, type 1 */ nim->nifti_type = NIFTI_FTYPE_NIFTI1_1; else if( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ) /* cannot be type 1 */ nim->nifti_type = NIFTI_FTYPE_NIFTI1_2; } if( g_opts.debug > 2 ) fprintf(stderr," -> %d\n",nim->nifti_type); if( g_opts.debug > 1 ) /* warn user about anything strange */ nifti_type_and_names_match(nim, 1); if( is_valid_nifti_type(nim->nifti_type) ) return 0; /* success! */ fprintf(stderr,"** NSTFN: bad nifti_type %d, for '%s' and '%s'\n", nim->nifti_type, nim->fname, nim->iname); return -1; } /*--------------------------------------------------------------------------*/ /*! Determine if this is a NIFTI-formatted file.
   \return  0 if file looks like ANALYZE 7.5 [checks sizeof_hdr field == 348]
            1 if file marked as NIFTI (header+data in 1 file)
            2 if file marked as NIFTI (header+data in 2 files)
           -1 if it can't tell, file doesn't exist, etc.
   
*//*------------------------------------------------------------------------*/ int is_nifti_file( const char *hname ) { nifti_1_header nhdr ; znzFile fp ; int ii ; char *tmpname; /* rcr - update to check for nifti-1 or -2 */ /* bad input name? */ if( !nifti_validfilename(hname) ) return -1 ; /* open file */ tmpname = nifti_findhdrname(hname); if( tmpname == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** NIFTI: no header file found for '%s'\n",hname); return -1; } fp = znzopen( tmpname , "rb" , nifti_is_gzfile(tmpname) ) ; free(tmpname); if (znz_isnull(fp)) return -1 ; /* bad open? */ /* read header, close file */ ii = (int)znzread( &nhdr , 1 , sizeof(nhdr) , fp ) ; znzclose( fp ) ; if( ii < (int) sizeof(nhdr) ) return -1 ; /* bad read? */ /* check for NIFTI-ness */ if( NIFTI_VERSION(nhdr) != 0 ){ return ( NIFTI_ONEFILE(nhdr) ) ? 1 : 2 ; } /* check for ANALYZE-ness (sizeof_hdr field == 348) */ ii = nhdr.sizeof_hdr ; if( ii == (int)sizeof(nhdr) ) return 0 ; /* matches */ /* try byte-swapping header */ swap_4(ii) ; if( ii == (int)sizeof(nhdr) ) return 0 ; /* matches */ return -1 ; /* not good */ } static int print_hex_vals( const char * data, size_t nbytes, FILE * fp ) { size_t c; if ( !data || nbytes < 1 || !fp ) return -1; fputs("0x", fp); for ( c = 0; c < nbytes; c++ ) fprintf(fp, " %02x", data[c]); return 0; } /*----------------------------------------------------------------------*/ /*! display the contents of the nifti_1_header (send to stdout) \param info if non-NULL, print this character string \param hp pointer to nifti_1_header *//*--------------------------------------------------------------------*/ int disp_nifti_1_header( const char * info, const nifti_1_header * hp ) { int c; fputs( "-------------------------------------------------------\n", stdout ); if ( info ) fputs( info, stdout ); if ( !hp ){ fputs(" ** no nifti_1_header to display!\n",stdout); return 1; } fprintf(stdout," nifti_1_header :\n" " sizeof_hdr = %d\n" " data_type[10] = ", hp->sizeof_hdr); print_hex_vals(hp->data_type, 10, stdout); fprintf(stdout, "\n" " db_name[18] = "); print_hex_vals(hp->db_name, 18, stdout); fprintf(stdout, "\n" " extents = %d\n" " session_error = %d\n" " regular = 0x%x\n" " dim_info = 0x%x\n", hp->extents, hp->session_error, hp->regular, hp->dim_info ); fprintf(stdout, " dim[8] ="); for ( c = 0; c < 8; c++ ) fprintf(stdout," %d", hp->dim[c]); fprintf(stdout, "\n" " intent_p1 = %f\n" " intent_p2 = %f\n" " intent_p3 = %f\n" " intent_code = %d\n" " datatype = %d\n" " bitpix = %d\n" " slice_start = %d\n" " pixdim[8] =", hp->intent_p1, hp->intent_p2, hp->intent_p3, hp->intent_code, hp->datatype, hp->bitpix, hp->slice_start); /* break pixdim over 2 lines */ for ( c = 0; c < 4; c++ ) fprintf(stdout," %f", hp->pixdim[c]); fprintf(stdout, "\n "); for ( c = 4; c < 8; c++ ) fprintf(stdout," %f", hp->pixdim[c]); fprintf(stdout, "\n" " vox_offset = %f\n" " scl_slope = %f\n" " scl_inter = %f\n" " slice_end = %d\n" " slice_code = %d\n" " xyzt_units = 0x%x\n" " cal_max = %f\n" " cal_min = %f\n" " slice_duration = %f\n" " toffset = %f\n" " glmax = %d\n" " glmin = %d\n", hp->vox_offset, hp->scl_slope, hp->scl_inter, hp->slice_end, hp->slice_code, hp->xyzt_units, hp->cal_max, hp->cal_min, hp->slice_duration, hp->toffset, hp->glmax, hp->glmin); fprintf(stdout, " descrip = '%.80s'\n" " aux_file = '%.24s'\n" " qform_code = %d\n" " sform_code = %d\n" " quatern_b = %f\n" " quatern_c = %f\n" " quatern_d = %f\n" " qoffset_x = %f\n" " qoffset_y = %f\n" " qoffset_z = %f\n" " srow_x[4] = %f, %f, %f, %f\n" " srow_y[4] = %f, %f, %f, %f\n" " srow_z[4] = %f, %f, %f, %f\n" " intent_name = '%-.16s'\n" " magic = '%-.4s'\n", hp->descrip, hp->aux_file, hp->qform_code, hp->sform_code, hp->quatern_b, hp->quatern_c, hp->quatern_d, hp->qoffset_x, hp->qoffset_y, hp->qoffset_z, hp->srow_x[0], hp->srow_x[1], hp->srow_x[2], hp->srow_x[3], hp->srow_y[0], hp->srow_y[1], hp->srow_y[2], hp->srow_y[3], hp->srow_z[0], hp->srow_z[1], hp->srow_z[2], hp->srow_z[3], hp->intent_name, hp->magic); fputs( "-------------------------------------------------------\n", stdout ); fflush(stdout); return 0; } /*----------------------------------------------------------------------*/ /*! display the contents of the nifti_2_header (send to stdout) \param info if non-NULL, print this character string \param hp pointer to nifti_2_header *//*--------------------------------------------------------------------*/ int disp_nifti_2_header( const char * info, const nifti_2_header * hp ) { FILE * fp = stdout; int c; fputs( "-------------------------------------------------------\n", fp ); if ( info ) fputs( info, fp ); if ( !hp ){ fputs(" ** no nifti_2_header to display!\n",fp); return 1; } /* print fields one by one, makes changing order and copying easier */ fprintf(fp," nifti_2_header :\n"); fprintf(fp," sizeof_hdr = %d\n", hp->sizeof_hdr); fprintf(fp," magic[8] = '%-.4s' + ", hp->magic); print_hex_vals(hp->magic+4, 4, fp); fputc('\n', fp); fprintf(fp," datatype = %d (%s)\n", hp->datatype, nifti_datatype_to_string(hp->datatype)); fprintf(fp," bitpix = %d\n", hp->bitpix); fprintf(fp, " dim[8] ="); for ( c = 0; c < 8; c++ ) fprintf(fp," %" PRId64, hp->dim[c]); fputc('\n', fp); fprintf(fp, " intent_p1 = %lf\n", hp->intent_p1); fprintf(fp, " intent_p2 = %lf\n", hp->intent_p2); fprintf(fp, " intent_p3 = %lf\n", hp->intent_p3); fprintf(fp, " pixdim[8] ="); for ( c = 0; c < 8; c++ ) fprintf(fp," %lf", hp->pixdim[c]); fputc('\n', fp); fprintf(fp, " vox_offset = %" PRId64 "\n", hp->vox_offset); fprintf(fp, " scl_slope = %lf\n", hp->scl_slope); fprintf(fp, " scl_inter = %lf\n", hp->scl_inter); fprintf(fp, " cal_max = %lf\n", hp->cal_max); fprintf(fp, " cal_min = %lf\n", hp->cal_min); fprintf(fp, " slice_duration = %lf\n", hp->slice_duration); fprintf(fp, " toffset = %lf\n", hp->toffset); fprintf(fp, " slice_start = %" PRId64 "\n", hp->slice_start); fprintf(fp, " slice_end = %" PRId64 "\n", hp->slice_end); fprintf(fp, " descrip = '%.80s'\n", hp->descrip); fprintf(fp, " aux_file = '%.24s'\n", hp->aux_file); fprintf(fp, " qform_code = %d\n", hp->qform_code); fprintf(fp, " sform_code = %d\n", hp->sform_code); fprintf(fp, " quatern_b = %lf\n", hp->quatern_b); fprintf(fp, " quatern_c = %lf\n", hp->quatern_c); fprintf(fp, " quatern_d = %lf\n", hp->quatern_d); fprintf(fp, " qoffset_x = %lf\n", hp->qoffset_x); fprintf(fp, " qoffset_y = %lf\n", hp->qoffset_y); fprintf(fp, " qoffset_z = %lf\n", hp->qoffset_z); fprintf(fp, " srow_x[4] = %lf, %lf, %lf, %lf\n", hp->srow_x[0], hp->srow_x[1], hp->srow_x[2], hp->srow_x[3]); fprintf(fp, " srow_y[4] = %lf, %lf, %lf, %lf\n", hp->srow_y[0], hp->srow_y[1], hp->srow_y[2], hp->srow_y[3]); fprintf(fp, " srow_z[4] = %lf, %lf, %lf, %lf\n", hp->srow_z[0], hp->srow_z[1], hp->srow_z[2], hp->srow_z[3]); fprintf(fp, " slice_code = %d\n", hp->slice_code); fprintf(fp, " xyzt_units = %d\n", hp->xyzt_units); fprintf(fp, " intent_code = %d\n", hp->intent_code); fprintf(fp, " intent_name = '%-.16s'\n", hp->intent_name); fprintf(fp, " dim_info = 0x%02x\n",(unsigned char)hp->dim_info); fprintf(fp, " unused_str = 0x "); for ( c = 0; c < 15; c++ ) fprintf(fp," %02x", hp->unused_str[c]); fputc('\n', fp); fputs( "-------------------------------------------------------\n", fp ); fflush(fp); return 0; } #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_convert_n1hdr2nim: %s\n", (msg) ) ; \ return NULL ; } while(0) /*----------------------------------------------------------------------*/ /*! convert a nifti_1_header into a nift1_image \return an allocated nifti_image, or NULL on failure *//*--------------------------------------------------------------------*/ nifti_image* nifti_convert_n1hdr2nim(nifti_1_header nhdr, const char * fname) { int ii , doswap , ioff ; int ni_ver , is_onefile ; nifti_image *nim; nim = (nifti_image *)calloc( 1 , sizeof(nifti_image) ) ; if( !nim ) ERREX("failed to allocate nifti image"); /* be explicit with pointers */ nim->fname = NULL; nim->iname = NULL; nim->data = NULL; /**- check if we must swap bytes */ doswap = need_nhdr_swap(nhdr.dim[0], nhdr.sizeof_hdr); /* swap data flag */ if( doswap < 0 ){ free(nim); if( doswap == -1 ) ERREX("bad dim[0]") ; ERREX("bad sizeof_hdr") ; /* else */ } /**- determine if this is a NIFTI-1 compliant header */ ni_ver = NIFTI_VERSION(nhdr) ; /* * before swapping header, record the Analyze75 orient code */ if(ni_ver == 0) { /**- in analyze75, the orient code is at the same address as * qform_code, but it's just one byte * the qform_code will be zero, at which point you can check * analyze75_orient if you care to. */ unsigned char c = *((char *)(&nhdr.qform_code)); nim->analyze75_orient = (analyze_75_orient_code)c; } if( doswap ) { if ( g_opts.debug > 3 ) disp_nifti_1_header("-d ni1 pre-swap: ", &nhdr); swap_nifti_header( &nhdr , ni_ver ) ; } if ( g_opts.debug > 2 ) disp_nifti_1_header("-d nhdr2nim : ", &nhdr); if( nhdr.datatype == DT_BINARY || nhdr.datatype == DT_UNKNOWN ) { free(nim); ERREX("bad datatype") ; } if( nhdr.dim[1] <= 0 ) { free(nim); ERREX("bad dim[1]") ; } /* fix bad dim[] values in the defined dimension range */ for( ii=2 ; ii <= nhdr.dim[0] ; ii++ ) if( nhdr.dim[ii] <= 0 ) nhdr.dim[ii] = 1 ; /* fix any remaining bad dim[] values, so garbage does not propagate */ /* (only values 0 or 1 seem rational, otherwise set to arbirary 1) */ for( ii=nhdr.dim[0]+1 ; ii <= 7 ; ii++ ) if( nhdr.dim[ii] != 1 && nhdr.dim[ii] != 0) nhdr.dim[ii] = 1 ; #if 0 /* rely on dim[0], do not attempt to modify it 16 Nov 2005 [rickr] */ /**- get number of dimensions (ignoring dim[0] now) */ for( ii=7 ; ii >= 2 ; ii-- ) /* loop backwards until we */ if( nhdr.dim[ii] > 1 ) break ; /* find a dim bigger than 1 */ ndim = ii ; #endif /**- set bad grid spacings to 1.0 */ for( ii=1 ; ii <= nhdr.dim[0] ; ii++ ){ if( nhdr.pixdim[ii] == 0.0 || !IS_GOOD_FLOAT(nhdr.pixdim[ii]) ) nhdr.pixdim[ii] = 1.0f ; } is_onefile = (ni_ver > 0) && NIFTI_ONEFILE(nhdr) ; if( ni_ver ) nim->nifti_type = (is_onefile) ? NIFTI_FTYPE_NIFTI1_1 : NIFTI_FTYPE_NIFTI1_2 ; else nim->nifti_type = NIFTI_FTYPE_ANALYZE ; ii = nifti_short_order() ; if( doswap ) nim->byteorder = REVERSE_ORDER(ii) ; else nim->byteorder = ii ; /**- set dimensions of data array */ nim->ndim = nim->dim[0] = nhdr.dim[0]; nim->nx = nim->dim[1] = nhdr.dim[1]; nim->ny = nim->dim[2] = nhdr.dim[2]; nim->nz = nim->dim[3] = nhdr.dim[3]; nim->nt = nim->dim[4] = nhdr.dim[4]; nim->nu = nim->dim[5] = nhdr.dim[5]; nim->nv = nim->dim[6] = nhdr.dim[6]; nim->nw = nim->dim[7] = nhdr.dim[7]; for( ii=1, nim->nvox=1; ii <= nhdr.dim[0]; ii++ ) nim->nvox *= nhdr.dim[ii]; /**- set the type of data in voxels and how many bytes per voxel */ nim->datatype = nhdr.datatype ; nifti_datatype_sizes( nim->datatype , &(nim->nbyper) , &(nim->swapsize) ) ; if( nim->nbyper == 0 ){ free(nim); ERREX("bad datatype"); } /**- set the grid spacings */ nim->dx = nim->pixdim[1] = nhdr.pixdim[1] ; nim->dy = nim->pixdim[2] = nhdr.pixdim[2] ; nim->dz = nim->pixdim[3] = nhdr.pixdim[3] ; nim->dt = nim->pixdim[4] = nhdr.pixdim[4] ; nim->du = nim->pixdim[5] = nhdr.pixdim[5] ; nim->dv = nim->pixdim[6] = nhdr.pixdim[6] ; nim->dw = nim->pixdim[7] = nhdr.pixdim[7] ; /**- compute qto_xyz transformation from pixel indexes (i,j,k) to (x,y,z) */ if( !ni_ver || nhdr.qform_code <= 0 ){ /**- if not nifti or qform_code <= 0, use grid spacing for qto_xyz */ nim->qto_xyz.m[0][0] = nim->dx ; /* grid spacings */ nim->qto_xyz.m[1][1] = nim->dy ; /* along diagonal */ nim->qto_xyz.m[2][2] = nim->dz ; /* off diagonal is zero */ nim->qto_xyz.m[0][1]=nim->qto_xyz.m[0][2]=nim->qto_xyz.m[0][3] = 0.0f; nim->qto_xyz.m[1][0]=nim->qto_xyz.m[1][2]=nim->qto_xyz.m[1][3] = 0.0f; nim->qto_xyz.m[2][0]=nim->qto_xyz.m[2][1]=nim->qto_xyz.m[2][3] = 0.0f; /* last row is always [ 0 0 0 1 ] */ nim->qto_xyz.m[3][0]=nim->qto_xyz.m[3][1]=nim->qto_xyz.m[3][2] = 0.0f; nim->qto_xyz.m[3][3]= 1.0f ; nim->qform_code = NIFTI_XFORM_UNKNOWN ; if( g_opts.debug > 1 ) fprintf(stderr,"-d no qform provided\n"); } else { /**- else NIFTI: use the quaternion-specified transformation */ nim->quatern_b = FIXED_FLOAT( nhdr.quatern_b ) ; nim->quatern_c = FIXED_FLOAT( nhdr.quatern_c ) ; nim->quatern_d = FIXED_FLOAT( nhdr.quatern_d ) ; nim->qoffset_x = FIXED_FLOAT(nhdr.qoffset_x) ; nim->qoffset_y = FIXED_FLOAT(nhdr.qoffset_y) ; nim->qoffset_z = FIXED_FLOAT(nhdr.qoffset_z) ; nim->qfac = (nhdr.pixdim[0] < 0.0) ? -1.0f : 1.0f ; /* left-handedness? */ nim->qto_xyz = nifti_quatern_to_dmat44( nim->quatern_b, nim->quatern_c, nim->quatern_d, nim->qoffset_x, nim->qoffset_y, nim->qoffset_z, nim->dx , nim->dy , nim->dz , nim->qfac ) ; nim->qform_code = nhdr.qform_code ; if( g_opts.debug > 1 ) nifti_disp_matrix_orient("-d qform orientations:\n", nim->qto_xyz); } /**- load inverse transformation (x,y,z) -> (i,j,k) */ nim->qto_ijk = nifti_dmat44_inverse( nim->qto_xyz ) ; /**- load sto_xyz affine transformation, if present */ if( !ni_ver || nhdr.sform_code <= 0 ){ /**- if not nifti or sform_code <= 0, then no sto transformation */ nim->sform_code = NIFTI_XFORM_UNKNOWN ; if( g_opts.debug > 1 ) fprintf(stderr,"-d no sform provided\n"); } else { /**- else set the sto transformation from srow_*[] */ nim->sto_xyz.m[0][0] = nhdr.srow_x[0] ; nim->sto_xyz.m[0][1] = nhdr.srow_x[1] ; nim->sto_xyz.m[0][2] = nhdr.srow_x[2] ; nim->sto_xyz.m[0][3] = nhdr.srow_x[3] ; nim->sto_xyz.m[1][0] = nhdr.srow_y[0] ; nim->sto_xyz.m[1][1] = nhdr.srow_y[1] ; nim->sto_xyz.m[1][2] = nhdr.srow_y[2] ; nim->sto_xyz.m[1][3] = nhdr.srow_y[3] ; nim->sto_xyz.m[2][0] = nhdr.srow_z[0] ; nim->sto_xyz.m[2][1] = nhdr.srow_z[1] ; nim->sto_xyz.m[2][2] = nhdr.srow_z[2] ; nim->sto_xyz.m[2][3] = nhdr.srow_z[3] ; /* last row is always [ 0 0 0 1 ] */ nim->sto_xyz.m[3][0]=nim->sto_xyz.m[3][1]=nim->sto_xyz.m[3][2] = 0.0f; nim->sto_xyz.m[3][3]= 1.0f ; nim->sto_ijk = nifti_dmat44_inverse( nim->sto_xyz ) ; nim->sform_code = nhdr.sform_code ; if( g_opts.debug > 1 ) nifti_disp_matrix_orient("-d sform orientations:\n", nim->sto_xyz); } /**- set miscellaneous NIFTI stuff */ if( ni_ver ){ nim->scl_slope = FIXED_FLOAT( nhdr.scl_slope ) ; nim->scl_inter = FIXED_FLOAT( nhdr.scl_inter ) ; nim->intent_code = nhdr.intent_code ; nim->intent_p1 = FIXED_FLOAT( nhdr.intent_p1 ) ; nim->intent_p2 = FIXED_FLOAT( nhdr.intent_p2 ) ; nim->intent_p3 = FIXED_FLOAT( nhdr.intent_p3 ) ; nim->toffset = FIXED_FLOAT( nhdr.toffset ) ; memcpy(nim->intent_name,nhdr.intent_name,15); nim->intent_name[15] = '\0'; nim->xyz_units = XYZT_TO_SPACE(nhdr.xyzt_units) ; nim->time_units = XYZT_TO_TIME (nhdr.xyzt_units) ; nim->freq_dim = DIM_INFO_TO_FREQ_DIM ( nhdr.dim_info ) ; nim->phase_dim = DIM_INFO_TO_PHASE_DIM( nhdr.dim_info ) ; nim->slice_dim = DIM_INFO_TO_SLICE_DIM( nhdr.dim_info ) ; nim->slice_code = nhdr.slice_code ; nim->slice_start = nhdr.slice_start ; nim->slice_end = nhdr.slice_end ; nim->slice_duration = FIXED_FLOAT(nhdr.slice_duration) ; } /**- set Miscellaneous ANALYZE stuff */ nim->cal_min = FIXED_FLOAT(nhdr.cal_min) ; nim->cal_max = FIXED_FLOAT(nhdr.cal_max) ; memcpy(nim->descrip ,nhdr.descrip ,79) ; nim->descrip [79] = '\0' ; memcpy(nim->aux_file,nhdr.aux_file,23) ; nim->aux_file[23] = '\0' ; /**- set ioff from vox_offset (but at least sizeof(header)) */ is_onefile = ni_ver && NIFTI_ONEFILE(nhdr) ; if( is_onefile ){ ioff = (int)nhdr.vox_offset ; if( ioff < (int) sizeof(nhdr) ) ioff = (int) sizeof(nhdr) ; } else { ioff = (int)nhdr.vox_offset ; } nim->iname_offset = ioff ; /**- deal with file names if set */ if (fname!=NULL) { nifti_set_filenames(nim,fname,0,0); if (nim->iname==NULL) { ERREX("bad filename"); } } else { nim->fname = NULL; nim->iname = NULL; } /* clear extension fields */ nim->num_ext = 0; nim->ext_list = NULL; return nim; } #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_convert_n2hdr2nim: %s\n", (msg) ) ; \ return NULL ; } while(0) /*----------------------------------------------------------------------*/ /*! convert a nifti_2_header into a nifti_image \return an allocated nifti_image, or NULL on failure *//*--------------------------------------------------------------------*/ nifti_image* nifti_convert_n2hdr2nim(nifti_2_header nhdr, const char * fname) { int ii, doswap, ni_ver, is_onefile; nifti_image *nim; nim = (nifti_image *)calloc( 1 , sizeof(nifti_image) ) ; if( !nim ) ERREX("failed to allocate nifti image"); /* be explicit with pointers */ nim->fname = NULL; nim->iname = NULL; nim->data = NULL; /**- check if we must swap bytes */ doswap = NIFTI2_NEEDS_SWAP(nhdr); /* swap data flag */ /**- determine if this is a NIFTI-2 compliant header */ ni_ver = NIFTI_VERSION(nhdr) ; if(ni_ver != 2) { free(nim); fprintf(stderr,"** convert NIFTI-2 hdr2nim: bad version %d\n", ni_ver); return NULL; } if( doswap ) { if ( g_opts.debug > 3 ) disp_nifti_2_header("-d n2 pre-swap: ", &nhdr); swap_nifti_header( &nhdr , ni_ver ) ; } else if ( g_opts.debug > 3 ) fprintf(stderr,"-- n2hdr2nim: no swap\n"); if ( g_opts.debug > 2 ) disp_nifti_2_header("-d n2hdr2nim : ", &nhdr); if( nhdr.datatype == DT_BINARY || nhdr.datatype == DT_UNKNOWN ) { free(nim); ERREX("bad datatype") ; } if( nhdr.dim[1] <= 0 ) { free(nim); ERREX("bad dim[1]") ; } /* fix bad dim[] values in the defined dimension range */ for( ii=2 ; ii <= nhdr.dim[0] ; ii++ ) if( nhdr.dim[ii] <= 0 ) nhdr.dim[ii] = 1 ; /* fix any remaining bad dim[] values, so garbage does not propagate */ /* (only values 0 or 1 seem rational, otherwise set to arbirary 1) */ for( ii=nhdr.dim[0]+1 ; ii <= 7 ; ii++ ) if( nhdr.dim[ii] != 1 && nhdr.dim[ii] != 0) nhdr.dim[ii] = 1 ; /**- set bad grid spacings to 1.0 */ for( ii=1 ; ii <= nhdr.dim[0] ; ii++ ){ if( nhdr.pixdim[ii] == 0.0 || !IS_GOOD_FLOAT(nhdr.pixdim[ii]) ) nhdr.pixdim[ii] = 1.0 ; } is_onefile = (ni_ver > 0) && NIFTI_ONEFILE(nhdr) ; nim->nifti_type = (is_onefile) ? NIFTI_FTYPE_NIFTI1_1 : NIFTI_FTYPE_NIFTI1_2; ii = nifti_short_order() ; if( doswap ) nim->byteorder = REVERSE_ORDER(ii) ; else nim->byteorder = ii ; /**- set dimensions of data array */ nim->ndim = nim->dim[0] = nhdr.dim[0]; nim->nx = nim->dim[1] = nhdr.dim[1]; nim->ny = nim->dim[2] = nhdr.dim[2]; nim->nz = nim->dim[3] = nhdr.dim[3]; nim->nt = nim->dim[4] = nhdr.dim[4]; nim->nu = nim->dim[5] = nhdr.dim[5]; nim->nv = nim->dim[6] = nhdr.dim[6]; nim->nw = nim->dim[7] = nhdr.dim[7]; for( ii=1, nim->nvox=1; ii <= nhdr.dim[0]; ii++ ) nim->nvox *= nhdr.dim[ii]; /**- set the type of data in voxels and how many bytes per voxel */ nim->datatype = nhdr.datatype ; nifti_datatype_sizes( nim->datatype , &(nim->nbyper) , &(nim->swapsize) ) ; if( nim->nbyper == 0 ){ free(nim); ERREX("bad datatype"); } /**- set the grid spacings */ nim->dx = nim->pixdim[1] = nhdr.pixdim[1] ; nim->dy = nim->pixdim[2] = nhdr.pixdim[2] ; nim->dz = nim->pixdim[3] = nhdr.pixdim[3] ; nim->dt = nim->pixdim[4] = nhdr.pixdim[4] ; nim->du = nim->pixdim[5] = nhdr.pixdim[5] ; nim->dv = nim->pixdim[6] = nhdr.pixdim[6] ; nim->dw = nim->pixdim[7] = nhdr.pixdim[7] ; /**- compute qto_xyz transformation from pixel indexes (i,j,k) to (x,y,z) */ if( !ni_ver || nhdr.qform_code <= 0 ){ /**- if not nifti or qform_code <= 0, use grid spacing for qto_xyz */ nim->qto_xyz.m[0][0] = nim->dx ; /* grid spacings */ nim->qto_xyz.m[1][1] = nim->dy ; /* along diagonal */ nim->qto_xyz.m[2][2] = nim->dz ; /* off diagonal is zero */ nim->qto_xyz.m[0][1]=nim->qto_xyz.m[0][2]=nim->qto_xyz.m[0][3] = 0.0f; nim->qto_xyz.m[1][0]=nim->qto_xyz.m[1][2]=nim->qto_xyz.m[1][3] = 0.0f; nim->qto_xyz.m[2][0]=nim->qto_xyz.m[2][1]=nim->qto_xyz.m[2][3] = 0.0f; /* last row is always [ 0 0 0 1 ] */ nim->qto_xyz.m[3][0]=nim->qto_xyz.m[3][1]=nim->qto_xyz.m[3][2] = 0.0f; nim->qto_xyz.m[3][3]= 1.0f ; nim->qform_code = NIFTI_XFORM_UNKNOWN ; if( g_opts.debug > 1 ) fprintf(stderr,"-d no qform provided\n"); } else { /**- else NIFTI: use the quaternion-specified transformation */ nim->quatern_b = FIXED_FLOAT( nhdr.quatern_b ) ; nim->quatern_c = FIXED_FLOAT( nhdr.quatern_c ) ; nim->quatern_d = FIXED_FLOAT( nhdr.quatern_d ) ; nim->qoffset_x = FIXED_FLOAT(nhdr.qoffset_x) ; nim->qoffset_y = FIXED_FLOAT(nhdr.qoffset_y) ; nim->qoffset_z = FIXED_FLOAT(nhdr.qoffset_z) ; nim->qfac = (nhdr.pixdim[0] < 0.0) ? -1.0 : 1.0 ; /* left-handedness? */ nim->qto_xyz = nifti_quatern_to_dmat44( nim->quatern_b, nim->quatern_c, nim->quatern_d, nim->qoffset_x, nim->qoffset_y, nim->qoffset_z, nim->dx , nim->dy , nim->dz , nim->qfac ) ; nim->qform_code = nhdr.qform_code ; if( g_opts.debug > 1 ) nifti_disp_matrix_orient("-d qform orientations:\n", nim->qto_xyz); } /**- load inverse transformation (x,y,z) -> (i,j,k) */ nim->qto_ijk = nifti_dmat44_inverse( nim->qto_xyz ) ; /**- load sto_xyz affine transformation, if present */ if( !ni_ver || nhdr.sform_code <= 0 ){ /**- if not nifti or sform_code <= 0, then no sto transformation */ nim->sform_code = NIFTI_XFORM_UNKNOWN ; if( g_opts.debug > 1 ) fprintf(stderr,"-d no sform provided\n"); } else { /**- else set the sto transformation from srow_*[] */ nim->sto_xyz.m[0][0] = nhdr.srow_x[0] ; nim->sto_xyz.m[0][1] = nhdr.srow_x[1] ; nim->sto_xyz.m[0][2] = nhdr.srow_x[2] ; nim->sto_xyz.m[0][3] = nhdr.srow_x[3] ; nim->sto_xyz.m[1][0] = nhdr.srow_y[0] ; nim->sto_xyz.m[1][1] = nhdr.srow_y[1] ; nim->sto_xyz.m[1][2] = nhdr.srow_y[2] ; nim->sto_xyz.m[1][3] = nhdr.srow_y[3] ; nim->sto_xyz.m[2][0] = nhdr.srow_z[0] ; nim->sto_xyz.m[2][1] = nhdr.srow_z[1] ; nim->sto_xyz.m[2][2] = nhdr.srow_z[2] ; nim->sto_xyz.m[2][3] = nhdr.srow_z[3] ; /* last row is always [ 0 0 0 1 ] */ nim->sto_xyz.m[3][0]=nim->sto_xyz.m[3][1]=nim->sto_xyz.m[3][2] = 0.0f; nim->sto_xyz.m[3][3]= 1.0f ; nim->sto_ijk = nifti_dmat44_inverse( nim->sto_xyz ) ; nim->sform_code = nhdr.sform_code ; if( g_opts.debug > 1 ) nifti_disp_matrix_orient("-d sform orientations:\n", nim->sto_xyz); } /**- set miscellaneous NIFTI stuff */ if( ni_ver ){ nim->scl_slope = FIXED_FLOAT( nhdr.scl_slope ) ; nim->scl_inter = FIXED_FLOAT( nhdr.scl_inter ) ; nim->intent_code = nhdr.intent_code ; nim->intent_p1 = FIXED_FLOAT( nhdr.intent_p1 ) ; nim->intent_p2 = FIXED_FLOAT( nhdr.intent_p2 ) ; nim->intent_p3 = FIXED_FLOAT( nhdr.intent_p3 ) ; nim->toffset = FIXED_FLOAT( nhdr.toffset ) ; memcpy(nim->intent_name,nhdr.intent_name,15); nim->intent_name[15] = '\0'; nim->xyz_units = XYZT_TO_SPACE(nhdr.xyzt_units) ; nim->time_units = XYZT_TO_TIME (nhdr.xyzt_units) ; nim->freq_dim = DIM_INFO_TO_FREQ_DIM ( nhdr.dim_info ) ; nim->phase_dim = DIM_INFO_TO_PHASE_DIM( nhdr.dim_info ) ; nim->slice_dim = DIM_INFO_TO_SLICE_DIM( nhdr.dim_info ) ; nim->slice_code = nhdr.slice_code ; nim->slice_start = nhdr.slice_start ; nim->slice_end = nhdr.slice_end ; nim->slice_duration = FIXED_FLOAT(nhdr.slice_duration) ; } /**- set Miscellaneous ANALYZE stuff */ nim->cal_min = FIXED_FLOAT(nhdr.cal_min) ; nim->cal_max = FIXED_FLOAT(nhdr.cal_max) ; memcpy(nim->descrip ,nhdr.descrip ,79) ; nim->descrip [79] = '\0' ; memcpy(nim->aux_file,nhdr.aux_file,23) ; nim->aux_file[23] = '\0' ; /**- set ioff from vox_offset (but at least sizeof(header)) */ nim->iname_offset = nhdr.vox_offset; if( is_onefile && nhdr.vox_offset < (int64_t)sizeof(nhdr) ) nim->iname_offset = (int64_t)sizeof(nhdr); /**- deal with file names if set */ if (fname!=NULL) { nifti_set_filenames(nim,fname,0,0); if (nim->iname==NULL) { ERREX("bad filename"); } } else { nim->fname = NULL; nim->iname = NULL; } /* clear extension fields */ nim->num_ext = 0; nim->ext_list = NULL; return nim; } #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_image_open(%s): %s\n", \ (hname != NULL) ? hname : "(null)" , (msg) ) ; \ return fptr ; } while(0) /*************************************************************** * nifti_image_open ***************************************************************/ /*! znzFile nifti_image_open( char *hname, char *opts , nifti_image **nim) \brief Read in NIFTI-1 or ANALYZE-7.5 file (pair) header information into a nifti_image struct. - The image data is not read from disk (it may be read later using nifti_image_load(), for example). - The image data will be stored in whatever data format the input data is; no scaling will be applied. - DT_BINARY data is not supported. - nifti_image_free() can be used to delete the returned struct, when you are done with it. \param hname filename of dataset .hdr or .nii file \param opts options string for opening the header file \param nim pointer to pointer to nifti_image struct (this routine allocates the nifti_image struct) \return file pointer (gzippable) to the file with the image data, ready for reading.
NULL if something fails badly. \sa nifti_image_load, nifti_image_free */ znzFile nifti_image_open(const char * hname, char * opts, nifti_image ** nim) { znzFile fptr=NULL; /* open the hdr and reading it in, but do not load the data */ *nim = nifti_image_read(hname,0); /* open the image file, ready for reading (compressed works for all reads) */ if( ((*nim) == NULL) || ((*nim)->iname == NULL) || ((*nim)->nbyper <= 0) || ((*nim)->nvox <= 0) ) ERREX("bad header info") ; /* open image data file */ fptr = znzopen( (*nim)->iname, opts, nifti_is_gzfile((*nim)->iname) ); if( znz_isnull(fptr) ) ERREX("Can't open data file") ; return fptr; } /*----------------------------------------------------------------------*/ /*! return an allocated and filled nifti_1_header struct Read the binary header from disk, and swap bytes if necessary. \return an allocated nifti_1_header struct, or NULL on failure \param hname name of file containing header \param swapped if not NULL, return whether header bytes were swapped \param check flag to check for invalid nifti_1_header \warning ASCII header type is not supported \sa nifti_image_read, nifti_image_free, nifti_image_read_bricks *//*--------------------------------------------------------------------*/ nifti_1_header * nifti_read_n1_hdr(const char * hname, int *swapped, int check) { nifti_1_header nhdr, * hptr; znzFile fp; int bytes, lswap; char * hfile; char fname[] = { "nifti_read_n1_hdr" }; /* determine file name to use for header */ hfile = nifti_findhdrname(hname); if( hfile == NULL ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to find header file for", hname); return NULL; } else if( g_opts.debug > 1 ) fprintf(stderr,"-d %s: found header filename '%s'\n",fname,hfile); fp = znzopen( hfile, "rb", nifti_is_gzfile(hfile) ); if( znz_isnull(fp) ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open header file",hfile); free(hfile); return NULL; } free(hfile); /* done with filename */ if( has_ascii_header(fp) == 1 ){ znzclose( fp ); if( g_opts.debug > 0 ) LNI_FERR(fname,"ASCII header type not supported",hname); return NULL; } /* read the binary header */ bytes = (int)znzread( &nhdr, 1, sizeof(nhdr), fp ); znzclose( fp ); /* we are done with the file now */ if( bytes < (int)sizeof(nhdr) ){ if( g_opts.debug > 0 ){ LNI_FERR(fname,"bad binary header read for file", hname); fprintf(stderr," - read %d of %d bytes\n",bytes, (int)sizeof(nhdr)); } return NULL; } /* now just decide on byte swapping */ lswap = need_nhdr_swap(nhdr.dim[0], nhdr.sizeof_hdr); /* swap data flag */ if( check && lswap < 0 ){ LNI_FERR(fname,"bad nifti_1_header for file", hname); return NULL; } else if ( lswap < 0 ) { lswap = 0; /* if swapping does not help, don't do it */ if(g_opts.debug > 1) fprintf(stderr,"-- swap failure, none applied\n"); } if( lswap ) { if ( g_opts.debug > 3 ) disp_nifti_1_header("-d nhdr pre-swap: ", &nhdr); swap_nifti_header( &nhdr , NIFTI_VERSION(nhdr) ) ; } if ( g_opts.debug > 2 ) disp_nifti_1_header("-d nhdr post-swap: ", &nhdr); if ( check && ! nifti_hdr1_looks_good(&nhdr) ){ LNI_FERR(fname,"nifti_1_header looks bad for file", hname); return NULL; } /* all looks good, so allocate memory for and return the header */ hptr = (nifti_1_header *)malloc(sizeof(nifti_1_header)); if( ! hptr ){ fprintf(stderr,"** nifti_read_hdr: failed to alloc nifti_1_header\n"); return NULL; } if( swapped ) *swapped = lswap; /* only if they care */ memcpy(hptr, &nhdr, sizeof(nifti_1_header)); return hptr; } /*----------------------------------------------------------------------*/ /*! return an allocated and filled nifti_2_header struct Read the binary header from disk, and swap bytes if necessary. \return an allocated nifti_2_header struct, or NULL on failure \param hname name of file containing header \param swapped if not NULL, return whether header bytes were swapped \param check flag to check for invalid nifti_2_header \warning ASCII header type is not supported allow now, convert nim 2 hdr [02 Jan 2019 rickr] \sa nifti_read_header, nifti_read_n1_hdr, nifti_image_read, nifti_image_read_bricks *//*--------------------------------------------------------------------*/ nifti_2_header * nifti_read_n2_hdr(const char * hname, int * swapped, int check) { nifti_2_header nhdr, * hptr; nifti_image * nim=NULL; znzFile fp; int bytes, lswap, rv; char * hfile; char fname[] = { "nifti_read_n2_hdr" }; /* determine file name to use for header */ hfile = nifti_findhdrname(hname); if( hfile == NULL ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to find header file for", hname); return NULL; } else if( g_opts.debug > 1 ) fprintf(stderr,"-d %s: found N2 header filename '%s'\n",fname,hfile); fp = znzopen( hfile, "rb", nifti_is_gzfile(hfile) ); if( znz_isnull(fp) ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open N2 header file",hfile); free(hfile); return NULL; } free(hfile); /* done with filename */ /* ASCII is not part of standard, but allow */ if( has_ascii_header(fp) == 1 ){ if( g_opts.debug > 1 ) fprintf(stderr,"++ reading ASCII header via NIFTI-2 in %s\n", hname); nim = nifti_read_ascii_image(fp, hname, -1, 0); znzclose(fp) ; if( ! nim ) return NULL; hptr = (nifti_2_header *)malloc(sizeof(nifti_2_header)); rv = nifti_convert_nim2n2hdr(nim, hptr); free(nim); if( rv ) { free(hptr); return NULL; } return hptr; } /* read the binary header */ bytes = (int)znzread( &nhdr, 1, sizeof(nhdr), fp ); znzclose( fp ); /* we are done with the file now */ if( bytes < (int)sizeof(nhdr) ){ if( g_opts.debug > 0 ){ LNI_FERR(fname,"bad binary header read for N2 file", hname); fprintf(stderr," - read %d of %d bytes\n",bytes, (int)sizeof(nhdr)); } return NULL; } /* now just decide on byte swapping */ lswap = NIFTI2_NEEDS_SWAP(nhdr); if( lswap ) { if ( g_opts.debug > 3 ) disp_nifti_2_header("-d n2hdr pre-swap: ", &nhdr); swap_nifti_header( &nhdr , 2 ); /* use explicit version */ } if ( g_opts.debug > 2 ) disp_nifti_2_header("-d nhdr post-swap: ", &nhdr); if ( check && ! nifti_hdr2_looks_good(&nhdr) ){ LNI_FERR(fname,"nifti_2_header looks bad for file", hname); return NULL; } /* all looks good, so allocate memory for and return the header */ hptr = (nifti_2_header *)malloc(sizeof(nifti_2_header)); if( ! hptr ){ fprintf(stderr,"** nifti2_read_hdr: failed to alloc nifti_2_header\n"); return NULL; } if( swapped ) *swapped = lswap; /* only if they care */ memcpy(hptr, &nhdr, sizeof(nifti_2_header)); return hptr; } /*----------------------------------------------------------------------*/ /*! decide if this nifti_1_header structure looks reasonable Check dim[0], dim[1], sizeof_hdr, and datatype. Check magic string for "n+1". Maybe more tests will follow. \return 1 if the header seems valid, 0 otherwise \sa nifti_nim_is_valid, valid_nifti_extensions *//*--------------------------------------------------------------------*/ int nifti_hdr1_looks_good(const nifti_1_header * hdr) { int ni_ver, c, errs = 0; /* check dim[0] and sizeof_hdr */ if( need_nhdr_swap(hdr->dim[0], hdr->sizeof_hdr) < 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"** NIFTI: bad hdr1 fields: dim0, sizeof_hdr = %d, %d\n", hdr->dim[0], hdr->sizeof_hdr); errs++; } /* check the valid dimension sizes (maybe dim[0] is bad) */ for( c = 1; c <= hdr->dim[0] && c <= 7; c++ ) if( hdr->dim[c] <= 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"** NIFTI: bad nhdr field: dim[%d] = %d\n", c,hdr->dim[c]); errs++; } ni_ver = NIFTI_VERSION(*hdr); /* determine header type */ if( ni_ver > 0 ){ /* NIFTI */ if( ! nifti_datatype_is_valid(hdr->datatype, 1) ){ if( g_opts.debug > 0 ) fprintf(stderr,"** bad NIFTI datatype in hdr, %d\n",hdr->datatype); errs++; } } else { /* ANALYZE 7.5 */ if( g_opts.debug > 1 ) { /* maybe tell user it's an ANALYZE hdr */ fprintf(stderr, "-- nhdr magic field implies ANALYZE: magic = '%.4s' : ",hdr->magic); print_hex_vals(hdr->magic, 4, stderr); fputc('\n', stderr); } if( ! nifti_datatype_is_valid(hdr->datatype, 0) ){ if( g_opts.debug > 0 ) fprintf(stderr,"** NIFTI: bad ANALYZE datatype in hdr, %d\n", hdr->datatype); errs++; } } if( errs ) return 0; /* problems */ if( g_opts.debug > 2 ) fprintf(stderr,"-d nifti header looks good\n"); return 1; /* looks good */ } /*----------------------------------------------------------------------*/ /*! check that sizeof() returns the proper size * * if ni_ver is valid (1 or 2 right now), check those sizes * if ni_ver == 0, check all known sizes * else whine and fail *//*--------------------------------------------------------------------*/ int nifti_valid_header_size(int ni_ver, int whine) { int size, errs=0, checks=0; if ( !ni_ver || (ni_ver == 1) ) { size = 348; checks++; if( sizeof(nifti_1_header) != size ) { if( whine ) fprintf(stderr, "** warning: sizeof(nifti_1_header) = %d, expected %d\n", (int)sizeof(nifti_1_header), size); errs++; } } if ( !ni_ver || (ni_ver == 2) ) { size = 540; checks++; if( sizeof(nifti_2_header) != size ) { if( whine ) fprintf(stderr, "** warning: sizeof(nifti_2_header) = %d, expected %d\n", (int)sizeof(nifti_2_header), size); errs++; } } if ( ! checks ) { fprintf(stderr,"** nifti_valid_header_size: bad ni_ver = %d\n",ni_ver); return 0; } return errs ? 0 : 1; /* though !errs seems more fun */ } /*----------------------------------------------------------------------*/ /*! decide if this nifti_2_header structure looks reasonable * swapping should have already happened Check sizeof() and sizeof_hdr. Check dim[0], dim[i], and datatype. Check magic string for "n+2". \return 1 if the header seems valid, 0 otherwise \sa nifti_nim_is_valid, valid_nifti_extensions *//*--------------------------------------------------------------------*/ int nifti_hdr2_looks_good(const nifti_2_header * hdr) { int ni_ver, c, errs = 0; int64_t d0; if( !hdr ) { fprintf(stderr,"** NIFTI n2hdr: hdr is NULL\n"); return 0; } /* for now, just warn if the header sizes are not right */ if( g_opts.debug > 0 ) (void)nifti_valid_header_size(0, 1); if( hdr->sizeof_hdr != sizeof(nifti_2_header) ) { if( g_opts.debug > 0 ) fprintf(stderr,"** NIFTI bad n2hdr: sizeof_hdr = %d\n", hdr->sizeof_hdr); errs++; } /* check the valid dimension sizes (maybe dim[0] is bad) */ d0 = hdr->dim[0]; if( d0 < 0 || d0 > 7 ) { if( g_opts.debug > 0 ) fprintf(stderr,"** NIFTI: bad n2hdr: dim0 = %" PRId64 "\n", d0); errs++; } else { /* only check dims if d0 is okay */ for( c = 1; c <= d0; c++ ) if( hdr->dim[c] <= 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"** NIFTI: bad nhdr field: dim[%d] = %" PRId64 "\n", c, hdr->dim[c]); errs++; } } ni_ver = NIFTI_VERSION(*hdr); /* note version */ if( ! nifti_datatype_is_valid(hdr->datatype, ni_ver) ){ if( g_opts.debug > 0 ) fprintf(stderr,"** bad %s NIFTI datatype in hdr, %d\n", ni_ver ? "NIFTI" : "ANALYZE", hdr->datatype); errs++; } /* NIFTI_VERSION must return 2, or else sizes will not match */ if( ni_ver != 2 || memcmp((hdr->magic+4), nifti2_magic+4, 4) ) { if( g_opts.debug > 0 ) { fprintf(stderr, "-- header magic not NIFTI-2, magic = '%.4s' + ", hdr->magic); print_hex_vals(hdr->magic+4, 4, stderr); fputc('\n', stderr); } errs++; } if( errs ) return 0; /* problems */ if( g_opts.debug > 2 ) fprintf(stderr,"-d nifti header looks good\n"); return 1; /* looks good */ } /*---------------------------------------------------------------------- * check whether byte swapping is needed * * dim[0] should be in [0,7], and sizeof_hdr should be accurate * * \returns > 0 : needs swap * 0 : does not need swap * < 0 : error condition *----------------------------------------------------------------------*/ static int need_nhdr_swap( short dim0, int hdrsize ) { short d0 = dim0; /* so we won't have to swap them on the stack */ int hsize = hdrsize; if( d0 != 0 ){ /* then use it for the check */ if( d0 > 0 && d0 <= 7 ) return 0; nifti_swap_2bytes(1, &d0); /* swap? */ if( d0 > 0 && d0 <= 7 ) return 1; if( g_opts.debug > 1 ){ fprintf(stderr,"** NIFTI: bad swapped d0 = %d, unswapped = ", d0); nifti_swap_2bytes(1, &d0); /* swap? */ fprintf(stderr,"%d\n", d0); } return -1; /* bad, naughty d0 */ } /* dim[0] == 0 should not happen, but could, so try hdrsize */ if( hsize == sizeof(nifti_1_header) ) return 0; nifti_swap_4bytes(1, &hsize); /* swap? */ if( hsize == sizeof(nifti_1_header) ) return 1; if( g_opts.debug > 1 ){ fprintf(stderr,"** NIFTI: bad swapped hsize = %d, unswapped = ", hsize); nifti_swap_4bytes(1, &hsize); /* swap? */ fprintf(stderr,"%d\n", hsize); } return -2; /* bad, naughty hsize */ } /* use macro LNI_FILE_ERROR instead of ERREX() #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_image_read(%s): %s\n", \ (hname != NULL) ? hname : "(null)" , (msg) ) ; \ return NULL ; } while(0) */ /*************************************************************** * nifti_read_header ***************************************************************/ /*! \brief Read and return a nifti header, along with the found type - The data buffer will be byteswapped if necessary. - The data buffer will not be scaled. - The data buffer is allocated with calloc(). \param hname filename of the nifti dataset \param nver : \return A void pointer, which should be cast based on the returned nver. It points to an allocated header struct. */ void * nifti_read_header( const char *hname, int *nver, int check ) { nifti_1_header n1hdr; nifti_2_header n2hdr; znzFile fp; void * hresult = NULL; int64_t remain, h1size=0, h2size=0; char fname[] = { "nifti_read_header" }; char *hfile=NULL, *posn; int ii, ni_ver; if( g_opts.debug > 2 ){ fprintf(stderr,"-d reading header from '%s'",hname); fprintf(stderr,", HAVE_ZLIB = %d\n", nifti_compiled_with_zlib()); } /**- determine filename to use for header */ hfile = nifti_findhdrname(hname); if( hfile == NULL ){ if(g_opts.debug > 0) LNI_FERR(fname,"failed to find header file for", hname); return NULL; /* check return */ } else if( g_opts.debug > 2 ) fprintf(stderr,"-d %s: found header filename '%s'\n",fname,hfile); h1size = sizeof(nifti_1_header); h2size = sizeof(nifti_2_header); /**- open file, separate reading of header, extensions and data */ fp = znzopen(hfile, "rb", nifti_is_gzfile(hfile)); if( znz_isnull(fp) ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open header file",hfile); free(hfile); return NULL; } /**- first try to read dataset as ASCII (and return NIFTI2 if so) */ if( has_ascii_header( fp ) ) { znzclose(fp) ; free(hfile); if( nver ) *nver = 2; return nifti_read_n2_hdr(hname, NULL, check); } /**- next read into nifti_1_header and determine nifti type */ ii = (int)znzread(&n1hdr, 1, h1size, fp); if( ii < (int)h1size ){ /* failure? */ if( g_opts.debug > 0 ){ LNI_FERR(fname,"bad binary header read for file", hfile); fprintf(stderr," - read %d of %d bytes\n",ii, (int)h1size); } znzclose(fp) ; free(hfile); return NULL; } /* find out what type of header we have */ ni_ver = nifti_header_version((char *)&n1hdr, h1size); if( g_opts.debug > 2 ) fprintf(stderr,"-- %s: NIFTI version = %d\n", fname, ni_ver); /* maybe set return NIFTI version */ if( nver ) *nver = ni_ver; /* if NIFTI-2, copy and finish reading header */ if ( ni_ver == 2 ) { if( g_opts.debug > 2 ) fprintf(stderr,"-- %s: copying and filling NIFTI-2 header...\n",fname); memcpy(&n2hdr, &n1hdr, h1size); /* copy first part */ remain = h2size - h1size; posn = (char *)&n2hdr + h1size; ii = (int)znzread(posn, 1, remain, fp); /* read remaining part */ if( ii < (int)remain) { LNI_FERR(fname,"short NIFTI-2 header read for file", hfile); znzclose(fp); free(hfile); return NULL; } } /* clean up */ znzclose(fp); free(hfile); /* allocate header space and return */ if( ni_ver == 0 || ni_ver == 1 ) { hresult = malloc(h1size); if( ! hresult ) { LNI_FERR(fname,"failed to alloc NIFTI-1 header for file", hname); return NULL; } memcpy(hresult, (void *)&n1hdr, h1size); if ( check && ! nifti_hdr1_looks_good(hresult) ){ LNI_FERR(fname,"nifti_1_header looks bad for file", hname); return hresult; } } else if ( ni_ver == 2 ) { hresult = malloc(h2size); if( ! hresult ) { LNI_FERR(fname,"failed to alloc NIFTI-2 header for file", hname); return NULL; } memcpy(hresult, &n2hdr, h2size); if ( check && ! nifti_hdr2_looks_good(hresult) ){ LNI_FERR(fname,"nifti_2_header looks bad for file", hname); return hresult; } } else { if( g_opts.debug > 0 ) fprintf(stderr, "** %s: bad nifti header version %d\n", hname, ni_ver); /* return a nifti-1 header anyway */ hresult = malloc(h1size); if( ! hresult ) { LNI_FERR(fname,"failed to alloc NIFTI-?? header for file", hname); return NULL; } memcpy(hresult, (void *)&n1hdr, h1size); } if( g_opts.debug > 1 ) fprintf(stderr,"-- returning NIFTI-%d header in %s\n", ni_ver, hname); return hresult; } /*************************************************************** * nifti_image_read ***************************************************************/ /*! \brief Read a nifti header and optionally the data, creating a nifti_image. - The data buffer will be byteswapped if necessary. - The data buffer will not be scaled. - The data buffer is allocated with calloc(). \param hname filename of the nifti dataset \param read_data Flag, true=read data blob, false=don't read blob. \return A pointer to the nifti_image data structure. \sa nifti_image_free, nifti_free_extensions, nifti_image_read_bricks */ nifti_image *nifti_image_read( const char *hname , int read_data ) { nifti_1_header n1hdr; nifti_2_header n2hdr; nifti_image *nim; znzFile fp; int rv, ii, ni_ver, onefile=0; int64_t filesize, remain, h1size=0, h2size=0; char fname[] = { "nifti_image_read" }; char *hfile=NULL, *posn; if( g_opts.debug > 1 ){ fprintf(stderr,"-d image_read from '%s', read_data = %d",hname,read_data); fprintf(stderr,", HAVE_ZLIB = %d\n", nifti_compiled_with_zlib()); } /**- determine filename to use for header */ hfile = nifti_findhdrname(hname); if( hfile == NULL ){ if(g_opts.debug > 0) LNI_FERR(fname,"failed to find header file for", hname); return NULL; /* check return */ } else if( g_opts.debug > 1 ) fprintf(stderr,"-d %s: found header filename '%s'\n",fname,hfile); if( nifti_is_gzfile(hfile) ) filesize = -1; /* unknown */ else filesize = nifti_get_filesize(hfile); /**- open file, separate reading of header, extensions and data */ fp = znzopen(hfile, "rb", nifti_is_gzfile(hfile)); if( znz_isnull(fp) ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open header file",hfile); free(hfile); return NULL; } /**- first try to read dataset as ASCII (and return if so) */ rv = has_ascii_header( fp ); if( rv < 0 ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"short header read",hfile); znzclose( fp ); free(hfile); return NULL; } else if ( rv == 1 ) { /* process special file type */ nim = nifti_read_ascii_image( fp, hfile, filesize, read_data ); znzclose(fp); free(hfile); return nim; } h1size = sizeof(nifti_1_header); h2size = sizeof(nifti_2_header); /**- next read into nifti_1_header and determine nifti type */ ii = (int)znzread(&n1hdr, 1, h1size, fp); if( ii < (int)h1size ){ /* failure? */ if( g_opts.debug > 0 ){ LNI_FERR(fname,"bad binary header read for file", hfile); fprintf(stderr," - read %d of %d bytes\n",ii, (int)h1size); } znzclose(fp) ; free(hfile); return NULL; } /* find out what type of header we have */ ni_ver = nifti_header_version((char *)&n1hdr, h1size); if( g_opts.debug > 2 ) fprintf(stderr,"-- %s: NIFTI version = %d\n", fname, ni_ver); if( ni_ver == 0 || ni_ver == 1 ) { nim = nifti_convert_n1hdr2nim(n1hdr,hfile); onefile = NIFTI_ONEFILE(n1hdr); } else if ( ni_ver == 2 ) { /* fill nifti-2 header and convert */ if( g_opts.debug > 2 ) fprintf(stderr,"-- %s: copying and filling NIFTI-2 header...\n",fname); memcpy(&n2hdr, &n1hdr, h1size); /* copy first part */ remain = h2size - h1size; posn = (char *)&n2hdr + h1size; ii = (int)znzread(posn, 1, remain, fp); /* read remaining part */ if( ii < (int)remain) { LNI_FERR(fname,"short NIFTI-2 header read for file", hfile); znzclose(fp); free(hfile); return NULL; } nim = nifti_convert_n2hdr2nim(n2hdr,hfile); onefile = NIFTI_ONEFILE(n2hdr); } else { if( g_opts.debug > 0 ) fprintf(stderr,"** %s: bad nifti im header version %d\n",fname,ni_ver); znzclose(fp); free(hfile); return NULL; } if( nim == NULL ){ znzclose( fp ) ; /* close the file */ if( g_opts.debug > 0 ) LNI_FERR(fname,"cannot create nifti image from header",hfile); free(hfile); /* had to save this for debug message */ return NULL; } if( g_opts.debug > 3 ){ fprintf(stderr,"+d nifti_image_read(), have nifti image:\n"); if( g_opts.debug > 2 ) nifti_image_infodump(nim); } /**- check for extensions (any errors here means no extensions) */ if ( onefile ) remain = nim->iname_offset; else remain = filesize; if ( ni_ver <= 1 ) remain -= h1size; else remain -= h2size; (void)nifti_read_extensions(nim, fp, remain); znzclose( fp ) ; /* close the file */ free(hfile); if ( g_opts.alter_cifti && nifti_looks_like_cifti(nim) ) nifti_alter_cifti_dims(nim); /**- read the data if desired, then bug out */ if( read_data ){ if( nifti_image_load( nim ) < 0 ){ nifti_image_free(nim); /* take ball, go home. */ return NULL; } } else nim->data = NULL ; return nim ; } /*---------------------------------------------------------------------- # return the index of the first occurrence of the given ecode, else -1 *----------------------------------------------------------------------*/ static int nifti_ext_type_index(nifti_image * nim, int ecode) { int ind; if ( !nim || ecode < 0 ) return -1; for( ind = 0; ind < nim->num_ext; ind++ ) if( nim->ext_list[ind].ecode == ecode ) return ind; return -1; } /*---------------------------------------------------------------------- *! does this dataset look like CIFTI? * * check dimensions and extension ecodes for CIFTI * * should have - nx=ny=nz=nt=1, nu,nv>1, nw optional * - CIFTI extension *----------------------------------------------------------------------*/ int nifti_looks_like_cifti(nifti_image * nim) { if( ! nim ) return 0; if( nifti_ext_type_index(nim, NIFTI_ECODE_CIFTI) < 0 ) return 0; if( nim->nx > 1 || nim->ny > 1 || nim->nz > 1 || nim->nt > 1 ) return 0; if( nim->nu > 1 || nim->nv > 1 ) return 1; /* looks like it */ return 0; } /*---------------------------------------------------------------------- *! alter the dims[] from CIFTI style * * convert nu -> nx, nv -> nt/nu, nw -> nv *----------------------------------------------------------------------*/ int nifti_alter_cifti_dims(nifti_image * nim) { if( ! nifti_looks_like_cifti(nim) ) return 0; /* the main effect, move position axis to x ... */ if( nim->nu > 1 || nim->dim[5] ) { nim->nx = nim->nu; nim->nu = 1; nim->dim[1] = nim->dim[5]; nim->dim[5] = 1; } return 0; } /*---------------------------------------------------------------------- * has_ascii_header - see if the NIFTI header is an ASCII format * * If the file starts with the ASCII string " 1 ) fprintf(stderr,"-d %s: have ASCII NIFTI file of size %d\n",fname,slen); if( slen > 65530 ) slen = 65530 ; sbuf = (char *)calloc(sizeof(char),slen+1) ; if( !sbuf ){ fprintf(stderr,"** %s: failed to alloc %d bytes for sbuf",lfunc,65530); return NULL; } znzread( sbuf , 1 , slen , fp ) ; nim = nifti_image_from_ascii( sbuf, &txt_size ) ; free( sbuf ) ; if( nim == NULL ){ LNI_FERR(lfunc,"failed nifti_image_from_ascii()",fname); return NULL; } nim->nifti_type = NIFTI_FTYPE_ASCII ; /* compute remaining space for extensions */ remain = flen - txt_size - (int)nifti_get_volsize(nim); if( remain > 4 ){ /* read extensions (reposition file pointer, first) */ znzseek(fp, txt_size, SEEK_SET); (void) nifti_read_extensions(nim, fp, (int64_t)remain); } nim->iname_offset = -1 ; /* check from the end of the file */ if( read_data ) rv = nifti_image_load( nim ) ; else nim->data = NULL ; /* check for nifti_image_load() failure, maybe bail out */ if( read_data && rv != 0 ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d failed image_load, free nifti image struct\n"); free(nim); return NULL; } return nim ; } /*---------------------------------------------------------------------- * Read the extensions into the nifti_image struct 08 Dec 2004 [rickr] * * This function is called just after the header struct is read in, and * it is assumed the file pointer has not moved. The value in remain * is assumed to be accurate, reflecting the bytes of space for potential * extensions. * * return the number of extensions read in, or < 0 on error *----------------------------------------------------------------------*/ static int nifti_read_extensions( nifti_image *nim, znzFile fp, int64_t remain ) { nifti1_extender extdr; /* defines extension existence */ nifti1_extension extn; /* single extension to process */ nifti1_extension * Elist; /* list of processed extensions */ int64_t posn, count; /* rcr n2 - add and use nifti2_extension type? */ if( !nim || znz_isnull(fp) ) { if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_read_extensions: bad inputs (%p,%p)\n", (void *)nim, (void *)fp); return -1; } posn = znztell(fp); if( g_opts.debug > 2 ) fprintf(stderr,"-d nre: posn=%" PRId64 ", offset=%" PRId64 ", type=%d, remain=%" PRId64 "\n", posn, nim->iname_offset, nim->nifti_type, remain); if( remain < 16 ){ if( g_opts.debug > 2 ){ if( g_opts.skip_blank_ext ) fprintf(stderr,"-d no extender in '%s' is okay, as " "skip_blank_ext is set\n",nim->fname); else fprintf(stderr,"-d remain=%" PRId64 ", no space for extensions\n", remain); } return 0; } count = znzread( extdr.extension, 1, 4, fp ); /* get extender */ if( count < 4 ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d file '%s' is too short for an extender\n", nim->fname); return 0; } if( extdr.extension[0] != 1 ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d extender[0] (%d) shows no extensions for '%s'\n", extdr.extension[0], nim->fname); return 0; } remain -= 4; if( g_opts.debug > 2 ) fprintf(stderr,"-d found valid 4-byte extender, remain = %" PRId64 "\n", remain); /* so we expect extensions, but have no idea of how many there may be */ count = 0; Elist = NULL; while (nifti_read_next_extension(&extn, nim, remain, fp) > 0) { if( nifti_add_exten_to_list(&extn, &Elist, (int)count+1) < 0 ){ free(Elist); if( g_opts.debug > 0 ) fprintf(stderr,"** NIFTI: failed adding ext %" PRId64 " to list\n", count); return -1; } /* we have a new extension */ if( g_opts.debug > 1 ){ fprintf(stderr,"+d found extension #%" PRId64 ", code = 0x%x, size = %d\n", count, extn.ecode, extn.esize); if( extn.ecode == NIFTI_ECODE_AFNI && g_opts.debug > 2 ) /* ~XML */ fprintf(stderr," AFNI extension: %.*s\n", extn.esize-8,extn.edata); else if( extn.ecode == NIFTI_ECODE_COMMENT && g_opts.debug > 2 ) fprintf(stderr," COMMENT extension: %.*s\n", /* TEXT */ extn.esize-8,extn.edata); } remain -= extn.esize; count++; } if( g_opts.debug > 2 ) fprintf(stderr,"+d found %" PRId64 " extension(s)\n", count); /* rcr n2 - allow int64_t num ext? */ nim->num_ext = (int)count; nim->ext_list = Elist; return count; } /*----------------------------------------------------------------------*/ /*! nifti_add_extension - add an extension, with a copy of the data Add an extension to the nim->ext_list array. Fill this extension with a copy of the data, noting the length and extension code. \param nim - nifti_image to add extension to \param data - raw extension data \param length - length of raw extension data \param ecode - extension code \sa extension codes NIFTI_ECODE_* in nifti1_io.h \sa nifti_free_extensions, valid_nifti_extensions, nifti_copy_extensions \return 0 on success, -1 on error (and free the entire list) *//*--------------------------------------------------------------------*/ int nifti_add_extension(nifti_image *nim, const char * data, int len, int ecode) { nifti1_extension ext; /* error are printed in functions */ if( nifti_fill_extension(&ext, data, len, ecode) ) { free(ext.edata); return -1; } if( nifti_add_exten_to_list(&ext, &nim->ext_list, nim->num_ext+1)) { free(ext.edata); return -1; } nim->num_ext++; /* success, so increment */ return 0; } /*----------------------------------------------------------------------*/ /* nifti_add_exten_to_list - add a new nifti1_extension to the list We will append via "malloc, copy and free", because on an error, the list will revert to the previous one (sorry realloc(), only quality dolphins get to become part of St@rk!st brand tunafish). return 0 on success, -1 on error (and free the entire list) *//*--------------------------------------------------------------------*/ static int nifti_add_exten_to_list( nifti1_extension * new_ext, nifti1_extension ** list, int new_length ) { nifti1_extension * tmplist; tmplist = *list; *list = (nifti1_extension *)malloc(new_length * sizeof(nifti1_extension)); /* check for failure first */ if( ! *list ){ fprintf(stderr,"** NIFTI: failed to alloc %d ext structs (%d bytes)\n", new_length, new_length*(int)sizeof(nifti1_extension)); if( !tmplist ) return -1; /* no old list to lose */ *list = tmplist; /* reset list to old one */ return -1; } /* if an old list exists, copy the pointers and free the list */ if( tmplist ){ memcpy(*list, tmplist, (new_length-1)*sizeof(nifti1_extension)); free(tmplist); } /* for some reason, I just don't like struct copy... */ (*list)[new_length-1].esize = new_ext->esize; (*list)[new_length-1].ecode = new_ext->ecode; (*list)[new_length-1].edata = new_ext->edata; if( g_opts.debug > 2 ) fprintf(stderr,"+d allocated and appended extension #%d to list\n", new_length); return 0; } /*----------------------------------------------------------------------*/ /* nifti_fill_extension - given data and length, fill an extension struct Allocate memory for data, copy data, set the size and code. return 0 on success, -1 on error (and free the entire list) *//*--------------------------------------------------------------------*/ static int nifti_fill_extension( nifti1_extension *ext, const char * data, int len, int ecode) { int esize; if( !ext || !data || len < 0 ){ fprintf(stderr,"** NIFTI fill_ext: bad params (%p,%p,%d)\n", (void *)ext, (void *)data, len); return -1; } else if( ! nifti_is_valid_ecode(ecode) ){ fprintf(stderr,"** NIFTI fill_ext: invalid ecode %d\n", ecode); /* should not be fatal 29 Apr 2015 [rickr] */ } /* compute esize, first : len+8, and take ceiling up to a mult of 16 */ esize = len+8; if( esize & 0xf ) esize = (esize + 0xf) & ~0xf; ext->esize = esize; /* allocate esize-8 (maybe more than len), using calloc for fill */ ext->edata = (char *)calloc(esize-8, sizeof(char)); if( !ext->edata ){ fprintf(stderr,"** NIFTI NFE: failed to alloc %d bytes for extension\n", len); return -1; } memcpy(ext->edata, data, len); /* copy the data, using len */ ext->ecode = ecode; /* set the ecode */ if( g_opts.debug > 2 ) fprintf(stderr,"+d alloc %d bytes for ext len %d, ecode %d, esize %d\n", esize-8, len, ecode, esize); return 0; } /*---------------------------------------------------------------------- * nifti_read_next_extension - read a single extension from the file * * return (>= 0 is okay): * * success : esize * no extension : 0 * error : -1 *----------------------------------------------------------------------*/ static int nifti_read_next_extension( nifti1_extension * nex, nifti_image *nim, int remain, znzFile fp ) { int swap = nim->byteorder != nifti_short_order(); int count, size, code = -1; /* first clear nex */ nex->esize = nex->ecode = 0; nex->edata = NULL; if( remain < 16 ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d only %d bytes remain, so no extension\n", remain); return 0; } /* must start with 4-byte size and code */ count = (int)znzread( &size, 4, 1, fp ); if( count == 1 ) count += (int)znzread( &code, 4, 1, fp ); if( count != 2 || code == -1 ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d current extension read failed\n"); znzseek(fp, -4*count, SEEK_CUR); /* back up past any read */ return 0; /* no extension, no error condition */ } if( swap ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d pre-swap exts: code %d, size %d\n", code, size); nifti_swap_4bytes(1, &size); nifti_swap_4bytes(1, &code); } if( g_opts.debug > 2 ) fprintf(stderr,"-d potential extension: code %d, size %d\n", code, size); if( !nifti_check_extension(nim, size, code, remain) ){ if( znzseek(fp, -8, SEEK_CUR) < 0 ){ /* back up past any read */ fprintf(stderr,"** NIFTI: failure to back out of extension read!\n"); return -1; } return 0; } /* now get the actual data */ nex->esize = size; nex->ecode = code; size -= 8; /* subtract space for size and code in extension */ nex->edata = (char *)malloc(size * sizeof(char)); if( !nex->edata ){ fprintf(stderr,"** NIFTI: failed to allocate %d bytes for extension\n", size); return -1; } count = (int)znzread(nex->edata, 1, size, fp); if( count < size ){ if( g_opts.debug > 0 ) fprintf(stderr,"-d read only %d (of %d) bytes for extension\n", count, size); free(nex->edata); nex->edata = NULL; return -1; } /* success! */ if( g_opts.debug > 2 ) fprintf(stderr,"+d successfully read extension, code %d, size %d\n", nex->ecode, nex->esize); return nex->esize; } /*----------------------------------------------------------------------*/ /*! for each extension, check code, size and data pointer *//*--------------------------------------------------------------------*/ int valid_nifti_extensions(const nifti_image * nim) { nifti1_extension * ext; int c, errs; if( nim->num_ext <= 0 || nim->ext_list == NULL ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d empty extension list\n"); return 0; } /* for each extension, check code, size and data pointer */ ext = nim->ext_list; errs = 0; for ( c = 0; c < nim->num_ext; c++ ){ if( ! nifti_is_valid_ecode(ext->ecode) ) { if( g_opts.debug > 1 ) fprintf(stderr,"-d ext %d, invalid code %d\n", c, ext->ecode); /* should not be fatal 29 Apr 2015 [rickr] */ } if( ext->esize <= 0 ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d ext %d, bad size = %d\n", c, ext->esize); errs++; } else if( ext->esize & 0xf ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d ext %d, size %d not multiple of 16\n", c, ext->esize); errs++; } if( ext->edata == NULL ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d ext %d, missing data\n", c); errs++; } ext++; } if( errs > 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"-d had %d extension errors, none will be written\n", errs); return 0; } /* if we're here, we're good */ return 1; } /*----------------------------------------------------------------------*/ /*! determine NIFTI version from buffer (check sizeof_hdr and magic) \return -1 on error, else NIFTI version *//*--------------------------------------------------------------------*/ int nifti_header_version(const char * buf, size_t nbytes){ nifti_1_header *n1p = (nifti_1_header *)buf; nifti_2_header *n2p = (nifti_2_header *)buf; char fname[] = { "nifti_header_version" }; int sizeof_hdr, sver, nver; if( !buf ) { if(g_opts.debug > 0) fprintf(stderr,"** %s: have NULL buffer pointer", fname); return -1; } if( nbytes < sizeof(nifti_1_header) ) { if(g_opts.debug > 0) fprintf(stderr,"** %s: nbytes=%zu, too small for test", fname, nbytes); return -1; } /* try to determine the version based on sizeof_hdr */ sver = -1; sizeof_hdr = n1p->sizeof_hdr; if ( sizeof_hdr == (int)sizeof(nifti_1_header) ) sver = 1; else if( sizeof_hdr == (int)sizeof(nifti_2_header) ) sver = 2; else { /* try swapping */ nifti_swap_4bytes(1, &sizeof_hdr); if ( sizeof_hdr == (int)sizeof(nifti_1_header) ) sver = 1; else if( sizeof_hdr == (int)sizeof(nifti_2_header) ) sver = 2; } /* and check magic field */ if ( sver == 1 ) nver = NIFTI_VERSION(*n1p); else if ( sver == 2 ) nver = NIFTI_VERSION(*n2p); else nver = -1; /* now compare and return */ if( g_opts.debug > 2 ) fprintf(stderr,"-- %s: size ver = %d, ni ver = %d\n", fname, sver, nver); if( sver == 1 ) { nver = NIFTI_VERSION(*n1p); if( nver == 0 ) return 0; /* ANALYZE */ if( nver == 1 ) return 1; /* NIFTI-1 */ if( g_opts.debug > 1 ) fprintf(stderr,"** %s: bad NIFTI-1 magic= %.4s", fname, n1p->magic); return -1; } else if ( sver == 2 ) { nver = NIFTI_VERSION(*n2p); if( nver == 2 ) return 2; /* NIFTI-2 */ if( g_opts.debug > 1 ) fprintf(stderr,"** %s: bad NIFTI-2 magic4= %.4s", fname, n2p->magic); return -1; } /* failure */ if( g_opts.debug > 0 ) fprintf(stderr,"** %s: bad sizeof_hdr = %d\n", fname, n1p->sizeof_hdr); return -1; } /*----------------------------------------------------------------------*/ /*! check whether the extension code is valid \return 1 if valid, 0 otherwise *//*--------------------------------------------------------------------*/ int nifti_is_valid_ecode( int ecode ) { if( ecode < NIFTI_ECODE_IGNORE || /* minimum code number (0) */ ecode > NIFTI_MAX_ECODE || /* maximum code number */ ecode & 1 ) /* cannot be odd */ return 0; return 1; } /*---------------------------------------------------------------------- * check for valid size and code, as well as can be done *----------------------------------------------------------------------*/ static int nifti_check_extension(nifti_image *nim, int size, int code, int rem) { /* check for bad code before bad size */ if( ! nifti_is_valid_ecode(code) ) { if( g_opts.debug > 2 ) fprintf(stderr,"-d invalid extension code %d\n",code); /* should not be fatal 29 Apr 2015 [rickr] */ } if( size < 16 ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d ext size %d, no extension\n",size); return 0; } if( size > rem ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d ext size %d, space %d, no extension\n", size, rem); return 0; } if( size & 0xf ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d nifti extension size %d not multiple of 16\n",size); return 0; } if( nim->nifti_type == NIFTI_FTYPE_ASCII && size > LNI_MAX_NIA_EXT_LEN ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d NVE, bad nifti_type 3 size %d\n", size); return 0; } return 1; } /*---------------------------------------------------------------------- * nifti_image_load_prep - prepare to read data * * Check nifti_image fields, open the file and seek to the appropriate * offset for reading. * * return NULL on failure *----------------------------------------------------------------------*/ static znzFile nifti_image_load_prep( nifti_image *nim ) { /* set up data space, open data file and seek, then call nifti_read_buffer */ int64_t ntot , ii , ioff; znzFile fp; char *tmpimgname; char fname[] = { "nifti_image_load_prep" }; /**- perform sanity checks */ if( nim == NULL || nim->iname == NULL || nim->nbyper <= 0 || nim->nvox <= 0 ) { if ( g_opts.debug > 0 ){ if( !nim ) fprintf(stderr,"** ERROR: N_image_load: no nifti image\n"); else fprintf(stderr,"** ERROR: nifti_image_load: bad params (%p,%d," "%" PRId64 ")\n", nim->iname, nim->nbyper, nim->nvox); } return NULL; } ntot = nifti_get_volsize(nim) ; /* total bytes to read */ /**- open image data file */ tmpimgname = nifti_findimgname(nim->iname , nim->nifti_type); if( tmpimgname == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** NIFTI: no image file found for '%s'\n",nim->iname); return NULL; } fp = znzopen(tmpimgname, "rb", nifti_is_gzfile(tmpimgname)); if (znz_isnull(fp)){ if(g_opts.debug > 0) LNI_FERR(fname,"cannot open data file",tmpimgname); free(tmpimgname); return NULL; /* bad open? */ } free(tmpimgname); /**- get image offset: a negative offset means to figure from end of file */ if( nim->iname_offset < 0 ){ if( nifti_is_gzfile(nim->iname) ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"negative offset for compressed file",nim->iname); znzclose(fp); return NULL; } ii = nifti_get_filesize( nim->iname ) ; if( ii <= 0 ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"empty data file",nim->iname); znzclose(fp); return NULL; } ioff = (ii > ntot) ? ii-ntot : 0 ; } else { /* non-negative offset */ ioff = nim->iname_offset ; /* means use it directly */ } /**- seek to the appropriate read position */ if( znzseek(fp , (long)ioff , SEEK_SET) < 0 ){ fprintf(stderr,"** NIFTI: could not seek to offset %" PRId64 " in file '%s'\n", ioff, nim->iname); znzclose(fp); return NULL; } /**- and return the File pointer */ return fp; } /*---------------------------------------------------------------------- * nifti_image_load *----------------------------------------------------------------------*/ /*! \fn int nifti_image_load( nifti_image *nim ) \brief Load the image blob into a previously initialized nifti_image. - If not yet set, the data buffer is allocated with calloc(). - The data buffer will be byteswapped if necessary. - The data buffer will not be scaled. This function is used to read the image from disk. It should be used after a function such as nifti_image_read(), so that the nifti_image structure is already initialized. \param nim pointer to a nifti_image (previously initialized) \return 0 on success, -1 on failure \sa nifti_image_read, nifti_image_free, nifti_image_unload */ int nifti_image_load( nifti_image *nim ) { /* set up data space, open data file and seek, then call nifti_read_buffer */ int64_t ntot , ii ; znzFile fp ; /**- open the file and position the FILE pointer */ fp = nifti_image_load_prep( nim ); if( fp == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_image_load, failed load_prep\n"); return -1; } ntot = nifti_get_volsize(nim); /**- if the data pointer is not yet set, get memory space for the image */ if( nim->data == NULL ) { nim->data = calloc(1,ntot) ; /* create image memory */ if( nim->data == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** NIFTI: failed to alloc %d bytes for image data\n", (int)ntot); znzclose(fp); return -1; } } /**- now that everything is set up, do the reading */ ii = nifti_read_buffer(fp,nim->data,ntot,nim); if( ii < ntot ){ znzclose(fp) ; free(nim->data) ; nim->data = NULL ; return -1 ; /* errors were printed in nifti_read_buffer() */ } /**- close the file */ znzclose( fp ) ; return 0 ; } /* 30 Nov 2004 [rickr] #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_read_buffer: %s\n",(msg)) ; \ return 0; } while(0) */ /*----------------------------------------------------------------------*/ /*! read ntot bytes of data from an open file and byte swaps if necessary note that nifti_image is required for information on datatype, bsize (for any needed byte swapping), etc. This function does not allocate memory, so dataptr must be valid. *//*--------------------------------------------------------------------*/ int64_t nifti_read_buffer(znzFile fp, void* dataptr, int64_t ntot, nifti_image *nim) { int64_t ii; if( dataptr == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** ERROR: nifti_read_buffer: NULL dataptr\n"); return -1; } ii = znzread( dataptr , 1 , ntot , fp ) ; /* data input */ /* if read was short, fail */ if( ii < ntot ){ if( g_opts.debug > 0 ) fprintf(stderr,"++ WARNING: nifti_read_buffer(%s):\n" " data bytes needed = %" PRId64 "\n" " data bytes input = %" PRId64 "\n" " number missing = %" PRId64 " (set to 0)\n", nim->iname , ntot , ii , (ntot-ii) ) ; /* memset( (char *)(dataptr)+ii , 0 , ntot-ii ) ; now failure [rickr] */ return -1 ; } if( g_opts.debug > 2 ) fprintf(stderr,"+d nifti_read_buffer: read %" PRId64 " bytes\n", ii); /* byte swap array if needed */ /* ntot/swapsize might not fit as int, use int64_t 6 Jul 2010 [rickr] */ if( nim->swapsize > 1 && nim->byteorder != nifti_short_order() ) { if( g_opts.debug > 1 ) fprintf(stderr,"+d nifti_read_buffer: swapping data bytes...\n"); nifti_swap_Nbytes( (int)(ntot / nim->swapsize), nim->swapsize , dataptr ) ; } #ifdef isfinite { /* check input float arrays for goodness, and fix bad floats */ int fix_count = 0 ; switch( nim->datatype ){ case NIFTI_TYPE_FLOAT32: case NIFTI_TYPE_COMPLEX64:{ float *far = (float *)dataptr ; int64_t jj,nj ; nj = ntot / sizeof(float) ; for( jj=0 ; jj < nj ; jj++ ) /* count fixes 30 Nov 2004 [rickr] */ if( !IS_GOOD_FLOAT(far[jj]) ){ far[jj] = 0 ; fix_count++ ; } } break ; case NIFTI_TYPE_FLOAT64: case NIFTI_TYPE_COMPLEX128:{ double *far = (double *)dataptr ; int64_t jj,nj ; nj = ntot / sizeof(double) ; for( jj=0 ; jj < nj ; jj++ ) /* count fixes 30 Nov 2004 [rickr] */ if( !IS_GOOD_FLOAT(far[jj]) ){ far[jj] = 0 ; fix_count++ ; } } break ; } if( g_opts.debug > 1 ) fprintf(stderr,"+d in image, %d bad floats were set to 0\n", fix_count); } #endif return ii; } /*--------------------------------------------------------------------------*/ /*! Unload the data in a nifti_image struct, but keep the metadata. *//*------------------------------------------------------------------------*/ void nifti_image_unload( nifti_image *nim ) { if( nim != NULL && nim->data != NULL ){ free(nim->data) ; nim->data = NULL ; } } /*--------------------------------------------------------------------------*/ /*! free 'everything' about a nifti_image struct (including the passed struct) free (only fields which are not NULL): - fname and iname - data - any ext_list[i].edata - ext_list - nim *//*------------------------------------------------------------------------*/ void nifti_image_free( nifti_image *nim ) { if( nim == NULL ) return ; if( nim->fname != NULL ) free(nim->fname) ; if( nim->iname != NULL ) free(nim->iname) ; if( nim->data != NULL ) free(nim->data ) ; (void)nifti_free_extensions( nim ) ; free(nim) ; } /*--------------------------------------------------------------------------*/ /*! free the nifti extensions - If any edata pointer is set in the extension list, free() it. - Free ext_list, if it is set. - Clear num_ext and ext_list from nim. \return 0 on success, -1 on error \sa nifti_add_extension, nifti_copy_extensions *//*------------------------------------------------------------------------*/ int nifti_free_extensions( nifti_image *nim ) { int c ; if( nim == NULL ) return -1; if( nim->num_ext > 0 && nim->ext_list ){ for( c = 0; c < nim->num_ext; c++ ) if ( nim->ext_list[c].edata ) free(nim->ext_list[c].edata); free(nim->ext_list); } /* or if it is inconsistent, warn the user (if we are not in quiet mode) */ else if ( (nim->num_ext > 0 || nim->ext_list != NULL) && (g_opts.debug > 0) ) fprintf(stderr,"** warning: nifti extension num/ptr mismatch (%d,%p)\n", nim->num_ext, (void *)nim->ext_list); if( g_opts.debug > 2 ) fprintf(stderr,"+d free'd %d extension(s)\n", nim->num_ext); nim->num_ext = 0; nim->ext_list = NULL; return 0; } /*--------------------------------------------------------------------------*/ /*! Print to stdout some info about a nifti_image struct. *//*------------------------------------------------------------------------*/ void nifti_image_infodump( const nifti_image *nim ) { char *str = nifti_image_to_ascii( nim ) ; /* stdout -> stderr 2 Dec 2004 [rickr] */ if( str != NULL ){ fputs(str,stderr) ; free(str) ; } } /*-------------------------------------------------------------------------- * nifti_write_buffer just check for a null znzFile and call znzwrite *--------------------------------------------------------------------------*/ /*! \fn int64_t nifti_write_buffer(znzFile fp, void *buffer, int64_t numbytes) \brief write numbytes of buffer to file, fp \param fp File pointer (from znzopen) to gzippable nifti datafile \param buffer data buffer to be written \param numbytes number of bytes in buffer to write \return number of bytes successfully written */ int64_t nifti_write_buffer(znzFile fp, const void *buffer, int64_t numbytes) { /* Write all the image data at once (no swapping here) */ int64_t ss; if (znz_isnull(fp)){ fprintf(stderr,"** ERROR: nifti_write_buffer: null file pointer\n"); return 0; } ss = znzwrite( buffer , 1 , numbytes , fp ) ; return ss; } /*----------------------------------------------------------------------*/ /*! write the nifti_image data to file (from nim->data or from NBL) If NBL is not NULL, write the data from that structure. Otherwise, write it out from nim->data. No swapping is done here. \param fp : File pointer \param nim : nifti_image corresponding to the data \param NBL : optional source of write data (if NULL use nim->data) \return 0 on success, -1 on failure Note: the nifti_image byte_order is set as that of the current CPU. This is because such a conversion was made to the data upon reading, while byte_order was not set (so the programs would know what format the data was on disk). Effectively, since byte_order should match what is on disk, it should bet set to that of the current CPU whenever new filenames are assigned. *//*--------------------------------------------------------------------*/ int nifti_write_all_data(znzFile fp, nifti_image * nim, const nifti_brick_list * NBL) { int64_t ss, bnum; if( !NBL ){ /* just write one buffer and get out of here */ if( nim->data == NULL ){ fprintf(stderr,"** NIFTI ERROR (NWAD): no image data to write\n"); return -1; } ss = nifti_write_buffer(fp,nim->data,nim->nbyper * nim->nvox); if (ss < nim->nbyper * nim->nvox){ fprintf(stderr, "** NIFTI ERROR (NWAD): wrote only %" PRId64 " of %" PRId64 " bytes to file\n", ss, nim->nbyper * nim->nvox); return -1; } if( g_opts.debug > 1 ) fprintf(stderr,"+d wrote single image of %" PRId64 " bytes\n", ss); } else { if( ! NBL->bricks || NBL->nbricks <= 0 || NBL->bsize <= 0 ){ fprintf(stderr,"** NIFTI error (NWAD): no brick data to write (%p,%" PRId64 ",%" PRId64 ")\n", (void *)NBL->bricks, NBL->nbricks, NBL->bsize); return -1; } for( bnum = 0; bnum < NBL->nbricks; bnum++ ){ ss = nifti_write_buffer(fp, NBL->bricks[bnum], NBL->bsize); if( ss < NBL->bsize ){ fprintf(stderr, "** NIFTI ERROR (NWAD): wrote only %" PRId64 " of %" PRId64 " bytes of brick %" PRId64 " of %" PRId64 " to file\n", ss, NBL->bsize, bnum+1, NBL->nbricks); return -1; } } if( g_opts.debug > 1 ) fprintf(stderr,"+d wrote image of %" PRId64 " brick(s), each of %" PRId64 " bytes\n", NBL->nbricks, NBL->bsize); } /* mark as being in this CPU byte order */ nim->byteorder = nifti_short_order() ; return 0; } /* return number of extensions written, or -1 on error */ static int nifti_write_extensions(znzFile fp, nifti_image *nim) { nifti1_extension * list; char extdr[4] = { 0, 0, 0, 0 }; int c, size, ok = 1; if( znz_isnull(fp) || !nim || nim->num_ext < 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_write_extensions, bad params\n"); return -1; } /* if no extensions and user requests it, skip extender */ if( g_opts.skip_blank_ext && (nim->num_ext == 0 || ! nim->ext_list ) ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d no exts and skip_blank_ext set, " "so skipping 4-byte extender\n"); return 0; } /* if invalid extension list, clear num_ext */ if( ! valid_nifti_extensions(nim) ) nim->num_ext = 0; /* write out extender block */ if( nim->num_ext > 0 ) extdr[0] = 1; if( nifti_write_buffer(fp, extdr, 4) != 4 ){ fprintf(stderr,"** NIFTI ERROR: failed to write extender\n"); return -1; } list = nim->ext_list; for ( c = 0; c < nim->num_ext; c++ ){ size = (int)nifti_write_buffer(fp, &list->esize, sizeof(int)); ok = (size == (int)sizeof(int)); if( ok ){ size = (int)nifti_write_buffer(fp, &list->ecode, sizeof(int)); ok = (size == (int)sizeof(int)); } if( ok ){ size = (int)nifti_write_buffer(fp, list->edata, list->esize - 8); ok = (size == list->esize - 8); } if( !ok ){ fprintf(stderr,"** NIFTI: failed while writing extension #%d\n",c); return -1; } else if ( g_opts.debug > 2 ) fprintf(stderr,"+d wrote extension %d of %d bytes\n", c, size); list++; } if( g_opts.debug > 1 ) fprintf(stderr,"+d wrote out %d extension(s)\n", nim->num_ext); return nim->num_ext; } /*----------------------------------------------------------------------*/ /*! basic initialization of a nifti_image struct (to a 1x1x1 image) *//*--------------------------------------------------------------------*/ nifti_image* nifti_simple_init_nim(void) { nifti_image *nim; nifti_2_header nhdr; int nbyper, swapsize; memset(&nhdr,0,sizeof(nhdr)) ; /* zero out header, to be safe */ nhdr.sizeof_hdr = sizeof(nhdr) ; nhdr.dim[0] = 3 ; nhdr.dim[1] = 1 ; nhdr.dim[2] = 1 ; nhdr.dim[3] = 1 ; nhdr.dim[4] = 0 ; nhdr.pixdim[0] = 0.0 ; nhdr.pixdim[1] = 1.0 ; nhdr.pixdim[2] = 1.0 ; nhdr.pixdim[3] = 1.0 ; nhdr.datatype = DT_FLOAT32 ; nifti_datatype_sizes( nhdr.datatype , &nbyper, &swapsize ); nhdr.bitpix = 8 * nbyper ; memcpy(nhdr.magic, nifti2_magic, 8); /* init to single file */ nim = nifti_convert_n2hdr2nim(nhdr,NULL); nim->fname = NULL; nim->iname = NULL; return nim; } /*----------------------------------------------------------------------*/ /*! basic initialization of a nifti_2_header struct (with given dimensions) Return an allocated nifti_2_header struct, based on the given dimensions and datatype. \param arg_dims : optional dim[8] array (default {3,1,1,1,0,0,0,0}) \param arg_dtype : optional datatype (default DT_FLOAT32) \return pointer to allocated nifti_2_header struct *//*--------------------------------------------------------------------*/ nifti_2_header * nifti_make_new_n2_header(const int64_t arg_dims[], int arg_dtype) { nifti_2_header * nhdr; const int64_t default_dims[8] = { 3, 1, 1, 1, 0, 0, 0, 0 }; const int64_t * dim; /* either passed or default dims */ int dtype; /* either passed or default dtype */ int c, nbyper, swapsize; /* if arg_dims is passed, apply it */ if( arg_dims ) dim = arg_dims; else dim = default_dims; /* validate dim: if there is any problem, apply default_dims */ if( dim[0] < 1 || dim[0] > 7 ) { fprintf(stderr,"** nifti_simple_hdr_with_dims: bad dim[0]=%" PRId64 "\n", dim[0]); dim = default_dims; } else { for( c = 1; c <= dim[0]; c++ ) if( dim[c] < 1 ) { fprintf(stderr, "** nifti_simple_hdr_with_dims: bad dim[%d]=%" PRId64 "\n", c, dim[c]); dim = default_dims; break; } } /* validate dtype, too */ dtype = arg_dtype; if( ! nifti_is_valid_datatype(dtype) ) { fprintf(stderr,"** nifti_simple_hdr_with_dims: bad dtype %d\n",dtype); dtype = DT_FLOAT32; } /* now populate the header struct */ if( g_opts.debug > 1 ) fprintf(stderr,"+d make_new_n2_header, dim[0] = %" PRId64 ", datatype = %d\n", dim[0], dtype); nhdr = (nifti_2_header *)calloc(1,sizeof(nifti_2_header)); if( !nhdr ){ fprintf(stderr,"** NIFTI make_new_n2_header: failed to alloc hdr\n"); return NULL; } nhdr->sizeof_hdr = sizeof(nifti_2_header) ; /* init dim and pixdim */ nhdr->dim[0] = dim[0]; nhdr->pixdim[0] = 0.0; for( c = 1; c <= dim[0]; c++ ) { nhdr->dim[c] = dim[c]; nhdr->pixdim[c] = 1.0; } nhdr->datatype = dtype ; nifti_datatype_sizes( nhdr->datatype , &nbyper, &swapsize ); nhdr->bitpix = 8 * nbyper ; memcpy(nhdr->magic, nifti2_magic, 8); /* init to single file */ return nhdr; } /*----------------------------------------------------------------------*/ /*! basic initialization of a nifti_1_header struct (with given dimensions) Return an allocated nifti_1_header struct, based on the given dimensions and datatype. \param arg_dims : optional dim[8] array (default {3,1,1,1,0,0,0,0}) \param arg_dtype : optional datatype (default DT_FLOAT32) \return pointer to allocated nifti_1_header struct *//*--------------------------------------------------------------------*/ nifti_1_header * nifti_make_new_n1_header(const int64_t arg_dims[], int arg_dtype) { nifti_1_header * nhdr; const int64_t default_dims[8] = { 3, 1, 1, 1, 0, 0, 0, 0 }; const int64_t * dim; /* either passed or default dims */ int dtype; /* either passed or default dtype */ int c, nbyper, swapsize; /* if arg_dims is passed, apply it */ if( arg_dims ) dim = arg_dims; else dim = default_dims; /* validate dim: if there is any problem, apply default_dims */ if( dim[0] < 1 || dim[0] > 7 ) { fprintf(stderr,"** nifti_simple_hdr_with_dims: bad dim[0]=%" PRId64 "\n", dim[0]); dim = default_dims; } else { for( c = 1; c <= dim[0]; c++ ) if( dim[c] < 1 ) { fprintf(stderr, "** nifti_simple_hdr_with_dims: bad dim[%d]=%" PRId64 "\n", c, dim[c]); dim = default_dims; break; } } /* validate dtype, too */ dtype = arg_dtype; if( ! nifti_is_valid_datatype(dtype) ) { fprintf(stderr,"** nifti_simple_hdr_with_dims: bad dtype %d\n",dtype); dtype = DT_FLOAT32; } /* now populate the header struct */ if( g_opts.debug > 1 ) fprintf(stderr,"+d make_new_n1_header, dim[0] = %" PRId64 ", datatype = %d\n", dim[0], dtype); nhdr = (nifti_1_header *)calloc(1,sizeof(nifti_1_header)); if( !nhdr ){ fprintf(stderr,"** NIFTI make_new_n1_header: failed to alloc hdr\n"); return NULL; } nhdr->sizeof_hdr = sizeof(nifti_1_header) ; nhdr->regular = 'r' ; /* for some stupid reason */ /* init dim and pixdim */ nhdr->dim[0] = (int)dim[0]; /* rcr n2 - check dim sizes for nifti-1 */ /* (verify vals are < 2^15) */ nhdr->pixdim[0] = 0.0f; for( c = 1; c <= dim[0]; c++ ) { nhdr->dim[c] = (int)dim[c]; nhdr->pixdim[c] = 1.0f; } nhdr->datatype = dtype ; nifti_datatype_sizes( nhdr->datatype , &nbyper, &swapsize ); nhdr->bitpix = 8 * nbyper ; strcpy(nhdr->magic, "n+1"); /* init to single file */ return nhdr; } /*----------------------------------------------------------------------*/ /*! basic creation of a nifti_image struct Create a nifti_image from the given dimensions and data type. Optinally, allocate zero-filled data. \param dims : optional dim[8] (default {3,1,1,1,0,0,0,0}) \param datatype : optional datatype (default DT_FLOAT32) \param data_fill : if flag is set, allocate zero-filled data for image \return pointer to allocated nifti_image struct *//*--------------------------------------------------------------------*/ nifti_image * nifti_make_new_nim(const int64_t dims[], int datatype, int data_fill) { nifti_image * nim; nifti_2_header * nhdr; nhdr = nifti_make_new_n2_header(dims, datatype); if( !nhdr ) return NULL; /* error already printed */ nim = nifti_convert_n2hdr2nim(*nhdr,NULL); free(nhdr); /* in any case, we are done with this */ if( !nim ){ fprintf(stderr,"** NMNN: nifti_convert_n2hdr2nim failure\n"); return NULL; } if( g_opts.debug > 1 ) fprintf(stderr,"+d nifti_make_new_nim, data_fill = %d\n",data_fill); if( data_fill ) { nim->data = calloc(nim->nvox, nim->nbyper); /* if we cannot allocate data, take ball and go home */ if( !nim->data ) { fprintf(stderr,"** NIFTI NMNN: failed to alloc %" PRId64 " bytes for data\n", nim->nvox*nim->nbyper); nifti_image_free(nim); nim = NULL; } } return nim; } #undef N_CHECK_2BYTE_VAL #define N_CHECK_2BYTE_VAL(fn) do { if( ! NIFTI_IS_16_BIT_INT(nim->fn) ) { \ fprintf(stderr,"** nim->%s = %" PRId64 \ " does not fit into NIFTI-1 header\n", \ #fn, (int64_t)nim->fn); return 1; } } while(0) /*----------------------------------------------------------------------*/ /*! convert a nifti_image structure to a nifti_1_header struct No allocation is done, this should be used via structure copy. As in:
    nifti_1_header my_header;
    my_header = nifti_convert_nim2n1hdr(my_nim_pointer);
    
*//*--------------------------------------------------------------------*/ int nifti_convert_nim2n1hdr(const nifti_image * nim, nifti_1_header * hdr) { nifti_1_header nhdr; if( !hdr ) { fprintf(stderr,"** nifti_CN2N1hdr: no hdr to fill\n"); return 1; } memset(&nhdr,0,sizeof(nhdr)) ; /* zero out header, to be safe */ /**- load the ANALYZE-7.5 generic parts of the header struct */ nhdr.sizeof_hdr = sizeof(nhdr) ; nhdr.regular = 'r' ; /* for some stupid reason */ N_CHECK_2BYTE_VAL(ndim); N_CHECK_2BYTE_VAL(nx); N_CHECK_2BYTE_VAL(ny); N_CHECK_2BYTE_VAL(nz); N_CHECK_2BYTE_VAL(nt); N_CHECK_2BYTE_VAL(nu); N_CHECK_2BYTE_VAL(nv); N_CHECK_2BYTE_VAL(nw); N_CHECK_2BYTE_VAL(datatype); N_CHECK_2BYTE_VAL(nbyper); nhdr.dim[0] = nim->ndim ; nhdr.dim[1] = nim->nx ; nhdr.dim[2] = nim->ny ; nhdr.dim[3] = nim->nz ; nhdr.dim[4] = nim->nt ; nhdr.dim[5] = nim->nu ; nhdr.dim[6] = nim->nv ; nhdr.dim[7] = nim->nw ; nhdr.pixdim[0] = 0.0f ; nhdr.pixdim[1] = nim->dx ; nhdr.pixdim[2] = nim->dy ; nhdr.pixdim[3] = nim->dz ; nhdr.pixdim[4] = nim->dt ; nhdr.pixdim[5] = nim->du ; nhdr.pixdim[6] = nim->dv ; nhdr.pixdim[7] = nim->dw ; nhdr.datatype = nim->datatype ; nhdr.bitpix = 8 * nim->nbyper ; if( nim->cal_max > nim->cal_min ){ nhdr.cal_max = nim->cal_max ; nhdr.cal_min = nim->cal_min ; } if( nim->scl_slope != 0.0 ){ nhdr.scl_slope = nim->scl_slope ; nhdr.scl_inter = nim->scl_inter ; } if( nim->descrip[0] != '\0' ){ memcpy(nhdr.descrip ,nim->descrip ,79) ; nhdr.descrip[79] = '\0' ; } if( nim->aux_file[0] != '\0' ){ memcpy(nhdr.aux_file ,nim->aux_file ,23) ; nhdr.aux_file[23] = '\0' ; } /**- Load NIFTI specific stuff into the header */ if( nim->nifti_type > NIFTI_FTYPE_ANALYZE ){ /* then not ANALYZE */ if( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcpy(nhdr.magic,"n+1") ; else strcpy(nhdr.magic,"ni1") ; nhdr.pixdim[1] = (float)fabs(nhdr.pixdim[1]) ; nhdr.pixdim[2] = (float)fabs(nhdr.pixdim[2]) ; nhdr.pixdim[3] = (float)fabs(nhdr.pixdim[3]) ; nhdr.pixdim[4] = (float)fabs(nhdr.pixdim[4]) ; nhdr.pixdim[5] = (float)fabs(nhdr.pixdim[5]) ; nhdr.pixdim[6] = (float)fabs(nhdr.pixdim[6]) ; nhdr.pixdim[7] = (float)fabs(nhdr.pixdim[7]) ; N_CHECK_2BYTE_VAL(intent_code); N_CHECK_2BYTE_VAL(qform_code); N_CHECK_2BYTE_VAL(sform_code); nhdr.intent_code = nim->intent_code ; nhdr.intent_p1 = nim->intent_p1 ; nhdr.intent_p2 = nim->intent_p2 ; nhdr.intent_p3 = nim->intent_p3 ; if( nim->intent_name[0] != '\0' ){ memcpy(nhdr.intent_name,nim->intent_name,15) ; nhdr.intent_name[15] = '\0' ; } nhdr.vox_offset = (float) nim->iname_offset ; nhdr.xyzt_units = SPACE_TIME_TO_XYZT( nim->xyz_units, nim->time_units ) ; nhdr.toffset = nim->toffset ; if( nim->qform_code > 0 ){ nhdr.qform_code = nim->qform_code ; nhdr.quatern_b = nim->quatern_b ; nhdr.quatern_c = nim->quatern_c ; nhdr.quatern_d = nim->quatern_d ; nhdr.qoffset_x = nim->qoffset_x ; nhdr.qoffset_y = nim->qoffset_y ; nhdr.qoffset_z = nim->qoffset_z ; nhdr.pixdim[0] = (nim->qfac >= 0.0) ? 1.0f : -1.0f ; } if( nim->sform_code > 0 ){ nhdr.sform_code = nim->sform_code ; nhdr.srow_x[0] = nim->sto_xyz.m[0][0] ; nhdr.srow_x[1] = nim->sto_xyz.m[0][1] ; nhdr.srow_x[2] = nim->sto_xyz.m[0][2] ; nhdr.srow_x[3] = nim->sto_xyz.m[0][3] ; nhdr.srow_y[0] = nim->sto_xyz.m[1][0] ; nhdr.srow_y[1] = nim->sto_xyz.m[1][1] ; nhdr.srow_y[2] = nim->sto_xyz.m[1][2] ; nhdr.srow_y[3] = nim->sto_xyz.m[1][3] ; nhdr.srow_z[0] = nim->sto_xyz.m[2][0] ; nhdr.srow_z[1] = nim->sto_xyz.m[2][1] ; nhdr.srow_z[2] = nim->sto_xyz.m[2][2] ; nhdr.srow_z[3] = nim->sto_xyz.m[2][3] ; } N_CHECK_2BYTE_VAL(sform_code); N_CHECK_2BYTE_VAL(slice_start); N_CHECK_2BYTE_VAL(slice_end); nhdr.dim_info = FPS_INTO_DIM_INFO( nim->freq_dim , nim->phase_dim , nim->slice_dim ) ; nhdr.slice_code = nim->slice_code ; nhdr.slice_start = nim->slice_start ; nhdr.slice_end = nim->slice_end ; nhdr.slice_duration = nim->slice_duration ; } memcpy(hdr, &nhdr, sizeof(nhdr)); return 0; } /*----------------------------------------------------------------------*/ /*! convert a nifti_image structure to a nifti_2_header struct No allocation is done, this should be used via structure copy. As in:
    nifti_2_header my_header;
    my_header = nifti_convert_nim2n2hdr(my_nim_pointer);
    
*//*--------------------------------------------------------------------*/ int nifti_convert_nim2n2hdr(const nifti_image * nim, nifti_2_header * hdr) { nifti_2_header nhdr; if( !hdr ) { fprintf(stderr,"** nifti_CN2N2hdr: no hdr to fill\n"); return 1; } memset(&nhdr,0,sizeof(nhdr)) ; /* zero out header, to be safe */ /**- load the ANALYZE-7.5 generic parts of the header struct */ nhdr.sizeof_hdr = sizeof(nhdr) ; if( nim->nifti_type == NIFTI_FTYPE_NIFTI2_1 ) strcpy(nhdr.magic,"n+2") ; else strcpy(nhdr.magic,"ni2") ; nhdr.datatype = nim->datatype ; nhdr.bitpix = 8 * nim->nbyper ; nhdr.dim[0] = nim->ndim ; nhdr.dim[1] = nim->nx ; nhdr.dim[2] = nim->ny ; nhdr.dim[3] = nim->nz ; nhdr.dim[4] = nim->nt ; nhdr.dim[5] = nim->nu ; nhdr.dim[6] = nim->nv ; nhdr.dim[7] = nim->nw ; nhdr.intent_p1 = nim->intent_p1 ; nhdr.intent_p2 = nim->intent_p2 ; nhdr.intent_p3 = nim->intent_p3 ; nhdr.pixdim[0] = 0.0 ; nhdr.pixdim[1] = fabs(nim->dx) ; nhdr.pixdim[2] = fabs(nim->dy) ; nhdr.pixdim[3] = fabs(nim->dz) ; nhdr.pixdim[4] = fabs(nim->dt) ; nhdr.pixdim[5] = fabs(nim->du) ; nhdr.pixdim[6] = fabs(nim->dv) ; nhdr.pixdim[7] = fabs(nim->dw) ; nhdr.vox_offset = nim->iname_offset ; nhdr.scl_slope = nim->scl_slope ; nhdr.scl_inter = nim->scl_inter ; nhdr.cal_max = nim->cal_max ; nhdr.cal_min = nim->cal_min ; nhdr.slice_duration = nim->slice_duration ; nhdr.toffset = nim->toffset ; nhdr.slice_start = nim->slice_start ; nhdr.slice_end = nim->slice_end ; if( nim->descrip[0] != '\0' ){ memcpy(nhdr.descrip ,nim->descrip ,79) ; nhdr.descrip[79] = '\0' ; } if( nim->aux_file[0] != '\0' ){ memcpy(nhdr.aux_file ,nim->aux_file ,23) ; nhdr.aux_file[23] = '\0' ; } if( nim->qform_code > 0 ){ nhdr.qform_code = nim->qform_code ; nhdr.quatern_b = nim->quatern_b ; nhdr.quatern_c = nim->quatern_c ; nhdr.quatern_d = nim->quatern_d ; nhdr.qoffset_x = nim->qoffset_x ; nhdr.qoffset_y = nim->qoffset_y ; nhdr.qoffset_z = nim->qoffset_z ; nhdr.pixdim[0] = (nim->qfac >= 0.0) ? 1.0f : -1.0f ; } if( nim->sform_code > 0 ){ nhdr.sform_code = nim->sform_code ; nhdr.srow_x[0] = nim->sto_xyz.m[0][0] ; nhdr.srow_x[1] = nim->sto_xyz.m[0][1] ; nhdr.srow_x[2] = nim->sto_xyz.m[0][2] ; nhdr.srow_x[3] = nim->sto_xyz.m[0][3] ; nhdr.srow_y[0] = nim->sto_xyz.m[1][0] ; nhdr.srow_y[1] = nim->sto_xyz.m[1][1] ; nhdr.srow_y[2] = nim->sto_xyz.m[1][2] ; nhdr.srow_y[3] = nim->sto_xyz.m[1][3] ; nhdr.srow_z[0] = nim->sto_xyz.m[2][0] ; nhdr.srow_z[1] = nim->sto_xyz.m[2][1] ; nhdr.srow_z[2] = nim->sto_xyz.m[2][2] ; nhdr.srow_z[3] = nim->sto_xyz.m[2][3] ; } nhdr.slice_code = nim->slice_code ; nhdr.xyzt_units = SPACE_TIME_TO_XYZT( nim->xyz_units, nim->time_units ) ; nhdr.intent_code = nim->intent_code ; if( nim->intent_name[0] != '\0' ){ memcpy(nhdr.intent_name,nim->intent_name,15) ; nhdr.intent_name[15] = '\0' ; } nhdr.dim_info = FPS_INTO_DIM_INFO( nim->freq_dim , nim->phase_dim , nim->slice_dim ) ; nhdr.unused_str[0] = '\0' ; /* not needed, but complete */ memcpy(hdr, &nhdr, sizeof(nhdr)); return 0; } /*----------------------------------------------------------------------*/ /*! \fn int nifti_copy_extensions(nifti_image * nim_dest, nifti_image * nim_src) \brief copy the nifti1_extension list from src to dest Duplicate the list of nifti1_extensions. The dest structure must be clear of extensions. \return 0 on success, -1 on failure \sa nifti_add_extension, nifti_free_extensions */ int nifti_copy_extensions(nifti_image * nim_dest, const nifti_image * nim_src) { char * data; int64_t bytes; int c, size, old_size; if( nim_dest->num_ext > 0 || nim_dest->ext_list != NULL ){ fprintf(stderr,"** NIFTI: will not copy over existing extensions\n"); return -1; } if( g_opts.debug > 1 ) fprintf(stderr,"+d duplicating %d extension(s)\n", nim_src->num_ext); if( nim_src->num_ext <= 0 ) return 0; bytes = nim_src->num_ext * sizeof(nifti1_extension); /* I'm lazy */ nim_dest->ext_list = (nifti1_extension *)malloc(bytes); if( !nim_dest->ext_list ){ fprintf(stderr,"** failed to allocate %d nifti1_extension structs\n", nim_src->num_ext); return -1; } /* copy the extension data */ nim_dest->num_ext = 0; for( c = 0; c < nim_src->num_ext; c++ ){ size = old_size = nim_src->ext_list[c].esize; if( size & 0xf ) size = (size + 0xf) & ~0xf; /* make multiple of 16 */ if( g_opts.debug > 2 ) fprintf(stderr,"+d dup'ing ext #%d of size %d (from size %d)\n", c, size, old_size); /* data length is size-8, as esize includes space for esize and ecode */ data = (char *)calloc(size-8,sizeof(char)); /* maybe size > old */ if( !data ){ fprintf(stderr,"** NIFTI: failed to alloc %d bytes for extention\n", size); if( c == 0 ) { free(nim_dest->ext_list); nim_dest->ext_list = NULL; } /* otherwise, keep what we have (a.o.t. deleting them all) */ return -1; } /* finally, fill the new structure */ nim_dest->ext_list[c].esize = size; nim_dest->ext_list[c].ecode = nim_src->ext_list[c].ecode; nim_dest->ext_list[c].edata = data; memcpy(data, nim_src->ext_list[c].edata, old_size-8); nim_dest->num_ext++; } return 0; } /*----------------------------------------------------------------------*/ /*! compute the total size of all extensions \return the total of all esize fields Note that each esize includes 4 bytes for ecode, 4 bytes for esize, and the bytes used for the data. Each esize also needs to be a multiple of 16, so it may be greater than the sum of its 3 parts. *//*--------------------------------------------------------------------*/ int nifti_extension_size(nifti_image *nim) { int c, size = 0; if( !nim || nim->num_ext <= 0 ) return 0; if( g_opts.debug > 2 ) fprintf(stderr,"-d ext sizes:"); for ( c = 0; c < nim->num_ext; c++ ){ size += nim->ext_list[c].esize; if( g_opts.debug > 2 ) fprintf(stderr," %d",nim->ext_list[c].esize); } if( g_opts.debug > 2 ) fprintf(stderr," (total = %d)\n",size); return size; } /*----------------------------------------------------------------------*/ /*! set the nifti_image iname_offset field, based on nifti_type - use nifti_ver to determine the size of the header (0: default, else NIFTI-version) - if writing to 2 files, set offset to 0 - if writing to a single NIFTI-1 file, set the offset to 352 + total extension size, then align to 16-byte boundary - if writing an ASCII header, set offset to -1 *//*--------------------------------------------------------------------*/ void nifti_set_iname_offset(nifti_image *nim, int nifti_ver) { int64_t offset; int64_t hsize = sizeof(nifti_1_header); /* default */ if( nifti_ver < 0 || nifti_ver > 2 ) { if( g_opts.debug > 0 ) fprintf(stderr,"** invalid nifti_ver = %d for set_iname_offset\n", nifti_ver); /* but stick with the default */ } else if( nifti_ver == 2 ) { hsize = sizeof(nifti_2_header); } switch( nim->nifti_type ){ default: /* writing into 2 files */ /* we only write files with 0 offset in the 2 file format */ nim->iname_offset = 0 ; break ; /* NIFTI-1 single binary file - always update */ case NIFTI_FTYPE_NIFTI1_1: offset = nifti_extension_size(nim) + hsize + 4; /* be sure offset is aligned to a 16 byte boundary */ if ( ( offset % 16 ) != 0 ) offset = ((offset + 0xf) & ~0xf); if( nim->iname_offset != offset ){ if( g_opts.debug > 1 ) fprintf(stderr,"+d changing offset from %" PRId64 " to %" PRId64 "\n", nim->iname_offset, offset); nim->iname_offset = offset; } break ; /* non-standard case: NIFTI-1 ASCII header + binary data (single file) */ case NIFTI_FTYPE_ASCII: nim->iname_offset = -1 ; /* compute offset from filesize */ break ; } } /*----------------------------------------------------------------------*/ /*! write the nifti_image dataset to disk, optionally including data This is just a front-end for nifti_image_write_hdr_img2. \param nim nifti_image to write to disk \param write_data write options (see nifti_image_write_hdr_img2) \param opts file open options ("wb" from nifti_image_write) \sa nifti_image_write, nifti_image_write_hdr_img2, nifti_image_free, nifti_set_filenames *//*--------------------------------------------------------------------*/ znzFile nifti_image_write_hdr_img( nifti_image *nim , int write_data , const char* opts ) { return nifti_image_write_hdr_img2(nim,write_data,opts,NULL,NULL); } #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_image_write_hdr_img: %s\n",(msg)) ; \ return fp ; } while(0) /* ----------------------------------------------------------------------*/ /*! This writes the header (and optionally the image data) to file * * If the image data file is left open it returns a valid znzFile handle. * It also uses imgfile as the open image file is not null, and modifies * it inside. * * \param nim nifti_image to write to disk * \param write_opts flags whether to write data and/or close file (see below) * \param opts file-open options, probably "wb" from nifti_image_write() * \param imgfile optional open znzFile struct, for writing image data (may be NULL) * \param NBL optional nifti_brick_list, containing the image data (may be NULL) * * Values for write_opts mode are based on two binary flags * ( 0/1 for no-write/write data, and 0/2 for close/leave-open files ) : * - 0 = do not write data and close (do not open data file) * - 1 = write data and close * - 2 = do not write data and leave data file open * - 3 = write data and leave data file open * * \sa nifti_image_write, nifti_image_write_hdr_img, nifti_image_free, * nifti_set_filenames *//*---------------------------------------------------------------------*/ znzFile nifti_image_write_hdr_img2(nifti_image *nim, int write_opts, const char * opts, znzFile imgfile, const nifti_brick_list * NBL) { nifti_1_header n1hdr ; nifti_2_header n2hdr ; znzFile fp=NULL; int64_t ss ; int write_data, leave_open; int nver=1, hsize=(int)sizeof(nifti_1_header); /* 5 Aug 2015 */ char func[] = { "nifti_image_write_hdr_img2" }; write_data = write_opts & 1; /* just separate the bits now */ leave_open = write_opts & 2; if( ! nim ) ERREX("NULL input") ; if( ! nifti_validfilename(nim->fname) ) ERREX("bad fname input") ; if( write_data && ! nim->data && ! NBL ) ERREX("no image data") ; if( write_data && NBL && ! nifti_NBL_matches_nim(nim, NBL) ) ERREX("NBL does not match nim"); nifti_set_iname_offset(nim, 1); if( g_opts.debug > 1 ){ fprintf(stderr,"-d writing nifti file '%s'...\n", nim->fname); if( g_opts.debug > 2 ) fprintf(stderr,"-d nifti type %d, offset %" PRId64 "\n", nim->nifti_type, nim->iname_offset); } if( nim->nifti_type == NIFTI_FTYPE_ASCII ) /* non-standard case */ return nifti_write_ascii_image(nim,NBL,opts,write_data,leave_open); /* create the nifti header struct 5 Aug, 2015 [rickr] - default is NIFTI-1 (option?) - if that fails try NIFTI-2 */ if( nifti_convert_nim2n1hdr(nim, &n1hdr) ) { nifti_set_iname_offset(nim, 2); if( nifti_convert_nim2n2hdr(nim, &n2hdr) ) return NULL; fprintf(stderr,"+d writing %s as NIFTI-2, instead...\n", nim->fname); nver = 2; /* we will write NIFTI-2 */ hsize = (int)sizeof(nifti_2_header); } /* if writing to 2 files, make sure iname is set and different from fname */ if( nim->nifti_type != NIFTI_FTYPE_NIFTI1_1 ){ if( nim->iname && strcmp(nim->iname,nim->fname) == 0 ){ free(nim->iname) ; nim->iname = NULL ; } if( nim->iname == NULL ){ /* then make a new one */ nim->iname = nifti_makeimgname(nim->fname,nim->nifti_type,0,0); if( nim->iname == NULL ) return NULL; } } /* if we have an imgfile and will write the header there, use it */ if( ! znz_isnull(imgfile) && nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ){ if( g_opts.debug > 2 ) fprintf(stderr,"+d using passed file for hdr\n"); fp = imgfile; } else { if( g_opts.debug > 2 ) fprintf(stderr,"+d opening output file %s [%s]\n",nim->fname,opts); fp = znzopen( nim->fname , opts , nifti_is_gzfile(nim->fname) ) ; if( znz_isnull(fp) ){ LNI_FERR(func,"cannot open output file",nim->fname); return fp; } } /* write the header and extensions */ if( nver == 2 ) ss = znzwrite(&n2hdr , 1 , hsize , fp); /* write header */ else ss = znzwrite(&n1hdr , 1 , hsize , fp); /* write header */ if( ss < hsize ){ LNI_FERR(func,"bad header write to output file",nim->fname); znzclose(fp); return fp; } /* partial file exists, and errors have been printed, so ignore return */ if( nim->nifti_type != NIFTI_FTYPE_ANALYZE ) (void)nifti_write_extensions(fp,nim); /* if the header is all we want, we are done */ if( ! write_data && ! leave_open ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d header is all we want: done\n"); znzclose(fp); return(fp); } if( nim->nifti_type != NIFTI_FTYPE_NIFTI1_1 ){ /* get a new file pointer */ znzclose(fp); /* first, close header file */ if( ! znz_isnull(imgfile) ){ if(g_opts.debug > 2) fprintf(stderr,"+d using passed file for img\n"); fp = imgfile; } else { if( g_opts.debug > 2 ) fprintf(stderr,"+d opening img file '%s'\n", nim->iname); fp = znzopen( nim->iname , opts , nifti_is_gzfile(nim->iname) ) ; if( znz_isnull(fp) ) ERREX("cannot open image file") ; } } znzseek(fp, nim->iname_offset, SEEK_SET); /* in any case, seek to offset */ if( write_data ) nifti_write_all_data(fp,nim,NBL); if( ! leave_open ) znzclose(fp); return fp; } /*----------------------------------------------------------------------*/ /*! write a nifti_image to disk in ASCII format *//*--------------------------------------------------------------------*/ znzFile nifti_write_ascii_image(nifti_image *nim, const nifti_brick_list * NBL, const char *opts, int write_data, int leave_open) { znzFile fp; char * hstr; hstr = nifti_image_to_ascii( nim ) ; /* get header in ASCII form */ if( ! hstr ){ fprintf(stderr,"** failed image_to_ascii()\n"); return NULL; } fp = znzopen( nim->fname , opts , nifti_is_gzfile(nim->fname) ) ; if( znz_isnull(fp) ){ free(hstr); fprintf(stderr,"** NIFTI: failed to open '%s' for ascii write\n", nim->fname); return fp; } znzputs(hstr,fp); /* header */ nifti_write_extensions(fp,nim); /* extensions */ if ( write_data ) { nifti_write_all_data(fp,nim,NBL); } /* data */ if ( ! leave_open ) { znzclose(fp); } free(hstr); return fp; /* returned but may be closed */ } /*--------------------------------------------------------------------------*/ /*! Write a nifti_image to disk. Since data is properly byte-swapped upon reading, it is assumed to be in the byte-order of the current CPU at write time. Thus, nim->byte_order should match that of the current CPU. Note that the nifti_set_filenames() function takes the flag, set_byte_order. The following fields of nim affect how the output appears: - nifti_type = 0 ==> ANALYZE-7.5 format file pair will be written - nifti_type = 1 ==> NIFTI-1 format single file will be written (data offset will be 352+extensions) - nifti_type = 2 ==> NIFTI_1 format file pair will be written - nifti_type = 3 ==> NIFTI_1 ASCII single file will be written - fname is the name of the output file (header or header+data) - if a file pair is being written, iname is the name of the data file - existing files WILL be overwritten with extreme prejudice - if qform_code > 0, the quatern_*, qoffset_*, and qfac fields determine the qform output, NOT the qto_xyz matrix; if you want to compute these fields from the qto_xyz matrix, you can use the utility function nifti_mat44_to_quatern() \sa nifti_image_write_bricks, nifti_image_free, nifti_set_filenames, nifti_image_write_hdr_img *//*------------------------------------------------------------------------*/ void nifti_image_write( nifti_image *nim ) { znzFile fp = nifti_image_write_hdr_img(nim,1,"wb"); if( fp ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d niw: done with znzFile\n"); free(fp); } if( g_opts.debug > 1 ) fprintf(stderr,"-d nifti_image_write: done\n"); } /*----------------------------------------------------------------------*/ /*! similar to nifti_image_write, but data is in NBL struct, not nim->data \sa nifti_image_write, nifti_image_free, nifti_set_filenames, nifti_free_NBL *//*--------------------------------------------------------------------*/ void nifti_image_write_bricks( nifti_image *nim, const nifti_brick_list * NBL ) { znzFile fp = nifti_image_write_hdr_img2(nim,1,"wb",NULL,NBL); if( fp ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d niwb: done with znzFile\n"); free(fp); } if( g_opts.debug > 1 ) fprintf(stderr,"-d niwb: done writing bricks\n"); } /*----------------------------------------------------------------------*/ /*! copy the nifti_image structure, without data Duplicate the structure, including fname, iname and extensions. Leave the data pointer as NULL. *//*--------------------------------------------------------------------*/ nifti_image * nifti_copy_nim_info(const nifti_image * src) { nifti_image *dest; dest = (nifti_image *)calloc(1,sizeof(nifti_image)); if( !dest ){ fprintf(stderr,"** NCNI: failed to alloc nifti_image\n"); return NULL; } memcpy(dest, src, sizeof(nifti_image)); if( src->fname ) dest->fname = nifti_strdup(src->fname); if( src->iname ) dest->iname = nifti_strdup(src->iname); dest->num_ext = 0; dest->ext_list = NULL; /* errors will be printed in NCE(), continue in either case */ (void)nifti_copy_extensions(dest, src); dest->data = NULL; return dest; } /*------------------------------------------------------------------------*/ /* Un-escape a C string in place -- that is, convert XML escape sequences back into their characters. (This can be done in place since the replacement is always smaller than the input.) Escapes recognized are: - < -> < - > -> > - " -> " - ' -> ' - & -> & Also replace CR LF pair (Microsoft), or CR alone (Macintosh) with LF (Unix), per the XML standard. Return value is number of replacements made (if you care). --------------------------------------------------------------------------*/ #undef CR #undef LF #define CR 0x0D #define LF 0x0A static int unescape_string( char *str ) { int ii,jj , nn,ll ; if( str == NULL ) return 0 ; /* no string? */ ll = (int)strlen(str) ; if( ll == 0 ) return 0 ; /* scan for escapes: &something; */ for( ii=jj=nn=0 ; ii': lout += 4 ; break ; /* replace '<' with "<" */ case '"' : case '\'': lout += 6 ; break ; /* replace '"' with """ */ case CR: case LF: lout += 6 ; break ; /* replace CR with " " LF with " " */ default: lout++ ; break ; /* copy all other chars */ } } out = (char *)calloc(1,lout) ; /* allocate output string */ if( !out ){ fprintf(stderr,"** NIFTI escapize_string: failed to alloc %d bytes\n", lout); return NULL; } out[0] = '\'' ; /* opening quote mark */ for( ii=0,jj=1 ; ii < lstr ; ii++ ){ switch( str[ii] ){ default: out[jj++] = str[ii] ; break ; /* normal characters */ case '&': memcpy(out+jj,"&",5) ; jj+=5 ; break ; case '<': memcpy(out+jj,"<",4) ; jj+=4 ; break ; case '>': memcpy(out+jj,">",4) ; jj+=4 ; break ; case '"' : memcpy(out+jj,""",6) ; jj+=6 ; break ; case '\'': memcpy(out+jj,"'",6) ; jj+=6 ; break ; case CR: memcpy(out+jj," ",6) ; jj+=6 ; break ; case LF: memcpy(out+jj," ",6) ; jj+=6 ; break ; } } out[jj++] = '\'' ; /* closing quote mark */ out[jj] = '\0' ; /* terminate the string */ return out ; } /*---------------------------------------------------------------------------*/ /*! Dump the information in a NIFTI image header to an XML-ish ASCII string that can later be converted back into a NIFTI header in nifti_image_from_ascii(). The resulting string can be free()-ed when you are done with it. *//*-------------------------------------------------------------------------*/ char *nifti_image_to_ascii( const nifti_image *nim ) { char *buf , *ebuf ; int nbuf ; if( nim == NULL ) return NULL ; /* stupid caller */ if( g_opts.debug > 2 ) fprintf(stderr,"+d converting %s to ASCII\n",nim->fname); buf = (char *)calloc(1,65534); /* longer than needed, to be safe */ if( !buf ){ fprintf(stderr,"** NIFTI NITA: failed to alloc %d bytes\n",65534); return NULL; } sprintf( buf , "nifti_type == NIFTI_FTYPE_NIFTI1_1) ? "NIFTI-1+" :(nim->nifti_type == NIFTI_FTYPE_NIFTI1_2) ? "NIFTI-1" :(nim->nifti_type == NIFTI_FTYPE_ASCII ) ? "NIFTI-1A" : "ANALYZE-7.5" ) ; /** Strings that we don't control (filenames, etc.) that might contain "weird" characters (like quotes) are "escaped": - A few special characters are replaced by XML-style escapes, using the function escapize_string(). - On input, function unescape_string() reverses this process. - The result is that the NIFTI ASCII-format header is XML-compliant. */ ebuf = escapize_string(nim->fname) ; sprintf( buf+strlen(buf) , " header_filename = %s\n",ebuf); free(ebuf); ebuf = escapize_string(nim->iname) ; sprintf( buf+strlen(buf) , " image_filename = %s\n", ebuf); free(ebuf); sprintf( buf+strlen(buf) , " image_offset = '%" PRId64 "'\n" , nim->iname_offset ); sprintf( buf+strlen(buf), " ndim = '%" PRId64 "'\n",nim->ndim); sprintf( buf+strlen(buf), " nx = '%" PRId64 "'\n", nim->nx ); if( nim->ndim > 1 ) sprintf( buf+strlen(buf), " ny = '%" PRId64 "'\n", nim->ny ); if( nim->ndim > 2 ) sprintf( buf+strlen(buf), " nz = '%" PRId64 "'\n", nim->nz ); if( nim->ndim > 3 ) sprintf( buf+strlen(buf), " nt = '%" PRId64 "'\n", nim->nt ); if( nim->ndim > 4 ) sprintf( buf+strlen(buf), " nu = '%" PRId64 "'\n", nim->nu ); if( nim->ndim > 5 ) sprintf( buf+strlen(buf), " nv = '%" PRId64 "'\n", nim->nv ); if( nim->ndim > 6 ) sprintf( buf+strlen(buf), " nw = '%" PRId64 "'\n", nim->nw ); sprintf( buf+strlen(buf), " dx = '%g'\n", nim->dx ); if( nim->ndim > 1 ) sprintf( buf+strlen(buf), " dy = '%g'\n", nim->dy ); if( nim->ndim > 2 ) sprintf( buf+strlen(buf), " dz = '%g'\n", nim->dz ); if( nim->ndim > 3 ) sprintf( buf+strlen(buf), " dt = '%g'\n", nim->dt ); if( nim->ndim > 4 ) sprintf( buf+strlen(buf), " du = '%g'\n", nim->du ); if( nim->ndim > 5 ) sprintf( buf+strlen(buf), " dv = '%g'\n", nim->dv ); if( nim->ndim > 6 ) sprintf( buf+strlen(buf), " dw = '%g'\n", nim->dw ); sprintf( buf+strlen(buf) , " datatype = '%d'\n" , nim->datatype ) ; sprintf( buf+strlen(buf) , " datatype_name = '%s'\n" , nifti_datatype_string(nim->datatype) ) ; sprintf( buf+strlen(buf) , " nvox = '%" PRId64 "'\n" , nim->nvox ) ; sprintf( buf+strlen(buf) , " nbyper = '%d'\n" , nim->nbyper ) ; sprintf( buf+strlen(buf) , " byteorder = '%s'\n" , (nim->byteorder==MSB_FIRST) ? "MSB_FIRST" : "LSB_FIRST" ) ; if( nim->cal_min < nim->cal_max ){ sprintf( buf+strlen(buf) , " cal_min = '%g'\n", nim->cal_min ) ; sprintf( buf+strlen(buf) , " cal_max = '%g'\n", nim->cal_max ) ; } if( nim->scl_slope != 0.0 ){ sprintf( buf+strlen(buf) , " scl_slope = '%g'\n" , nim->scl_slope ) ; sprintf( buf+strlen(buf) , " scl_inter = '%g'\n" , nim->scl_inter ) ; } if( nim->intent_code > 0 ){ sprintf( buf+strlen(buf) , " intent_code = '%d'\n", nim->intent_code ) ; sprintf( buf+strlen(buf) , " intent_code_name = '%s'\n" , nifti_intent_string(nim->intent_code) ) ; sprintf( buf+strlen(buf) , " intent_p1 = '%g'\n" , nim->intent_p1 ) ; sprintf( buf+strlen(buf) , " intent_p2 = '%g'\n" , nim->intent_p2 ) ; sprintf( buf+strlen(buf) , " intent_p3 = '%g'\n" , nim->intent_p3 ) ; if( nim->intent_name[0] != '\0' ){ ebuf = escapize_string(nim->intent_name) ; sprintf( buf+strlen(buf) , " intent_name = %s\n",ebuf) ; free(ebuf) ; } } if( nim->toffset != 0.0 ) sprintf( buf+strlen(buf) , " toffset = '%g'\n",nim->toffset ) ; if( nim->xyz_units > 0 ) sprintf( buf+strlen(buf) , " xyz_units = '%d'\n" " xyz_units_name = '%s'\n" , nim->xyz_units , nifti_units_string(nim->xyz_units) ) ; if( nim->time_units > 0 ) sprintf( buf+strlen(buf) , " time_units = '%d'\n" " time_units_name = '%s'\n" , nim->time_units , nifti_units_string(nim->time_units) ) ; if( nim->freq_dim > 0 ) sprintf( buf+strlen(buf) , " freq_dim = '%d'\n",nim->freq_dim ) ; if( nim->phase_dim > 0 ) sprintf( buf+strlen(buf) , " phase_dim = '%d'\n",nim->phase_dim ) ; if( nim->slice_dim > 0 ) sprintf( buf+strlen(buf) , " slice_dim = '%d'\n",nim->slice_dim ) ; if( nim->slice_code > 0 ) sprintf( buf+strlen(buf) , " slice_code = '%d'\n" " slice_code_name = '%s'\n" , nim->slice_code , nifti_slice_string(nim->slice_code) ) ; if( nim->slice_start >= 0 && nim->slice_end > nim->slice_start ) sprintf( buf+strlen(buf) , " slice_start = '%" PRId64 "'\n" " slice_end = '%" PRId64 "'\n", nim->slice_start , nim->slice_end ) ; if( nim->slice_duration != 0.0 ) sprintf( buf+strlen(buf) , " slice_duration = '%g'\n", nim->slice_duration ) ; if( nim->descrip[0] != '\0' ){ ebuf = escapize_string(nim->descrip) ; sprintf( buf+strlen(buf) , " descrip = %s\n",ebuf) ; free(ebuf) ; } if( nim->aux_file[0] != '\0' ){ ebuf = escapize_string(nim->aux_file) ; sprintf( buf+strlen(buf) , " aux_file = %s\n",ebuf) ; free(ebuf) ; } if( nim->qform_code > 0 ){ int i,j,k ; sprintf( buf+strlen(buf) , " qform_code = '%d'\n" " qform_code_name = '%s'\n" " qto_xyz_matrix = '%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g'\n" , nim->qform_code , nifti_xform_string(nim->qform_code) , nim->qto_xyz.m[0][0] , nim->qto_xyz.m[0][1] , nim->qto_xyz.m[0][2] , nim->qto_xyz.m[0][3] , nim->qto_xyz.m[1][0] , nim->qto_xyz.m[1][1] , nim->qto_xyz.m[1][2] , nim->qto_xyz.m[1][3] , nim->qto_xyz.m[2][0] , nim->qto_xyz.m[2][1] , nim->qto_xyz.m[2][2] , nim->qto_xyz.m[2][3] , nim->qto_xyz.m[3][0] , nim->qto_xyz.m[3][1] , nim->qto_xyz.m[3][2] , nim->qto_xyz.m[3][3] ) ; sprintf( buf+strlen(buf) , " qto_ijk_matrix = '%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g'\n" , nim->qto_ijk.m[0][0] , nim->qto_ijk.m[0][1] , nim->qto_ijk.m[0][2] , nim->qto_ijk.m[0][3] , nim->qto_ijk.m[1][0] , nim->qto_ijk.m[1][1] , nim->qto_ijk.m[1][2] , nim->qto_ijk.m[1][3] , nim->qto_ijk.m[2][0] , nim->qto_ijk.m[2][1] , nim->qto_ijk.m[2][2] , nim->qto_ijk.m[2][3] , nim->qto_ijk.m[3][0] , nim->qto_ijk.m[3][1] , nim->qto_ijk.m[3][2] , nim->qto_ijk.m[3][3] ) ; sprintf( buf+strlen(buf) , " quatern_b = '%g'\n" " quatern_c = '%g'\n" " quatern_d = '%g'\n" " qoffset_x = '%g'\n" " qoffset_y = '%g'\n" " qoffset_z = '%g'\n" " qfac = '%g'\n" , nim->quatern_b , nim->quatern_c , nim->quatern_d , nim->qoffset_x , nim->qoffset_y , nim->qoffset_z , nim->qfac ) ; nifti_dmat44_to_orientation( nim->qto_xyz , &i,&j,&k ) ; if( i > 0 && j > 0 && k > 0 ) sprintf( buf+strlen(buf) , " qform_i_orientation = '%s'\n" " qform_j_orientation = '%s'\n" " qform_k_orientation = '%s'\n" , nifti_orientation_string(i) , nifti_orientation_string(j) , nifti_orientation_string(k) ) ; } if( nim->sform_code > 0 ){ int i,j,k ; sprintf( buf+strlen(buf) , " sform_code = '%d'\n" " sform_code_name = '%s'\n" " sto_xyz_matrix = '%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g'\n" , nim->sform_code , nifti_xform_string(nim->sform_code) , nim->sto_xyz.m[0][0] , nim->sto_xyz.m[0][1] , nim->sto_xyz.m[0][2] , nim->sto_xyz.m[0][3] , nim->sto_xyz.m[1][0] , nim->sto_xyz.m[1][1] , nim->sto_xyz.m[1][2] , nim->sto_xyz.m[1][3] , nim->sto_xyz.m[2][0] , nim->sto_xyz.m[2][1] , nim->sto_xyz.m[2][2] , nim->sto_xyz.m[2][3] , nim->sto_xyz.m[3][0] , nim->sto_xyz.m[3][1] , nim->sto_xyz.m[3][2] , nim->sto_xyz.m[3][3] ) ; sprintf( buf+strlen(buf) , " sto_ijk matrix = '%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g'\n" , nim->sto_ijk.m[0][0] , nim->sto_ijk.m[0][1] , nim->sto_ijk.m[0][2] , nim->sto_ijk.m[0][3] , nim->sto_ijk.m[1][0] , nim->sto_ijk.m[1][1] , nim->sto_ijk.m[1][2] , nim->sto_ijk.m[1][3] , nim->sto_ijk.m[2][0] , nim->sto_ijk.m[2][1] , nim->sto_ijk.m[2][2] , nim->sto_ijk.m[2][3] , nim->sto_ijk.m[3][0] , nim->sto_ijk.m[3][1] , nim->sto_ijk.m[3][2] , nim->sto_ijk.m[3][3] ) ; nifti_dmat44_to_orientation( nim->sto_xyz , &i,&j,&k ) ; if( i > 0 && j > 0 && k > 0 ) sprintf( buf+strlen(buf) , " sform_i_orientation = '%s'\n" " sform_j_orientation = '%s'\n" " sform_k_orientation = '%s'\n" , nifti_orientation_string(i) , nifti_orientation_string(j) , nifti_orientation_string(k) ) ; } sprintf( buf+strlen(buf) , " num_ext = '%d'\n", nim->num_ext ) ; sprintf( buf+strlen(buf) , "/>\n" ) ; /* XML-ish closer */ nbuf = (int)strlen(buf) ; buf = (char *)realloc((void *)buf, nbuf+1); /* cut back to proper length */ if( !buf ) fprintf(stderr,"** NIFTI NITA: failed to realloc %d bytes\n", nbuf+1); return buf ; } /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /*! get the byte order for this CPU - LSB_FIRST means least significant byte, first (little endian) - MSB_FIRST means most significant byte, first (big endian) *//*--------------------------------------------------------------------*/ int nifti_short_order(void) /* determine this CPU's byte order */ { union { unsigned char bb[2] ; short ss ; } fred ; fred.bb[0] = 1 ; fred.bb[1] = 0 ; return (fred.ss == 1) ? LSB_FIRST : MSB_FIRST ; } /*---------------------------------------------------------------------------*/ #undef QQNUM #undef QNUM #undef QSTR /* macro to check lhs string against "n1"; if it matches, interpret rhs string as a number, and put it into nim->"n2" */ #define QQNUM(n1,n2,tt) if( strcmp(lhs,#n1)==0 ) nim->n2=(tt)strtod(rhs,NULL) /* same, but where "n1" == "n2" */ #define QNUM(nam,tt) QQNUM(nam,nam,tt) /* macro to check lhs string against "nam"; if it matches, put rhs string into nim->"nam" string, with max length = "ml" */ #define QSTR(nam,ml) if( strcmp(lhs,#nam) == 0 ) \ strncpy(nim->nam,rhs,ml), nim->nam[ml]='\0' /*---------------------------------------------------------------------------*/ /*! Take an XML-ish ASCII string and create a NIFTI image header to match. NULL is returned if enough information isn't present in the input string. - The image data can later be loaded with nifti_image_load(). - The struct returned here can be liberated with nifti_image_free(). - Not a lot of error checking is done here to make sure that the input values are reasonable! *//*-------------------------------------------------------------------------*/ nifti_image *nifti_image_from_ascii( const char *str, int * bytes_read ) { char lhs[1024] , rhs[1024] ; int ii , spos, nn ; nifti_image *nim ; /* will be output */ if( str == NULL || *str == '\0' ) return NULL ; /* bad input!? */ /* scan for opening string */ spos = 0 ; ii = sscanf( str+spos , "%1023s%n" , lhs , &nn ) ; spos += nn ; if( ii == 0 || strcmp(lhs,"nx = nim->ny = nim->nz = nim->nt = nim->nu = nim->nv = nim->nw = 1 ; nim->dx = nim->dy = nim->dz = nim->dt = nim->du = nim->dv = nim->dw = 0 ; nim->qfac = 1.0f ; nim->byteorder = nifti_short_order() ; /* starting at str[spos], scan for "equations" of the form lhs = 'rhs' and assign rhs values into the struct component named by lhs */ while(1){ while( isspace((int) str[spos]) ) spos++ ; /* skip whitespace */ if( str[spos] == '\0' ) break ; /* end of string? */ /* get lhs string */ ii = sscanf( str+spos , "%1023s%n" , lhs , &nn ) ; spos += nn ; if( ii == 0 || strcmp(lhs,"/>") == 0 ) break ; /* end of input? */ /* skip whitespace and the '=' marker */ while( isspace((int) str[spos]) || str[spos] == '=' ) spos++ ; if( str[spos] == '\0' ) break ; /* end of string? */ /* if next character is a quote ', copy everything up to next ' otherwise, copy everything up to next nonblank */ if( str[spos] == '\'' ){ ii = spos+1 ; while( str[ii] != '\0' && str[ii] != '\'' ) ii++ ; nn = ii-spos-1 ; if( nn > 1023 ) nn = 1023 ; memcpy(rhs,str+spos+1,nn) ; rhs[nn] = '\0' ; spos = (str[ii] == '\'') ? ii+1 : ii ; } else { ii = sscanf( str+spos , "%1023s%n" , rhs , &nn ) ; spos += nn ; if( ii == 0 ) break ; /* nothing found? */ } unescape_string(rhs) ; /* remove any XML escape sequences */ /* Now can do the assignment, based on lhs string. Start with special cases that don't fit the QNUM/QSTR macros. */ if( strcmp(lhs,"nifti_type") == 0 ){ if( strcmp(rhs,"ANALYZE-7.5") == 0 ) nim->nifti_type = NIFTI_FTYPE_ANALYZE ; else if( strcmp(rhs,"NIFTI-1+") == 0 ) nim->nifti_type = NIFTI_FTYPE_NIFTI1_1 ; else if( strcmp(rhs,"NIFTI-1") == 0 ) nim->nifti_type = NIFTI_FTYPE_NIFTI1_2 ; else if( strcmp(rhs,"NIFTI-1A") == 0 ) nim->nifti_type = NIFTI_FTYPE_ASCII ; } else if( strcmp(lhs,"header_filename") == 0 ){ nim->fname = nifti_strdup(rhs) ; } else if( strcmp(lhs,"image_filename") == 0 ){ nim->iname = nifti_strdup(rhs) ; } else if( strcmp(lhs,"sto_xyz_matrix") == 0 ){ sscanf( rhs , "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf" , &(nim->sto_xyz.m[0][0]) , &(nim->sto_xyz.m[0][1]) , &(nim->sto_xyz.m[0][2]) , &(nim->sto_xyz.m[0][3]) , &(nim->sto_xyz.m[1][0]) , &(nim->sto_xyz.m[1][1]) , &(nim->sto_xyz.m[1][2]) , &(nim->sto_xyz.m[1][3]) , &(nim->sto_xyz.m[2][0]) , &(nim->sto_xyz.m[2][1]) , &(nim->sto_xyz.m[2][2]) , &(nim->sto_xyz.m[2][3]) , &(nim->sto_xyz.m[3][0]) , &(nim->sto_xyz.m[3][1]) , &(nim->sto_xyz.m[3][2]) , &(nim->sto_xyz.m[3][3]) ) ; } else if( strcmp(lhs,"byteorder") == 0 ){ if( strcmp(rhs,"MSB_FIRST") == 0 ) nim->byteorder = MSB_FIRST ; if( strcmp(rhs,"LSB_FIRST") == 0 ) nim->byteorder = LSB_FIRST ; } else QQNUM(image_offset,iname_offset,int) ; else QNUM(datatype,short int) ; else QNUM(ndim,int) ; else QNUM(nx,int) ; else QNUM(ny,int) ; else QNUM(nz,int) ; else QNUM(nt,int) ; else QNUM(nu,int) ; else QNUM(nv,int) ; else QNUM(nw,int) ; else QNUM(dx,float) ; else QNUM(dy,float) ; else QNUM(dz,float) ; else QNUM(dt,float) ; else QNUM(du,float) ; else QNUM(dv,float) ; else QNUM(dw,float) ; else QNUM(cal_min,float) ; else QNUM(cal_max,float) ; else QNUM(scl_slope,float) ; else QNUM(scl_inter,float) ; else QNUM(intent_code,short) ; else QNUM(intent_p1,float) ; else QNUM(intent_p2,float) ; else QNUM(intent_p3,float) ; else QSTR(intent_name,15) ; else QNUM(toffset,float) ; else QNUM(xyz_units,int) ; else QNUM(time_units,int) ; else QSTR(descrip,79) ; else QSTR(aux_file,23) ; else QNUM(qform_code,int) ; else QNUM(quatern_b,float) ; else QNUM(quatern_c,float) ; else QNUM(quatern_d,float) ; else QNUM(qoffset_x,float) ; else QNUM(qoffset_y,float) ; else QNUM(qoffset_z,float) ; else QNUM(qfac,float) ; else QNUM(sform_code,int) ; else QNUM(freq_dim,int) ; else QNUM(phase_dim,int) ; else QNUM(slice_dim,int) ; else QNUM(slice_code,int) ; else QNUM(slice_start,int) ; else QNUM(slice_end,int) ; else QNUM(slice_duration,float) ; else QNUM(num_ext,int) ; } /* end of while loop */ if( bytes_read ) *bytes_read = spos+1; /* "process" last '\n' */ /* do miscellaneous checking and cleanup */ if( nim->ndim <= 0 ){ nifti_image_free(nim); return NULL; } /* bad! */ nifti_datatype_sizes( nim->datatype, &(nim->nbyper), &(nim->swapsize) ); if( nim->nbyper == 0 ){ nifti_image_free(nim); return NULL; } /* bad! */ nim->dim[0] = nim->ndim ; nim->dim[1] = nim->nx ; nim->pixdim[1] = nim->dx ; nim->dim[2] = nim->ny ; nim->pixdim[2] = nim->dy ; nim->dim[3] = nim->nz ; nim->pixdim[3] = nim->dz ; nim->dim[4] = nim->nt ; nim->pixdim[4] = nim->dt ; nim->dim[5] = nim->nu ; nim->pixdim[5] = nim->du ; nim->dim[6] = nim->nv ; nim->pixdim[6] = nim->dv ; nim->dim[7] = nim->nw ; nim->pixdim[7] = nim->dw ; nim->nvox = (int64_t)nim->nx * nim->ny * nim->nz * nim->nt * nim->nu * nim->nv * nim->nw ; if( nim->qform_code > 0 ) nim->qto_xyz = nifti_quatern_to_dmat44( nim->quatern_b, nim->quatern_c, nim->quatern_d, nim->qoffset_x, nim->qoffset_y, nim->qoffset_z, nim->dx , nim->dy , nim->dz , nim->qfac ) ; else nim->qto_xyz = nifti_quatern_to_dmat44( 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , nim->dx , nim->dy , nim->dz , 0.0 ) ; nim->qto_ijk = nifti_dmat44_inverse( nim->qto_xyz ) ; if( nim->sform_code > 0 ) nim->sto_ijk = nifti_dmat44_inverse( nim->sto_xyz ) ; return nim ; } /*---------------------------------------------------------------------------*/ /*! validate the nifti_image \return 1 if the structure seems valid, otherwise 0 \sa nifti_nim_has_valid_dims, nifti_hdr1_looks_good *//*-------------------------------------------------------------------------*/ int nifti_nim_is_valid(nifti_image * nim, int complain) { int errs = 0; if( !nim ){ fprintf(stderr,"** NIFTI is_valid_nim: nim is NULL\n"); return 0; } if( g_opts.debug > 2 ) fprintf(stderr,"-d nim_is_valid check...\n"); /**- check that dim[] matches the individual values ndim, nx, ny, ... */ if( ! nifti_nim_has_valid_dims(nim,complain) ){ if( !complain ) return 0; errs++; } /* might check nbyper, pixdim, q/sforms, swapsize, nifti_type, ... */ /**- be explicit in return of 0 or 1 */ if( errs > 0 ) return 0; else return 1; } /*---------------------------------------------------------------------------*/ /*! validate nifti dimensions \return 1 if valid, 0 if not \sa nifti_nim_is_valid, nifti_hdr1_looks_good rely on dim[] as the master *//*-------------------------------------------------------------------------*/ int nifti_nim_has_valid_dims(nifti_image * nim, int complain) { int64_t prod, c; int errs = 0; /**- start with dim[0]: failure here is considered terminal */ if( nim->dim[0] <= 0 || nim->dim[0] > 7 ){ errs++; if( complain ) fprintf(stderr,"** NIFTI NVd: dim[0] (%" PRId64 ") out of range [1,7]\n", nim->dim[0]); return 0; } /**- check whether ndim equals dim[0] */ if( nim->ndim != nim->dim[0] ){ errs++; if( ! complain ) return 0; fprintf(stderr,"** NIFTI NVd: ndim != dim[0] (%" PRId64 ",%" PRId64 ")\n", nim->ndim,nim->dim[0]); } /**- compare each dim[i] to the proper nx, ny, ... */ if( ( (nim->dim[0] >= 1) && (nim->dim[1] != nim->nx) ) || ( (nim->dim[0] >= 2) && (nim->dim[2] != nim->ny) ) || ( (nim->dim[0] >= 3) && (nim->dim[3] != nim->nz) ) || ( (nim->dim[0] >= 4) && (nim->dim[4] != nim->nt) ) || ( (nim->dim[0] >= 5) && (nim->dim[5] != nim->nu) ) || ( (nim->dim[0] >= 6) && (nim->dim[6] != nim->nv) ) || ( (nim->dim[0] >= 7) && (nim->dim[7] != nim->nw) ) ){ errs++; if( !complain ) return 0; fprintf(stderr,"** NIFTI NVd mismatch: dims = %" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 "\n" " nxyz... = %" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 ",%" PRId64 "\n", nim->dim[1], nim->dim[2], nim->dim[3], nim->dim[4], nim->dim[5], nim->dim[6], nim->dim[7], nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->nv, nim->nw ); } if( g_opts.debug > 2 ){ fprintf(stderr,"-d check dim[%" PRId64 "] =", nim->dim[0]); for( c = 0; c < 7; c++ ) fprintf(stderr," %" PRId64 "", nim->dim[c]); fputc('\n', stderr); } /**- check the dimensions, and that their product matches nvox */ prod = 1; for( c = 1; c <= nim->dim[0]; c++ ){ if( nim->dim[c] > 0) prod *= nim->dim[c]; else if( nim->dim[c] <= 0 ){ if( !complain ) return 0; fprintf(stderr,"** NIFTI NVd: dim[%" PRId64 "] (=%" PRId64 ") <= 0\n", c, nim->dim[c]); errs++; } } if( prod != nim->nvox ){ if( ! complain ) return 0; fprintf(stderr,"** NIFTI NVd: nvox does not match %" PRId64 "-dim product (%" PRId64 ", %" PRId64 ")\n", nim->dim[0], nim->nvox, prod); errs++; } /**- if debug, warn about any remaining dim that is neither 0, nor 1 */ /* (values in dims above dim[0] are undefined, as reminded by Cinly Ooi and Alle Meije Wink) 16 Nov 2005 [rickr] */ if( g_opts.debug > 1 ) for( c = nim->dim[0]+1; c <= 7; c++ ) if( nim->dim[c] != 0 && nim->dim[c] != 1 ) fprintf(stderr,"** NIFTI NVd warning: dim[%" PRId64 "] = %" PRId64 ", but ndim = %" PRId64 "\n", c, nim->dim[c], nim->dim[0]); if( g_opts.debug > 2 ) fprintf(stderr,"-d nim_has_valid_dims check, errs = %d\n", errs); /**- return invalid or valid */ if( errs > 0 ) return 0; else return 1; } /*---------------------------------------------------------------------------*/ /*! read a nifti image, collapsed across dimensions according to dims[8]

    This function may be used to read parts of a nifti dataset, such as
    the time series for a single voxel, or perhaps a slice.  It is similar
    to nifti_image_load(), though the passed 'data' parameter is used for
    returning the image, not nim->data.

    \param nim  given nifti_image struct, corresponding to the data file
    \param dims given list of dimensions (see below)
    \param data pointer to data pointer (if *data is NULL, data will be
                allocated, otherwise not)

    Here, dims is an array of 8 ints, similar to nim->dim[8].  While dims[0]
    is unused at this point, the other indices specify which dimensions to
    collapse (and at which index), and which not to collapse.  If dims[i] is
    set to -1, then that entire dimension will be read in, from index 0 to
    index (nim->dim[i] - 1).  If dims[i] >= 0, then only that index will be
    read in (so dims[i] must also be < nim->dim[i]).

    Example: given  nim->dim[8] = { 4, 64, 64, 21, 80, 1, 1, 1 } (4-D dataset)

      if dims[8] = { 0,  5,  4, 17, -1, -1, -1, -1 }
         -> read time series for voxel i,j,k = 5,4,17

      if dims[8] = { 0, -1, -1, -1, 17, -1, -1, -1 }
         -> read single volume at time point 17

    Example: given  nim->dim[8] = { 6, 64, 64, 21, 80, 4, 3, 1 } (6-D dataset)

      if dims[8] = { 0, 5, 4, 17, -1, 2, 1, 0 }
         -> read time series for the voxel i,j,k = 5,4,17, and dim 5,6 = 2,1

      if dims[8] = { 0, 5, 4, -1, -1, 0, 0, 0 }
         -> read time series for slice at i,j = 5,4, and dim 5,6,7 = 0,0,0
            (note that dims[7] is not relevant, but must be 0 or -1)

    If *data is NULL, then *data will be set as a pointer to new memory,
    allocated here for the resulting collapsed image data.

      e.g. { int    dims[8] = { 0,  5,  4, 17, -1, -1, -1, -1 };
             void * data    = NULL;
             ret_val = nifti_read_collapsed_image(nim, dims, &data);
             if( ret_val > 0 ){
                process_time_series(data);
                if( data != NULL ) free(data);
             }
           }

    NOTE: If *data is not NULL, then it will be assumed that it points to
          valid memory, sufficient to hold the results.  This is done for
          speed and possibly repeated calls to this function.

      e.g. { int64_t dims[8] = { 0,  -1, -1, -1, -1, -1, -1, -1 };
             void  * data    = NULL;
             for( zslice = 0; zslice < nzslices; zslice++ ){
                dims[3] = zslice;
                ret_val = nifti_read_collapsed_image(nim, dims, &data);
                if( ret_val > 0 ) process_slice(zslice, data);
             }
             if( data != NULL ) free(data);
           }

    \return
        -  the total number of bytes read, or < 0 on failure
        -  the read and byte-swapped data, in 'data'            
\sa nifti_image_read, nifti_image_free, nifti_image_read_bricks nifti_image_load *//*-------------------------------------------------------------------------*/ int64_t nifti_read_collapsed_image( nifti_image * nim, const int64_t dims [8], void ** data ) { znzFile fp; int64_t prods[8]; /* sizes are bounded by dims[], so 8 */ int pivots[8], nprods; /* sizes are bounded by dims[], so 8 */ int64_t c, bytes; /** - check pointers for sanity */ if( !nim || !dims || !data ){ fprintf(stderr,"** nifti_RCI: bad params %p, %p, %p\n", (void *)nim, (const void *)dims, (void *)data); return -1; } if( g_opts.debug > 2 ){ fprintf(stderr,"-d read_collapsed_image:\n dims ="); for(c = 0; c < 8; c++) fprintf(stderr," %3" PRId64 "", dims[c]); fprintf(stderr,"\n nim->dims ="); for(c = 0; c < 8; c++) fprintf(stderr," %3" PRId64 "", nim->dim[c]); fputc('\n', stderr); } /** - verify that dim[] makes sense */ if( ! nifti_nim_is_valid(nim, g_opts.debug > 0) ){ fprintf(stderr,"** NIFTI: invalid nim (file is '%s')\n", nim->fname ); return -1; } /** - verify that dims[] makes sense for this dataset */ for( c = 1; c <= nim->dim[0]; c++ ){ if( dims[c] >= nim->dim[c] ){ fprintf(stderr,"** nifti_RCI: dims[%" PRId64 "] >= nim->dim[%" PRId64 "] (%" PRId64 ",%" PRId64 ")\n", c, c, dims[c], nim->dim[c]); return -1; } } /** - prepare pivot list - pivots are fixed indices */ if( make_pivot_list(nim, dims, pivots, prods, &nprods) < 0 ) return -1; bytes = rci_alloc_mem(data, prods, nprods, nim->nbyper); if( bytes < 0 ) return -1; /** - open the image file for reading at the appropriate offset */ fp = nifti_image_load_prep( nim ); if( ! fp ){ free(*data); *data = NULL; return -1; } /* failure */ /** - call the recursive reading function, passing nim, the pivot info, location to store memory, and file pointer and position */ c = rci_read_data(nim, pivots, prods, nprods, dims, (char *)*data, fp, znztell(fp)); znzclose(fp); /* in any case, close the file */ if( c < 0 ){ free(*data); *data = NULL; return -1; } /* failure */ if( g_opts.debug > 1 ) fprintf(stderr,"+d read %" PRId64 " bytes of collapsed image from %s\n", bytes, nim->fname); return bytes; } /* local function to find strides per dimension. assumes 7D size and ** stride array. */ static void compute_strides(int64_t *strides,const int64_t *size,int nbyper) { int i; strides[0] = nbyper; for(i = 1; i < 7; i++) { strides[i] = size[i-1] * strides[i-1]; } } /*---------------------------------------------------------------------------*/ /*! read an arbitrary subregion from a nifti image This function may be used to read a single arbitary subregion of any rectangular size from a nifti dataset, such as a small 5x5x5 subregion around the center of a 3D image. \param nim given nifti_image struct, corresponding to the data file \param start_index the index location of first voxel that will be returned \param region_size the size of the subregion to be returned \param data pointer to data pointer (if *data is NULL, data will be allocated, otherwise not) Example: given nim->dim[8] = {3, 64, 64, 64, 1, 1, 1, 1 } (3-D dataset) if start_index[7] = { 29, 29, 29, 0, 0, 0, 0 } and region_size[7] = { 5, 5, 5, 1, 1, 1, 1 } -> read 5x5x5 region starting with the first voxel at (29,29,29) NOTE: If *data is not NULL, then it will be assumed that it points to valid memory, sufficient to hold the results. This is done for speed and possibly repeated calls to this function. \return - the total number of bytes read, or < 0 on failure - the read and byte-swapped data, in 'data' \sa nifti_image_read, nifti_image_free, nifti_image_read_bricks nifti_image_load, nifti_read_collapsed_image *//*-------------------------------------------------------------------------*/ int64_t nifti_read_subregion_image( nifti_image * nim, const int64_t *start_index, const int64_t *region_size, void ** data ) { znzFile fp; /* file to read */ int64_t i,j,k,l,m,n; /* indices for dims */ int64_t bytes = 0; /* total # bytes read */ int64_t total_alloc_size; /* size of buffer allocation */ char *readptr; /* where in *data to read next */ int64_t strides[7]; /* strides between dimensions */ int64_t collapsed_dims[8]; /* for read_collapsed_image */ int64_t *image_size; /* pointer to dimensions in header */ int64_t initial_offset; int64_t offset; /* seek offset for reading current row */ /* probably ignored, but set to ndim for consistency*/ collapsed_dims[0] = nim->ndim; /* build a dims array for collapsed image read */ for(i = 0; i < nim->ndim; i++) { /* if you take the whole extent in this dimension */ if(start_index[i] == 0 && region_size[i] == nim->dim[i+1]) collapsed_dims[i+1] = -1; /* if you specify a single element in this dimension */ else if(region_size[i] == 1) collapsed_dims[i+1] = start_index[i]; else collapsed_dims[i+1] = -2; /* sentinel value */ } /* fill out end of collapsed_dims */ for(i = nim->ndim ; i < 7; i++) collapsed_dims[i+1] = -1; /* check to see whether collapsed read is possible */ for(i = 1; i <= nim->ndim; i++) if(collapsed_dims[i] == -2) break; /* if you get through all the dimensions without hitting ** a subrange of size > 1, a collapsed read is possible */ if(i > nim->ndim) return nifti_read_collapsed_image(nim, collapsed_dims, data); /* point past first element of dim, which holds nim->ndim */ image_size = &(nim->dim[1]); /* check region sizes for sanity */ for(i = 0; i < nim->ndim; i++) if(start_index[i] + region_size[i] > image_size[i]) { if(g_opts.debug > 1) fprintf(stderr,"region doesn't fit within image size\n"); return -1; } /* get the file open */ fp = nifti_image_load_prep( nim ); /* the current offset is just past the nifti header, save * location so that SEEK_SET can be used below */ initial_offset = znztell(fp); /* get strides*/ compute_strides(strides,image_size,nim->nbyper); total_alloc_size = nim->nbyper; /* size of pixel */ /* find alloc size */ for(i = 0; i < nim->ndim; i++) total_alloc_size *= region_size[i]; /* allocate buffer, if necessary */ if(! *data) *data = malloc(total_alloc_size); if(! *data) { if(g_opts.debug > 1) fprintf(stderr,"allocation of %" PRId64 " bytes failed\n", total_alloc_size); return -1; } /* point to start of data buffer as char * */ readptr = *((char **)data); { /* can't assume that start_index and region_size have any more than ** nim->ndim elements so make local copies, filled out to seven elements */ int64_t si[7], rs[7]; for(i = 0; i < nim->ndim; i++) { si[i] = start_index[i]; rs[i] = region_size[i]; } for(i = nim->ndim; i < 7; i++) { si[i] = 0; rs[i] = 1; } /* loop through subregion and read a row at a time */ for(i = si[6]; i < (si[6] + rs[6]); i++) { for(j = si[5]; j < (si[5] + rs[5]); j++) { for(k = si[4]; k < (si[4] + rs[4]); k++) { for(l = si[3]; l < (si[3] + rs[3]); l++) { for(m = si[2]; m < (si[2] + rs[2]); m++) { for(n = si[1]; n < (si[1] + rs[1]); n++) { int64_t nread,read_amount; offset = initial_offset + (i * strides[6]) + (j * strides[5]) + (k * strides[4]) + (l * strides[3]) + (m * strides[2]) + (n * strides[1]) + (si[0] * strides[0]); znzseek(fp, offset, SEEK_SET); /* seek to current row */ read_amount = rs[0] * nim->nbyper; /* read a row of subregion */ nread = nifti_read_buffer(fp, readptr, read_amount, nim); if(nread != read_amount) { if(g_opts.debug > 1) { fprintf(stderr,"read of %" PRId64 " bytes failed\n", read_amount); return -1; } } bytes += nread; readptr += read_amount; } } } } } } } znzclose(fp); return bytes; } /* read the data from the file pointed to by fp - this a recursive function, so start with the base case - data is now (char *) for easy incrementing return 0 on success, < 0 on failure */ static int rci_read_data(nifti_image * nim, int * pivots, int64_t * prods, int nprods, const int64_t dims[], char * data, znzFile fp, int64_t base_offset) { int64_t sublen, offset, read_size; int c; /* bad check first - base_offset may not have been checked */ if( nprods <= 0 ){ fprintf(stderr,"** NIFTI rci_read_data, bad prods, %d\n", nprods); return -1; } /* base case: actually read the data */ if( nprods == 1 ){ int64_t nread, bytes; /* make sure things look good here */ if( *pivots != 0 ){ fprintf(stderr,"** NIFTI rciRD: final pivot == %d!\n", *pivots); return -1; } /* so just seek and read (prods[0] * nbyper) bytes from the file */ znzseek(fp, base_offset, SEEK_SET); bytes = prods[0] * nim->nbyper; nread = nifti_read_buffer(fp, data, bytes, nim); if( nread != bytes ){ fprintf(stderr,"** NIFTI rciRD: read only %" PRId64 " of %" PRId64 " bytes from '%s'\n", nread, bytes, nim->fname); return -1; } else if( g_opts.debug > 3 ) fprintf(stderr,"+d successful read of %" PRId64 " bytes at offset %" PRId64 "\n", bytes, base_offset); return 0; /* done with base case - return success */ } /* not the base case, so do a set of reduced reads */ /* compute size of sub-brick: all dimensions below pivot */ for( c = 1, sublen = 1; c < *pivots; c++ ) sublen *= nim->dim[c]; /* compute number of values to read, i.e. remaining prods */ for( c = 1, read_size = 1; c < nprods; c++ ) read_size *= prods[c]; read_size *= nim->nbyper; /* and multiply by bytes per voxel */ /* now repeatedly compute offsets, and recursively read */ for( c = 0; c < prods[0]; c++ ){ /* offset is (c * sub-block size (including pivot dim)) */ /* + (dims[] index into pivot sub-block) */ /* the unneeded multiplication is to make this more clear */ offset = (int64_t)c * sublen * nim->dim[*pivots] + (int64_t)sublen * dims[*pivots]; offset *= nim->nbyper; if( g_opts.debug > 3 ) fprintf(stderr,"-d reading %" PRId64 " bytes, foff %" PRId64 " + %" PRId64 ", doff %" PRId64 "\n", read_size, base_offset, offset, c*read_size); /* now read the next level down, adding this offset */ if( rci_read_data(nim, pivots+1, prods+1, nprods-1, dims, data + c * read_size, fp, base_offset + offset) < 0 ) return -1; } return 0; } /* allocate memory for all collapsed image data If *data is already set, do not allocate, but still calculate size for debug report. return total size on success, and < 0 on failure */ static int rci_alloc_mem(void **data, const int64_t prods[8], int nprods, int nbyper ) { int64_t size; int memindex; if( nbyper < 0 || nprods < 1 || nprods > 8 ){ fprintf(stderr,"** NIFTI rci_am: bad params, %d, %d\n", nbyper, nprods); return -1; } for( memindex = 0, size = 1; memindex < nprods; memindex++ ) size *= prods[memindex]; size *= nbyper; if( ! *data ){ /* then allocate what is needed */ if( g_opts.debug > 1 ) fprintf(stderr,"+d alloc %" PRId64 " (%" PRId64 " x %d) bytes for collapsed image\n", size, size/nbyper, nbyper); *data = malloc(size); /* actually allocate the memory */ if( ! *data ){ fprintf(stderr,"** NIFTI rci_am: failed to alloc %" PRId64 " bytes for data\n", size); return -1; } } else if( g_opts.debug > 1 ) fprintf(stderr,"-d rci_am: *data already set, need %" PRId64 " x %d bytes\n", size/nbyper, nbyper); return size; } /* prepare a pivot list for reading The pivot points are the indices into dims where the calling function wants to collapse a dimension. The last pivot should always be zero (note that we have space for that in the lists). */ static int make_pivot_list(nifti_image *nim, const int64_t dims[], int pivots[], int64_t prods[], int * nprods ) { int len, dind; len = 0; dind = nim->dim[0]; while( dind > 0 ){ prods[len] = 1; while( dind > 0 && (nim->dim[dind] == 1 || dims[dind] == -1) ){ prods[len] *= nim->dim[dind]; dind--; } pivots[len] = dind; len++; dind--; /* fine, let it drop out at -1 */ } /* make sure to include 0 as a pivot (instead of just 1, if it is) */ if( len > 0 && pivots[len-1] != 0 ){ pivots[len] = 0; prods[len] = 1; len++; } *nprods = len; if( g_opts.debug > 2 ){ fprintf(stderr,"+d pivot list created, pivots :"); for(dind = 0; dind < len; dind++) fprintf(stderr," %d", pivots[dind]); fprintf(stderr,", prods :"); for(dind = 0; dind < len; dind++) fprintf(stderr," %" PRId64 "", prods[dind]); fputc('\n',stderr); } return 0; } #undef ISEND #define ISEND(c) ( (c)==']' || (c)=='}' || (c)=='\0' ) /*---------------------------------------------------------------------*/ /*! Get an integer list in the range 0..(nvals-1), from the character string str. If we call the output pointer fred, then fred[0] = number of integers in the list (> 0), and fred[i] = i-th integer in the list for i=1..fred[0]. If on return, fred == NULL or fred[0] == 0, then something is wrong, and the caller must deal with that. Syntax of input string: - initial '{' or '[' is skipped, if present - ends when '}' or ']' or end of string is found - contains entries separated by commas - entries have one of these forms: - a single number - a dollar sign '$', which means nvals-1 - a sequence of consecutive numbers in the form "a..b" or "a-b", where "a" and "b" are single numbers (or '$') - a sequence of evenly spaced numbers in the form "a..b(c)" or "a-b(c)", where "c" encodes the step - Example: "[2,7..4,3..9(2)]" decodes to the list 2 7 6 5 4 3 5 7 9 - entries should be in the range 0..nvals-1 (borrowed, with permission, from thd_intlist.c) *//*-------------------------------------------------------------------*/ int64_t * nifti_get_int64list( int64_t nvals , const char * str ) { int64_t *subv = NULL ; int64_t *subv_realloc = NULL; int64_t ii , nout ; int64_t ibot,itop,istep , nused ; int ipos , slen ; char *cpt ; /* Meaningless input? */ if( nvals < 1 ) return NULL ; /* No selection list? */ if( str == NULL || str[0] == '\0' ) return NULL ; /* skip initial '[' or '{' */ subv = (int64_t *)malloc( sizeof(int64_t) * 2 ) ; if( !subv ) { fprintf(stderr,"** nifti_get_intlist: failed alloc of 2 ints\n"); return NULL; } subv[0] = nout = 0 ; ipos = 0 ; if( str[ipos] == '[' || str[ipos] == '{' ) ipos++ ; if( g_opts.debug > 1 ) fprintf(stderr,"-d making int_list (vals = %" PRId64 ") from '%s'\n", nvals, str); /**- for each sub-selector until end of input... */ slen = (int)strlen(str) ; while( ipos < slen && !ISEND(str[ipos]) ){ while( isspace((int) str[ipos]) ) ipos++ ; /* skip blanks */ if( ISEND(str[ipos]) ) break ; /* done */ /**- get starting value */ if( str[ipos] == '$' ){ /* special case */ ibot = nvals-1 ; ipos++ ; } else { /* decode an integer */ ibot = strtoll( str+ipos , &cpt , 10 ) ; if( ibot < 0 ){ fprintf(stderr,"** NIFTI ERROR: list index %" PRId64 " is out of range 0..%" PRId64 "\n", ibot,nvals-1) ; free(subv) ; return NULL ; } if( ibot >= nvals ){ fprintf(stderr,"** NIFTI ERROR: list index %" PRId64 " is out of range 0..%" PRId64 "\n", ibot,nvals-1) ; free(subv) ; return NULL ; } nused = (cpt-(str+ipos)) ; if( ibot == 0 && nused == 0 ){ fprintf(stderr,"** NIFTI : list syntax error '%s'\n",str+ipos) ; free(subv) ; return NULL ; } ipos += nused ; } while( isspace((int) str[ipos]) ) ipos++ ; /* skip blanks */ /**- if that's it for this sub-selector, add one value to list */ if( str[ipos] == ',' || ISEND(str[ipos]) ){ nout++ ; subv_realloc = (int64_t *)realloc( (char *)subv , sizeof(int64_t)*(nout+1) ) ; if( !subv_realloc ) { free(subv); fprintf(stderr,"** nifti_get_intlist: failed realloc of %" PRId64 " ints\n", nout+1); return NULL; } subv = subv_realloc; subv[0] = nout ; subv[nout] = ibot ; if( ISEND(str[ipos]) ) break ; /* done */ ipos++ ; continue ; /* re-start loop at next sub-selector */ } /**- otherwise, must have '..' or '-' as next inputs */ if( str[ipos] == '-' ){ ipos++ ; } else if( str[ipos] == '.' && str[ipos+1] == '.' ){ ipos++ ; ipos++ ; } else { fprintf(stderr,"** NIFTI ERROR: index list syntax is bad: '%s'\n", str+ipos) ; free(subv) ; return NULL ; } /**- get ending value for loop now */ if( str[ipos] == '$' ){ /* special case */ itop = nvals-1 ; ipos++ ; } else { /* decode an integer */ itop = strtoll( str+ipos , &cpt , 10 ) ; if( itop < 0 ){ fprintf(stderr,"** NIFTI ERROR: index %" PRId64 " is out of range 0..%" PRId64 "\n", itop,nvals-1) ; free(subv) ; return NULL ; } if( itop >= nvals ){ fprintf(stderr,"** NIFTI ERROR: index %" PRId64 " is out of range 0..%" PRId64 "\n", itop,nvals-1) ; free(subv) ; return NULL ; } nused = (cpt-(str+ipos)) ; if( itop == 0 && nused == 0 ){ fprintf(stderr,"** NIFTI: index list syntax error '%s'\n", str+ipos) ; free(subv) ; return NULL ; } ipos += nused ; } /**- set default loop step */ istep = (ibot <= itop) ? 1 : -1 ; while( isspace((int) str[ipos]) ) ipos++ ; /* skip blanks */ /**- check if we have a non-default loop step */ if( str[ipos] == '(' ){ /* decode an integer */ ipos++ ; istep = strtoll( str+ipos , &cpt , 10 ) ; if( istep == 0 ){ fprintf(stderr,"** NIFTI ERROR: index loop step is 0!\n") ; free(subv) ; return NULL ; } nused = (cpt-(str+ipos)) ; ipos += nused ; if( str[ipos] == ')' ) ipos++ ; if( (ibot-itop)*istep > 0 ){ fprintf(stderr,"** NIFTI WARNING: index list '%" PRId64 "..%" PRId64 "(%" PRId64 ")' means nothing\n", ibot,itop,istep ) ; } } /**- add values to output */ for( ii=ibot ; (ii-itop)*istep <= 0 ; ii += istep ){ nout++ ; subv_realloc = (int64_t *)realloc( (char *)subv , sizeof(int64_t)*(nout+1) ) ; if( !subv_realloc ) { free(subv); fprintf(stderr,"** nifti_get_intlist: failed realloc of %" PRId64 " ints\n", nout+1); return NULL; } subv = subv_realloc; subv[0] = nout ; subv[nout] = ii ; } /**- check if we have a comma to skip over */ while( isspace((int) str[ipos]) ) ipos++ ; /* skip blanks */ if( str[ipos] == ',' ) ipos++ ; /* skip commas */ } /* end of loop through selector string */ if( g_opts.debug > 1 ) { fprintf(stderr,"+d int_list (vals = %" PRId64 "): ", subv[0]); for( ii = 1; ii <= subv[0]; ii++ ) fprintf(stderr,"%" PRId64 " ", subv[ii]); fputc('\n',stderr); } if( subv[0] == 0 ){ free(subv); subv = NULL; } return subv ; } /*! a 32-bit version of nifti_get_int64list */ int * nifti_get_intlist( int nvals , const char * str ) { int *ilist=NULL; int64_t *i64list=NULL, nints, index; i64list = nifti_get_int64list((int64_t)nvals, str); if( !i64list ) return NULL; /* check that the length is between 1 and INT_MAX */ nints = i64list[0]; if( nints <= 0 ) { free(i64list); return NULL; } if( nints > INT_MAX ) { fprintf(stderr,"** nifti_get_intlist: %" PRId64 " ints is too long for 32-bits\n", nints); free(i64list); return NULL; } /* have a valid result, copy as ints */ ilist = (int *)malloc((nints+1) * sizeof(int)); if( !ilist ) { fprintf(stderr,"** nifti_get_intlist: failed to alloc %" PRId64 " ints\n", nints); free(i64list); return NULL; } /* copy list, including length at index 0 */ for( index=0; index <= nints; index++ ) { if( i64list[index] > INT_MAX ) { fprintf(stderr,"** nifti_get_intlist: value %" PRId64 " too big for 32-bits\n", i64list[index]); free(ilist); free(i64list); return NULL; } ilist[index] = (int)i64list[index]; } free(i64list); return ilist; } /*---------------------------------------------------------------------*/ /*! Given a NIFTI_TYPE string, such as "NIFTI_TYPE_INT16", return the * corresponding integral type code. The type code is the macro * value defined in nifti1.h. *//*-------------------------------------------------------------------*/ int nifti_datatype_from_string( const char * name ) { int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int c; if( !name ) return DT_UNKNOWN; for( c = tablen-1; c > 0; c-- ) if( !strcmp(name, nifti_type_list[c].name) ) break; return nifti_type_list[c].type; } /*---------------------------------------------------------------------*/ /*! Given a NIFTI_TYPE value, such as NIFTI_TYPE_INT16, return the * corresponding macro label as a string. The dtype code is the * macro value defined in nifti1.h. *//*-------------------------------------------------------------------*/ const char * nifti_datatype_to_string( int dtype ) { int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int c; for( c = tablen-1; c > 0; c-- ) if( nifti_type_list[c].type == dtype ) break; return nifti_type_list[c].name; } /*---------------------------------------------------------------------*/ /*! Determine whether dtype is a valid NIFTI_TYPE. * * DT_UNKNOWN is considered invalid * * The only difference 'for_nifti' makes is that DT_BINARY * should be invalid for a NIfTI dataset. *//*-------------------------------------------------------------------*/ int nifti_datatype_is_valid( int dtype, int for_nifti ) { int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int c; /* special case */ if( for_nifti && dtype == DT_BINARY ) return 0; for( c = tablen-1; c > 0; c-- ) if( nifti_type_list[c].type == dtype ) return 1; return 0; } /*---------------------------------------------------------------------*/ /*! Only as a test, verify that the new nifti_type_list table matches * the the usage of nifti_datatype_sizes (which could be changed to * use the table, if there were interest). * * return the number of errors (so 0 is success, as usual) *//*-------------------------------------------------------------------*/ int nifti_test_datatype_sizes(int verb) { int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int nbyper, ssize; int c, errs = 0; for( c = 0; c < tablen; c++ ) { nbyper = ssize = -1; nifti_datatype_sizes(nifti_type_list[c].type, &nbyper, &ssize); if( nbyper < 0 || ssize < 0 || nbyper != nifti_type_list[c].nbyper || ssize != nifti_type_list[c].swapsize ) { if( verb || g_opts.debug > 2 ) fprintf(stderr, "** NIFTI type mismatch: " "%s, %d, %d, %d : %d, %d\n", nifti_type_list[c].name, nifti_type_list[c].type, nifti_type_list[c].nbyper, nifti_type_list[c].swapsize, nbyper, ssize); errs++; } } if( errs ) fprintf(stderr,"** nifti_test_datatype_sizes: found %d errors\n",errs); else if( verb || g_opts.debug > 1 ) fprintf(stderr,"-- nifti_test_datatype_sizes: all OK\n"); return errs; } /*---------------------------------------------------------------------*/ /*! Display the nifti_type_list table. * * if which == 1 : display DT_* * if which == 2 : display NIFTI_TYPE* * else : display all *//*-------------------------------------------------------------------*/ int nifti_disp_type_list( int which ) { const char * style; int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int lwhich, c; if ( which == 1 ){ lwhich = 1; style = "DT_"; } else if( which == 2 ){ lwhich = 2; style = "NIFTI_TYPE_"; } else { lwhich = 3; style = "ALL"; } printf("nifti_type_list entries (%s) :\n" " name type nbyper swapsize\n" " --------------------- ---- ------ --------\n", style); for( c = 0; c < tablen; c++ ) if( (lwhich & 1 && nifti_type_list[c].name[0] == 'D') || (lwhich & 2 && nifti_type_list[c].name[0] == 'N') ) printf(" %-22s %5d %3d %5d\n", nifti_type_list[c].name, nifti_type_list[c].type, nifti_type_list[c].nbyper, nifti_type_list[c].swapsize); return 0; } nifti_clib-3.0.1/nifti2/nifti2_io.h000066400000000000000000001055131371325713600170600ustar00rootroot00000000000000/** \file nifti2_io.h \brief Data structures for using nifti2_io API. - Written by Bob Cox, SSCC NIMH - Revisions by Rick Reynolds, SSCC NIMH */ #ifndef _NIFTI2_IO_HEADER_ #define _NIFTI2_IO_HEADER_ #include #include #include #include #include #include #include #ifndef DONT_INCLUDE_ANALYZE_STRUCT #define DONT_INCLUDE_ANALYZE_STRUCT /*** not needed herein ***/ #endif #include "nifti1.h" /*** NIFTI-1 header specification ***/ #include "nifti2.h" /*** NIFTI-2 header specification ***/ #include /*=================*/ #ifdef __cplusplus extern "C" { #endif /*=================*/ /*****===================================================================*****/ /***** File nifti2_io.h == Declarations for nifti2_io.c *****/ /*****...................................................................*****/ /***** This code is a modification of nifti1_io.h. *****/ /*****...................................................................*****/ /***** This code is released to the public domain. *****/ /*****...................................................................*****/ /***** Author: Robert W Cox, SSCC/DIRP/NIMH/NIH/DHHS/USA/EARTH *****/ /***** Date: August 2003 *****/ /*****...................................................................*****/ /***** Neither the National Institutes of Health (NIH), nor any of its *****/ /***** employees imply any warranty of usefulness of this software for *****/ /***** any purpose, and do not assume any liability for damages, *****/ /***** incidental or otherwise, caused by any use of this document. *****/ /*****===================================================================*****/ /* ...................................................................... Modified by: Mark Jenkinson (FMRIB Centre, University of Oxford, UK) Date: July/August 2004 Mainly adding low-level IO and changing things to allow gzipped files to be read and written Full backwards compatability should have been maintained ...................................................................... Modified by: Rick Reynolds (SSCC/DIRP/NIMH, National Institutes of Health) Date: December 2004 Modified and added many routines for I/O, particularly involving extensions and nifti_brick_list. ...................................................................... Modified by: Rick Reynolds (SSCC/DIRP/NIMH, National Institutes of Health) Date: August 2013 Converted to be based on nifti_2_header. ** NOT BACKWARD COMPATABLE ** These routines will read/write both NIFTI-1 and NIFTI-2 image files, but modification to the _calling_ routies is necessary, since: a. the main nifti_image type has changed (to nifti2_image) b. some image field types have been altered (to have larger size) c. some routines have been changed to apply to multiple NIFTI types */ /********************** Some sample data structures **************************/ typedef struct { /** 4x4 matrix struct **/ float m[4][4] ; } mat44 ; typedef struct { /** 3x3 matrix struct **/ float m[3][3] ; } mat33 ; typedef struct { /** 4x4 matrix struct (double) **/ double m[4][4] ; } nifti_dmat44 ; typedef struct { /** 3x3 matrix struct (double) **/ double m[3][3] ; } nifti_dmat33 ; /*...........................................................................*/ /*! \enum analyze_75_orient_code * \brief Old-style analyze75 orientation * codes. */ typedef enum _analyze75_orient_code { a75_transverse_unflipped = 0, a75_coronal_unflipped = 1, a75_sagittal_unflipped = 2, a75_transverse_flipped = 3, a75_coronal_flipped = 4, a75_sagittal_flipped = 5, a75_orient_unknown = 6 } analyze_75_orient_code; /*! \struct nifti_image \brief High level data structure for open nifti datasets in the nifti2_io API. Note that this structure is not part of the nifti2 format definition; it is used to implement one API for reading/writing datasets in the nifti1 or nifti2 formats. Field types changed for NIFTI-2 (note: ALL floats to doubles): nx, ny, ..., nw, dim, nvox, dx, dy, ..., dw, pixdim, scl_slope, scl_inter, cal_min, cal_max, slice_start, slice_end, slice_duration, quatern_b,c,d, qoffset_x,y,z, qfac, qto_xyz,ijk, sto_xyz,ijk, toffset, intent_p1,2,3, iname_offset */ typedef struct { /*!< Image storage struct **/ int64_t ndim ; /*!< last dimension greater than 1 (1..7) */ int64_t nx ; /*!< dimensions of grid array */ int64_t ny ; /*!< dimensions of grid array */ int64_t nz ; /*!< dimensions of grid array */ int64_t nt ; /*!< dimensions of grid array */ int64_t nu ; /*!< dimensions of grid array */ int64_t nv ; /*!< dimensions of grid array */ int64_t nw ; /*!< dimensions of grid array */ int64_t dim[8] ; /*!< dim[0]=ndim, dim[1]=nx, etc. */ int64_t nvox ; /*!< number of voxels = nx*ny*nz*...*nw */ int nbyper ; /*!< bytes per voxel, matches datatype */ int datatype ; /*!< type of data in voxels: DT_* code */ double dx ; /*!< grid spacings */ double dy ; /*!< grid spacings */ double dz ; /*!< grid spacings */ double dt ; /*!< grid spacings */ double du ; /*!< grid spacings */ double dv ; /*!< grid spacings */ double dw ; /*!< grid spacings */ double pixdim[8] ; /*!< pixdim[1]=dx, etc. */ double scl_slope ; /*!< scaling parameter - slope */ double scl_inter ; /*!< scaling parameter - intercept */ double cal_min ; /*!< calibration parameter, minimum */ double cal_max ; /*!< calibration parameter, maximum */ int qform_code ; /*!< codes for (x,y,z) space meaning */ int sform_code ; /*!< codes for (x,y,z) space meaning */ int freq_dim ; /*!< indexes (1,2,3, or 0) for MRI */ int phase_dim ; /*!< directions in dim[]/pixdim[] */ int slice_dim ; /*!< directions in dim[]/pixdim[] */ int slice_code ; /*!< code for slice timing pattern */ int64_t slice_start ; /*!< index for start of slices */ int64_t slice_end ; /*!< index for end of slices */ double slice_duration ; /*!< time between individual slices */ /*! quaternion transform parameters [when writing a dataset, these are used for qform, NOT qto_xyz] */ double quatern_b , quatern_c , quatern_d , qoffset_x , qoffset_y , qoffset_z , qfac ; nifti_dmat44 qto_xyz ; /*!< qform: transform (i,j,k) to (x,y,z) */ nifti_dmat44 qto_ijk ; /*!< qform: transform (x,y,z) to (i,j,k) */ nifti_dmat44 sto_xyz ; /*!< sform: transform (i,j,k) to (x,y,z) */ nifti_dmat44 sto_ijk ; /*!< sform: transform (x,y,z) to (i,j,k) */ double toffset ; /*!< time coordinate offset */ int xyz_units ; /*!< dx,dy,dz units: NIFTI_UNITS_* code */ int time_units ; /*!< dt units: NIFTI_UNITS_* code */ int nifti_type ; /*!< see NIFTI_FTYPE_* codes, below: 0==ANALYZE, 1==NIFTI-1 (1 file), 2==NIFTI-1 (2 files), 3==NIFTI-ASCII (1 file) 4==NIFTI-2 (1 file), 5==NIFTI-2 (2 files) */ int intent_code ; /*!< statistic type (or something) */ double intent_p1 ; /*!< intent parameters */ double intent_p2 ; /*!< intent parameters */ double intent_p3 ; /*!< intent parameters */ char intent_name[16] ; /*!< optional description of intent data */ char descrip[80] ; /*!< optional text to describe dataset */ char aux_file[24] ; /*!< auxiliary filename */ char *fname ; /*!< header filename (.hdr or .nii) */ char *iname ; /*!< image filename (.img or .nii) */ int64_t iname_offset ; /*!< offset into iname where data starts */ int swapsize ; /*!< swap unit in image data (might be 0) */ int byteorder ; /*!< byte order on disk (MSB_ or LSB_FIRST) */ void *data ; /*!< pointer to data: nbyper*nvox bytes */ int num_ext ; /*!< number of extensions in ext_list */ nifti1_extension * ext_list ; /*!< array of extension structs (with data) */ analyze_75_orient_code analyze75_orient; /*!< for old analyze files, orient */ } nifti_image ; /* allow clarity */ typedef nifti_image nifti2_image; typedef struct { int ndim ; /*!< last dimension greater than 1 (1..7) */ int nx ; /*!< dimensions of grid array */ int ny ; /*!< dimensions of grid array */ int nz ; /*!< dimensions of grid array */ int nt ; /*!< dimensions of grid array */ int nu ; /*!< dimensions of grid array */ int nv ; /*!< dimensions of grid array */ int nw ; /*!< dimensions of grid array */ int dim[8] ; /*!< dim[0]=ndim, dim[1]=nx, etc. */ int64_t nvox ; /*!< number of voxels = nx*ny*nz*...*nw */ int nbyper ; /*!< bytes per voxel, matches datatype */ int datatype ; /*!< type of data in voxels: DT_* code */ float dx ; /*!< grid spacings */ float dy ; /*!< grid spacings */ float dz ; /*!< grid spacings */ float dt ; /*!< grid spacings */ float du ; /*!< grid spacings */ float dv ; /*!< grid spacings */ float dw ; /*!< grid spacings */ float pixdim[8] ; /*!< pixdim[1]=dx, etc. */ float scl_slope ; /*!< scaling parameter - slope */ float scl_inter ; /*!< scaling parameter - intercept */ float cal_min ; /*!< calibration parameter, minimum */ float cal_max ; /*!< calibration parameter, maximum */ int qform_code ; /*!< codes for (x,y,z) space meaning */ int sform_code ; /*!< codes for (x,y,z) space meaning */ int freq_dim ; /*!< indexes (1,2,3, or 0) for MRI */ int phase_dim ; /*!< directions in dim[]/pixdim[] */ int slice_dim ; /*!< directions in dim[]/pixdim[] */ int slice_code ; /*!< code for slice timing pattern */ int slice_start ; /*!< index for start of slices */ int slice_end ; /*!< index for end of slices */ float slice_duration ; /*!< time between individual slices */ /*! quaternion transform parameters [when writing a dataset, these are used for qform, NOT qto_xyz] */ float quatern_b , quatern_c , quatern_d , qoffset_x , qoffset_y , qoffset_z , qfac ; mat44 qto_xyz ; /*!< qform: transform (i,j,k) to (x,y,z) */ mat44 qto_ijk ; /*!< qform: transform (x,y,z) to (i,j,k) */ mat44 sto_xyz ; /*!< sform: transform (i,j,k) to (x,y,z) */ mat44 sto_ijk ; /*!< sform: transform (x,y,z) to (i,j,k) */ float toffset ; /*!< time coordinate offset */ int xyz_units ; /*!< dx,dy,dz units: NIFTI_UNITS_* code */ int time_units ; /*!< dt units: NIFTI_UNITS_* code */ int nifti_type ; /*!< 0==ANALYZE, 1==NIFTI-1 (1 file), 2==NIFTI-1 (2 files), 3==NIFTI-ASCII (1 file) */ int intent_code ; /*!< statistic type (or something) */ float intent_p1 ; /*!< intent parameters */ float intent_p2 ; /*!< intent parameters */ float intent_p3 ; /*!< intent parameters */ char intent_name[16] ; /*!< optional description of intent data */ char descrip[80] ; /*!< optional text to describe dataset */ char aux_file[24] ; /*!< auxiliary filename */ char *fname ; /*!< header filename (.hdr or .nii) */ char *iname ; /*!< image filename (.img or .nii) */ int iname_offset ; /*!< offset into iname where data starts */ int swapsize ; /*!< swap unit in image data (might be 0) */ int byteorder ; /*!< byte order on disk (MSB_ or LSB_FIRST) */ void *data ; /*!< pointer to data: nbyper*nvox bytes */ int num_ext ; /*!< number of extensions in ext_list */ nifti1_extension * ext_list ; /*!< array of extension structs (with data) */ analyze_75_orient_code analyze75_orient; /*!< for old analyze files, orient */ } nifti1_image ; /* struct for return from nifti_image_read_bricks() */ typedef struct { int64_t nbricks; /* the number of allocated pointers in 'bricks' */ int64_t bsize; /* the length of each data block, in bytes */ void ** bricks; /* array of pointers to data blocks */ } nifti_brick_list; /*****************************************************************************/ /*------------------ NIfTI version of ANALYZE 7.5 structure -----------------*/ /* (based on fsliolib/dbh.h, but updated for version 7.5) */ typedef struct { /* header info fields - describes the header overlap with NIfTI */ /* ------------------ */ int sizeof_hdr; /* 0 + 4 same */ char data_type[10]; /* 4 + 10 same */ char db_name[18]; /* 14 + 18 same */ int extents; /* 32 + 4 same */ short int session_error; /* 36 + 2 same */ char regular; /* 38 + 1 same */ char hkey_un0; /* 39 + 1 40 bytes */ /* image dimension fields - describes image sizes */ short int dim[8]; /* 0 + 16 same */ short int unused8; /* 16 + 2 intent_p1... */ short int unused9; /* 18 + 2 ... */ short int unused10; /* 20 + 2 intent_p2... */ short int unused11; /* 22 + 2 ... */ short int unused12; /* 24 + 2 intent_p3... */ short int unused13; /* 26 + 2 ... */ short int unused14; /* 28 + 2 intent_code */ short int datatype; /* 30 + 2 same */ short int bitpix; /* 32 + 2 same */ short int dim_un0; /* 34 + 2 slice_start */ float pixdim[8]; /* 36 + 32 same */ float vox_offset; /* 68 + 4 same */ float funused1; /* 72 + 4 scl_slope */ float funused2; /* 76 + 4 scl_inter */ float funused3; /* 80 + 4 slice_end, */ /* slice_code, */ /* xyzt_units */ float cal_max; /* 84 + 4 same */ float cal_min; /* 88 + 4 same */ float compressed; /* 92 + 4 slice_duration */ float verified; /* 96 + 4 toffset */ int glmax,glmin; /* 100 + 8 108 bytes */ /* data history fields - optional */ char descrip[80]; /* 0 + 80 same */ char aux_file[24]; /* 80 + 24 same */ char orient; /* 104 + 1 NO GOOD OVERLAP */ char originator[10]; /* 105 + 10 FROM HERE DOWN... */ char generated[10]; /* 115 + 10 */ char scannum[10]; /* 125 + 10 */ char patient_id[10]; /* 135 + 10 */ char exp_date[10]; /* 145 + 10 */ char exp_time[10]; /* 155 + 10 */ char hist_un0[3]; /* 165 + 3 */ int views; /* 168 + 4 */ int vols_added; /* 172 + 4 */ int start_field; /* 176 + 4 */ int field_skip; /* 180 + 4 */ int omax, omin; /* 184 + 8 */ int smax, smin; /* 192 + 8 200 bytes */ } nifti_analyze75; /* total: 348 bytes */ /*****************************************************************************/ /*--------------- Prototypes of functions defined in this file --------------*/ char const * nifti_datatype_string ( int dt ) ; char const *nifti_units_string ( int uu ) ; char const *nifti_intent_string ( int ii ) ; char const *nifti_xform_string ( int xx ) ; char const *nifti_slice_string ( int ss ) ; char const *nifti_orientation_string( int ii ) ; int nifti_is_inttype( int dt ) ; mat44 nifti_mat44_inverse ( mat44 R ) ; mat44 nifti_mat44_mul ( mat44 A , mat44 B ); nifti_dmat44 nifti_dmat44_inverse( nifti_dmat44 R ) ; int nifti_mat44_to_dmat44(mat44 * fm, nifti_dmat44 * dm); int nifti_dmat44_to_mat44(nifti_dmat44 * dm, mat44 * fm); nifti_dmat44 nifti_dmat44_mul ( nifti_dmat44 A , nifti_dmat44 B ); nifti_dmat33 nifti_dmat33_inverse( nifti_dmat33 R ) ; nifti_dmat33 nifti_dmat33_polar ( nifti_dmat33 A ) ; double nifti_dmat33_rownorm( nifti_dmat33 A ) ; double nifti_dmat33_colnorm( nifti_dmat33 A ) ; double nifti_dmat33_determ ( nifti_dmat33 R ) ; nifti_dmat33 nifti_dmat33_mul ( nifti_dmat33 A , nifti_dmat33 B ) ; mat33 nifti_mat33_inverse( mat33 R ) ; mat33 nifti_mat33_polar ( mat33 A ) ; float nifti_mat33_rownorm( mat33 A ) ; float nifti_mat33_colnorm( mat33 A ) ; float nifti_mat33_determ ( mat33 R ) ; mat33 nifti_mat33_mul ( mat33 A , mat33 B ) ; void nifti_swap_2bytes ( int64_t n , void *ar ) ; void nifti_swap_4bytes ( int64_t n , void *ar ) ; void nifti_swap_8bytes ( int64_t n , void *ar ) ; void nifti_swap_16bytes( int64_t n , void *ar ) ; void nifti_swap_Nbytes ( int64_t n , int siz , void *ar ) ; int nifti_datatype_is_valid (int dtype, int for_nifti); int nifti_datatype_from_string (const char * name); const char * nifti_datatype_to_string(int dtype); int nifti_header_version (const char * buf, size_t nbytes); int64_t nifti_get_filesize( const char *pathname ) ; void swap_nifti_header ( void * hdr , int ni_ver ) ; void old_swap_nifti_header( struct nifti_1_header *h , int is_nifti ); void nifti_swap_as_analyze( nifti_analyze75 *h ); void nifti_swap_as_nifti1( nifti_1_header *h ); void nifti_swap_as_nifti2( nifti_2_header *h ); /* main read/write routines */ nifti_image *nifti_image_read_bricks(const char *hname , int64_t nbricks, const int64_t *blist, nifti_brick_list * NBL); int nifti_image_load_bricks(nifti_image *nim , int64_t nbricks, const int64_t *blist, nifti_brick_list * NBL); void nifti_free_NBL( nifti_brick_list * NBL ); nifti_image *nifti_image_read ( const char *hname , int read_data); int nifti_image_load ( nifti_image *nim); void nifti_image_unload ( nifti_image *nim); void nifti_image_free ( nifti_image *nim); int64_t nifti_read_collapsed_image( nifti_image * nim, const int64_t dims[8], void ** data); int64_t nifti_read_subregion_image(nifti_image *nim, const int64_t *start_index, const int64_t *region_size, void ** data); void nifti_image_write ( nifti_image * nim ) ; void nifti_image_write_bricks(nifti_image * nim, const nifti_brick_list * NBL); void nifti_image_infodump( const nifti_image * nim ) ; void nifti_disp_lib_hist( int ver ) ; /* to display library history */ void nifti_disp_lib_version( void ) ; /* to display library version */ int nifti_disp_matrix_orient( const char * mesg, nifti_dmat44 mat ); int nifti_disp_type_list( int which ); char * nifti_image_to_ascii ( const nifti_image * nim ) ; nifti_image *nifti_image_from_ascii( const char * str, int * bytes_read ) ; int64_t nifti_get_volsize(const nifti_image *nim) ; /* basic file operations */ int nifti_set_filenames(nifti_image * nim, const char * prefix, int check, int set_byte_order); char * nifti_makehdrname (const char * prefix, int nifti_type, int check, int comp); char * nifti_makeimgname (const char * prefix, int nifti_type, int check, int comp); int is_nifti_file (const char *hname); char * nifti_find_file_extension(const char * name); int nifti_is_complete_filename(const char* fname); int nifti_validfilename(const char* fname); int disp_nifti_1_header(const char * info, const nifti_1_header * hp ) ; int disp_nifti_2_header( const char * info, const nifti_2_header * hp ) ; void nifti_set_debug_level( int level ) ; void nifti_set_skip_blank_ext( int skip ) ; void nifti_set_allow_upper_fext( int allow ) ; int nifti_get_alter_cifti( void ); void nifti_set_alter_cifti( int alter_cifti ); int nifti_alter_cifti_dims(nifti_image * nim); int valid_nifti_brick_list(nifti_image * nim , int64_t nbricks, const int64_t * blist, int disp_error); /* znzFile operations */ znzFile nifti_image_open(const char * hname, char * opts, nifti_image ** nim); znzFile nifti_image_write_hdr_img(nifti_image *nim, int write_data, const char* opts); znzFile nifti_image_write_hdr_img2( nifti_image *nim , int write_opts , const char* opts, znzFile imgfile, const nifti_brick_list * NBL); int64_t nifti_read_buffer(znzFile fp, void* dataptr, int64_t ntot, nifti_image *nim); int nifti_write_all_data(znzFile fp, nifti_image * nim, const nifti_brick_list * NBL); int64_t nifti_write_buffer(znzFile fp, const void * buffer, int64_t numbytes); nifti_image *nifti_read_ascii_image(znzFile fp, const char *fname, int flen, int read_data); znzFile nifti_write_ascii_image(nifti_image *nim, const nifti_brick_list * NBL, const char * opts, int write_data, int leave_open); void nifti_datatype_sizes( int datatype , int *nbyper, int *swapsize ) ; void nifti_dmat44_to_quatern(nifti_dmat44 R , double *qb, double *qc, double *qd, double *qx, double *qy, double *qz, double *dx, double *dy, double *dz, double *qfac); nifti_dmat44 nifti_quatern_to_dmat44( double qb, double qc, double qd, double qx, double qy, double qz, double dx, double dy, double dz, double qfac ); nifti_dmat44 nifti_make_orthog_dmat44( double r11, double r12, double r13 , double r21, double r22, double r23 , double r31, double r32, double r33 ) ; void nifti_mat44_to_quatern( mat44 R , float *qb, float *qc, float *qd, float *qx, float *qy, float *qz, float *dx, float *dy, float *dz, float *qfac ) ; mat44 nifti_quatern_to_mat44( float qb, float qc, float qd, float qx, float qy, float qz, float dx, float dy, float dz, float qfac ); mat44 nifti_make_orthog_mat44( float r11, float r12, float r13 , float r21, float r22, float r23 , float r31, float r32, float r33 ) ; int nifti_short_order(void) ; /* CPU byte order */ /* Orientation codes that might be returned from nifti_mat44_to_orientation().*/ #define NIFTI_L2R 1 /* Left to Right */ #define NIFTI_R2L 2 /* Right to Left */ #define NIFTI_P2A 3 /* Posterior to Anterior */ #define NIFTI_A2P 4 /* Anterior to Posterior */ #define NIFTI_I2S 5 /* Inferior to Superior */ #define NIFTI_S2I 6 /* Superior to Inferior */ void nifti_mat44_to_orientation( mat44 R , int *icod, int *jcod, int *kcod ) ; void nifti_dmat44_to_orientation( nifti_dmat44 R, int *icod, int *jcod, int *kcod ) ; /*--------------------- Low level IO routines ------------------------------*/ char * nifti_findhdrname (const char* fname); char * nifti_findimgname (const char* fname , int nifti_type); int nifti_is_gzfile (const char* fname); char * nifti_makebasename(const char* fname); /* other routines */ int nifti_convert_nim2n1hdr(const nifti_image* nim, nifti_1_header * hdr); int nifti_convert_nim2n2hdr(const nifti_image* nim, nifti_2_header * hdr); nifti_1_header * nifti_make_new_n1_header(const int64_t arg_dims[], int arg_dtype); nifti_2_header * nifti_make_new_n2_header(const int64_t arg_dims[], int arg_dtype); void * nifti_read_header(const char *hname, int *nver, int check); nifti_1_header * nifti_read_n1_hdr(const char *hname, int *swapped, int check); nifti_2_header * nifti_read_n2_hdr(const char *hname, int *swapped, int check); nifti_image * nifti_copy_nim_info(const nifti_image * src); nifti_image * nifti_make_new_nim(const int64_t dims[], int datatype, int data_fill); nifti_image * nifti_simple_init_nim(void); nifti_image * nifti_convert_n1hdr2nim(nifti_1_header nhdr,const char *fname); nifti_image * nifti_convert_n2hdr2nim(nifti_2_header nhdr,const char *fname); int nifti_looks_like_cifti(nifti_image * nim); int nifti_hdr1_looks_good (const nifti_1_header * hdr); int nifti_hdr2_looks_good (const nifti_2_header * hdr); int nifti_is_valid_datatype (int dtype); int nifti_is_valid_ecode (int ecode); int nifti_nim_is_valid (nifti_image * nim, int complain); int nifti_nim_has_valid_dims (nifti_image * nim, int complain); int is_valid_nifti_type (int nifti_type); int nifti_test_datatype_sizes (int verb); int nifti_type_and_names_match (nifti_image * nim, int show_warn); int nifti_update_dims_from_array(nifti_image * nim); void nifti_set_iname_offset (nifti_image *nim, int nifti_ver); int nifti_set_type_from_names (nifti_image * nim); int nifti_add_extension(nifti_image * nim, const char * data, int len, int ecode ); int nifti_compiled_with_zlib (void); int nifti_copy_extensions (nifti_image *nim_dest,const nifti_image *nim_src); int nifti_free_extensions (nifti_image *nim); int64_t * nifti_get_int64list(int64_t nvals , const char *str); int * nifti_get_intlist (int nvals , const char *str); char * nifti_strdup (const char *str); int valid_nifti_extensions(const nifti_image *nim); int nifti_valid_header_size(int ni_ver, int whine); /*-------------------- Some C convenience macros ----------------------------*/ /* NIfTI-1.1 extension codes: see http://nifti.nimh.nih.gov/nifti-1/documentation/faq#Q21 */ #define NIFTI_ECODE_IGNORE 0 /* changed from UNKNOWN, 29 June 2005 */ #define NIFTI_ECODE_DICOM 2 /* intended for raw DICOM attributes */ #define NIFTI_ECODE_AFNI 4 /* Robert W Cox: rwcox@nih.gov https://afni.nimh.nih.gov/afni */ #define NIFTI_ECODE_COMMENT 6 /* plain ASCII text only */ #define NIFTI_ECODE_XCEDE 8 /* David B Keator: dbkeator@uci.edu http://www.nbirn.net/Resources /Users/Applications/ /xcede/index.htm */ #define NIFTI_ECODE_JIMDIMINFO 10 /* Mark A Horsfield: mah5@leicester.ac.uk http://someplace/something */ #define NIFTI_ECODE_WORKFLOW_FWDS 12 /* Kate Fissell: fissell@pitt.edu http://kraepelin.wpic.pitt.edu /~fissell/NIFTI_ECODE_WORKFLOW_FWDS /NIFTI_ECODE_WORKFLOW_FWDS.html */ #define NIFTI_ECODE_FREESURFER 14 /* http://surfer.nmr.mgh.harvard.edu */ #define NIFTI_ECODE_PYPICKLE 16 /* embedded Python objects http://niftilib.sourceforge.net /pynifti */ /* LONI MiND codes: http://www.loni.ucla.edu/twiki/bin/view/Main/MiND */ #define NIFTI_ECODE_MIND_IDENT 18 /* Vishal Patel: vishal.patel@ucla.edu*/ #define NIFTI_ECODE_B_VALUE 20 #define NIFTI_ECODE_SPHERICAL_DIRECTION 22 #define NIFTI_ECODE_DT_COMPONENT 24 #define NIFTI_ECODE_SHC_DEGREEORDER 26 /* end LONI MiND codes */ #define NIFTI_ECODE_VOXBO 28 /* Dan Kimberg: www.voxbo.org */ #define NIFTI_ECODE_CARET 30 /* John Harwell: john@brainvis.wustl.edu http://brainvis.wustl.edu/wiki /index.php/Caret:Documentation :CaretNiftiExtension */ #define NIFTI_ECODE_CIFTI 32 /* CIFTI-2_Main_FINAL_1March2014.pdf */ #define NIFTI_ECODE_VARIABLE_FRAME_TIMING 34 /* 36 is currently unassigned, waiting on NIFTI_ECODE_AGILENT_PROCPAR */ #define NIFTI_ECODE_EVAL 38 /* Munster University Hospital */ /* http://www.mathworks.com/matlabcentral/fileexchange/42997-dicom-to-nifti-converter */ #define NIFTI_ECODE_MATLAB 40 /* MATLAB extension */ /* Quantiphyse extension https://quantiphyse.readthedocs.io/en/latest/advanced/nifti_extension.html*/ #define NIFTI_ECODE_QUANTIPHYSE 42 /* Quantiphyse extension */ /* Magnetic Resonance Spectroscopy (MRS) link to come... */ #define NIFTI_ECODE_MRS 44 /* MRS extension */ #define NIFTI_MAX_ECODE 44 /******* maximum extension code *******/ /* nifti_type file codes */ #define NIFTI_FTYPE_ANALYZE 0 /* old ANALYZE */ #define NIFTI_FTYPE_NIFTI1_1 1 /* NIFTI-1 */ #define NIFTI_FTYPE_NIFTI1_2 2 #define NIFTI_FTYPE_ASCII 3 #define NIFTI_FTYPE_NIFTI2_1 4 /* NIFTI-2 */ #define NIFTI_FTYPE_NIFTI2_2 5 #define NIFTI_MAX_FTYPE 5 /* this should match the maximum code */ /*------------------------------------------------------------------------*/ /*-- the rest of these apply only to nifti2_io.c, check for _NIFTI2_IO_C_ */ #ifdef _NIFTI2_IO_C_ typedef struct { int debug; /*!< debug level for status reports */ int skip_blank_ext; /*!< skip extender if no extensions */ int allow_upper_fext; /*!< allow uppercase file extensions */ int alter_cifti; /*!< convert CIFTI dimensions */ } nifti_global_options; typedef struct { int type; /* should match the NIFTI_TYPE_ #define */ int nbyper; /* bytes per value, matches nifti_image */ int swapsize; /* bytes per swap piece, matches nifti_image */ char const * const name; /* text string to match #define */ } nifti_type_ele; #undef LNI_FERR /* local nifti file error, to be compact and repetative */ #define LNI_FERR(func,msg,file) \ fprintf(stderr,"** ERROR (%s): %s '%s'\n",func,msg,file) #undef swap_2 #undef swap_4 #define swap_2(s) nifti_swap_2bytes(1,&(s)) /* s: 2-byte short; swap in place */ #define swap_4(v) nifti_swap_4bytes(1,&(v)) /* v: 4-byte value; swap in place */ /***** isfinite() is a C99 macro, which is present in many C implementations already *****/ #undef IS_GOOD_FLOAT #undef FIXED_FLOAT #ifdef isfinite /* use isfinite() to check floats/doubles for goodness */ # define IS_GOOD_FLOAT(x) isfinite(x) /* check if x is a "good" float */ # define FIXED_FLOAT(x) (isfinite(x) ? (x) : 0) /* fixed if bad */ #else # define IS_GOOD_FLOAT(x) 1 /* don't check it */ # define FIXED_FLOAT(x) (x) /* don't fix it */ #endif #undef ASSIF /* assign v to *p, if possible */ #define ASSIF(p,v) if( (p)!=NULL ) *(p) = (v) #undef MSB_FIRST #undef LSB_FIRST #undef REVERSE_ORDER #define LSB_FIRST 1 #define MSB_FIRST 2 #define REVERSE_ORDER(x) (3-(x)) /* convert MSB_FIRST <--> LSB_FIRST */ #define LNI_MAX_NIA_EXT_LEN 100000 /* consider a longer extension invalid */ #undef NIFTI_IS_16_BIT_INT #define NIFTI_IS_16_BIT_INT(x) ((x) <= 32767 && (x) >= -32768) #endif /* _NIFTI2_IO_C_ section */ /*------------------------------------------------------------------------*/ /*=================*/ #ifdef __cplusplus } #endif /*=================*/ #endif /* _NIFTI2_IO_HEADER_ */ nifti_clib-3.0.1/nifti2/nifti2_io_version.h000066400000000000000000000013611371325713600206210ustar00rootroot00000000000000/* NOTE: When changing version consider the impact on versions in nifti2_io_version.h nifti1_io_version.h nifticdf_version.h and znzlib.h */ #define NIFTI2_IO_VERSION_MAJOR 2 #define NIFTI2_IO_VERSION_MINOR 1 #define NIFTI2_IO_VERSION_PATCH 0 /* main string macros: NIFTI2_IO_VERSION and NIFTI2_IO_SOURCE_VERSION */ #define NIFTI2_IO_VERSION_TO_STRING(x) NIFTI2_IO_VERSION_TO_STRING0(x) #define NIFTI2_IO_VERSION_TO_STRING0(x) #x #define NIFTI2_IO_VERSION \ NIFTI2_IO_VERSION_TO_STRING(NIFTI2_IO_VERSION_MAJOR) \ "." NIFTI2_IO_VERSION_TO_STRING(NIFTI2_IO_VERSION_MINOR) \ "." NIFTI2_IO_VERSION_TO_STRING(NIFTI2_IO_VERSION_PATCH) #define NIFTI2_IO_SOURCE_VERSION "NIFTI2_IO version " NIFTI2_IO_VERSION nifti_clib-3.0.1/nifti2/nifti_regress_test/000077500000000000000000000000001371325713600207225ustar00rootroot00000000000000nifti_clib-3.0.1/nifti2/nifti_regress_test/@show.diffs000077500000000000000000000011341371325713600230210ustar00rootroot00000000000000#! /usr/bin/env tcsh set ddir = diffs set rdirs = ( results_* ) # verify that there are differences to view if ( $#rdirs < 2 ) then echo cannot proceed, we need at least 2 result directories exit endif # make sure the output directory exists if ( -d $ddir ) then echo removing old diffs \rm -f $ddir/* >& /dev/null else mkdir $ddir if ( ! -d $ddir ) then echo failed to make output directory, $ddir exit endif endif set r1 = $rdirs[1] set r2 = $rdirs[$#rdirs] cd $r2 foreach file (*) echo $file... diff ../$r1/$file $file >& ../$ddir/d.$file end nifti_clib-3.0.1/nifti2/nifti_regress_test/@test000077500000000000000000000033331371325713600217310ustar00rootroot00000000000000#! /usr/bin/env tcsh set ddir = nifti_regress_data set prog = nifti_tool # might allow this to change set grind = 0 # do we run with valgrind? if ( $#argv > 0 ) then if ( "$argv[1]" == "-grind" ) then set grind = 1 else echo "usage: `basename $0` [-grind]" exit endif endif # make sure $prog at least exists # $prog -ver >& /dev/null # if ( $status ) then # echo "missing program '$prog' (needs to be in PATH)" # exit # endif # set date and output dir (based on grind) set date = `date +%Y_%m_%d_%H%M` if ( $grind ) then set odir = vg_results_${prog}_${date} else set odir = results_${prog}_${date} endif # note command files (in commands dir) if ( ! -d commands ) then echo "** failure: missing commands directory" exit endif cd commands ; set cfiles = ( c* ) ; cd .. if ( $#cfiles < 1 ) then echo "** failure: no command files found in 'commands'" exit endif # create the output directory if ( -e $odir ) then echo "** failure: output directory '$odir' already exists" exit endif mkdir $odir if ( $status ) then echo "** failure: output directory '$odir' already exists" exit endif # copy data files into output dir cp $ddir/* $odir cd $odir # now begin the work echo "++ using `which $prog` ..." if ( $grind ) then alias $prog "valgrind --leak-resolution=high --leak-check=full $prog" endif foreach cfile ( $cfiles ) echo -n $cfile ... echo "--------------------------------------------------------" > e.$cfile cat ../commands/$cfile >> e.$cfile echo "" >> e.$cfile echo "--------------------------" >> e.$cfile echo "" >> e.$cfile source ../commands/$cfile >>& e.$cfile # to keep alias echo done end nifti_clib-3.0.1/nifti2/nifti_regress_test/CMakeLists.txt000066400000000000000000000000001371325713600234500ustar00rootroot00000000000000nifti_clib-3.0.1/nifti2/nifti_regress_test/README_regress000066400000000000000000000035341371325713600233410ustar00rootroot00000000000000Background: This is to perform regression testing, which is to say, make sure the software works the same way that it used to. This is not to test new features (see "modify an existing tree" for that). When code has been changed for a certain program that is involved in a regression testing tree, go to that tree, run the test, and make sure that the results have not changed (in any bad way). This is meant to be fast and easy. The test consists of command scripts that were written before. The scripts are executed, and the output is compared with the output of an older execution. The should ususally be identical. --------------------------------------------------------------------------- To perform regression testing, one needs the data (via 'make regress_data'). Given that, only the @test and @show_diffs are needed (sample commands are shown with a preceeding prompt, '> '). 1. Run the regression testing script. It goes through the steps: a. Create a "results" directory, including a timestamp. b. Copy all "data" files into it. c. 'cd' into the "results" directory. d. For each command script in the commands directory, execute it, storing all output text into a file called e."command name". > ./@test 2. To compare against an older execution, run the @show_diffs script. It goes through the steps: a. Make a list of the "results" directories. b. Create a new "diffs" directory. c. Compare files between the newest and oldest "results" dirs: - cd into newest "results" directory - foreach file (*) diff $file ../other.result/$file >& ../diffs/d.$file > ./@show_diffs 3. Look at the sizes of the diff files, or the contents (only expected differences should exist). > ls -l diffs > cat diffs/* nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/000077500000000000000000000000001371325713600244515ustar00rootroot00000000000000nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/bricks_test.sh000077500000000000000000000012351371325713600273250ustar00rootroot00000000000000#!/usr/bin/env bash # - copy some of the sub-bricks of the default stat file, # storing the history (command), and writing to a new 'f4.nii' # - compare these nifti_image structs if [ $# -lt 2 ] then echo Missing nifti tool and Binary directory name exit 1 fi NT=$1 DATA=$2 OUT_DATA=$(dirname ${DATA}) #Need to write to separate directory cd ${OUT_DATA} rm -fr ${DATA}/f4* if ${NT} -keep_hist -cbl -infiles ${DATA}/stat0.nii'[178..$,0,1]' -prefix ${OUT_DATA}/f4 then echo "" else echo "copy sub-bricks failed" fi if ${NT} -diff_nim -infiles ${DATA}/stat0.nii ${OUT_DATA}/f4.nii then echo diff failed '(no diffs found' exit 1 else echo diff succeeded fi exit 0 nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/c21_a_info_test.sh000077500000000000000000000011321371325713600277440ustar00rootroot00000000000000#!/bin/sh if [ $# -lt 2 ] then echo Missing nifti tool and Binary directory name exit 1 fi NT=$1 DATA=$2 OUT_DATA=$(dirname ${DATA}) #Need to write to separate directory cd ${OUT_DATA} # print simple info and terminate echo "============== version, NIFTI version, with zlib" $NT -ver $NT -nifti_ver $NT -with_zlib echo "============== history (NT), NIFTI history" $NT -hist $NT -nifti_hist echo "============== help, datatypes, hdr, nim" $NT -help $NT -help_datatypes $NT -help_datatypes D $NT -help_datatypes N $NT -help_datatypes T $NT -help_hdr1 $NT -help_hdr2 $NT -help_ana $NT -help_nim nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/c21_b_cifti_in.sh000077500000000000000000000100611371325713600275400ustar00rootroot00000000000000#!/bin/sh if [ $# -lt 2 ] then echo Missing nifti tool and Binary directory name exit 1 fi NT=$1 DATA=$2 OUT_DATA=$(dirname ${DATA}) #Need to write to separate directory cd ${OUT_DATA} # note the main input file and prefix for all output files infile=$DATA/Conte69.parcellations_VGD11b.32k_fs_LR.dlabel.nii prefix=out.c21.b rm -f $prefix* # -------------------------------------------------- # display basic nifti info stuff from existing dset if $NT -disp_hdr -infiles ${infile} -debug 3 then echo "=== disp_hdr succeeded" else echo === disp_hdr failed exit 1 fi if $NT -disp_nim -infiles ${infile} -debug 5 then echo "=== disp_nim succeeded" else echo === disp_nim failed exit 1 fi if $NT -disp_hdr2 -infiles ${infile} -debug 3 then echo "=== disp_hdr2 succeeded" else echo === disp_hdr2 failed exit 1 fi # allow failure? if $NT -disp_hdr1 -infiles ${infile} then echo === disp_hdr1 incorrectly succeeded exit 1 else echo === good: disp_hdr1 failed fi if $NT -disp_cext -infiles ${infile} then echo === disp_cext succeeded else echo === disp_cext failed exit 1 fi # display some data if $NT -infiles ${infile} -disp_ci 0 0 0 0 -1 23456 0 then echo === disp_ci succeeded else echo === disp_ci failed exit 1 fi # -------------------------------------------------- # modify an existing dset and compare echo "============== modify an hdr2 field" if $NT -mod_hdr2 -mod_field slice_start 3 -mod_field slice_duration 0.04 \ -infiles ${infile} -prefix ${prefix}.01.a.nii then echo === mod_hdr2 mod_nim succeeded else echo === mod_hdr2 mod_nim failed exit 1 fi echo "============== modify an image field" if $NT -debug 2 -infiles ${prefix}.01.a.nii -prefix ${prefix}.01.b.nia \ -mod_nim -mod_field qform_code 2 -mod_field sform_code 2 then echo === mod_nim succeeded else echo === mod_nim failed exit 1 fi echo "============== collapse 6th (last) dim of CIFTI input, compress output to test znz" if $NT -cci 0 0 0 0 -1 17 0 -infiles ${prefix}.01.a.nii \ -debug 3 -prefix ${prefix}.02.nii.gz then echo === cci succeeded else echo === cci failed exit 1 fi # store result for other commands tfile01=${prefix}.02.nii.gz echo "============== look for subsequent dimension changes (NIFTI types vary)" if $NT -diff_hdr2 -infiles ${infile} ${tfile01} then echo === diff_hdr2 incorrectly succeeded exit 1 else echo === good: diff_hdr2 showed a difference fi echo "============== look for subsequent dim changes (NIFTI types vary)" if $NT -diff_nim -infiles ${infile} ${tfile01} then echo === diff_nim incorrectly succeeded exit 1 else echo === good: diff_nim showed a difference fi echo "============== use volume index select, which requires sorting and selecting" if $NT -copy_brick_list -infiles ${infile}'[2,3,3,3,1]' \ -debug 3 \ -prefix ${prefix}.03.nii then echo === copy_brick_list succeeded else echo === copy_brick_list failed exit 1 fi echo "============== test CAPS file extension" if $NT -mod_hdr2 -mod_field slice_code 2 -infiles ${infile} \ -prefix ${prefix}.04.NII then echo === mod_hdr2 succeeded else echo === mod_hdr2 failed exit 1 fi # store result for other commands tfile02=${prefix}.04.NII echo "============== differ in slice_code? (nim)" if $NT -diff_nim -infiles ${infile} ${tfile02} then echo === second diff_nim incorrectly succeeded exit 1 else echo === good: second diff_nim showed a difference fi echo "============== differ in slice_code? (hdr)" if $NT -diff_hdr -infiles ${infile} ${tfile02} then echo === diff_hdr incorrectly succeeded exit 1 else echo === good: diff_hdr showed a difference fi echo "============== differ in slice_code? (hdr2)" if $NT -diff_hdr2 -infiles ${infile} ${tfile02} then echo === diff_hdr2 incorrectly succeeded exit 1 else echo === good: diff_hdr2 showed a difference fi echo "============== swap hdr as NIFTI (failes for N-2, but still debug)" if $NT -swap_as_nifti -debug 3 -infiles ${infile} -prefix ${prefix}.05.swap.nii then echo === swap_as_nifti incorrectly succeeded exit 1 else echo === good: swap_as_nifti whines for NIFTI-2 hdr as NIFTI-1 fi nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/c21_c_make_im.sh000077500000000000000000000103651371325713600273660ustar00rootroot00000000000000#!/bin/sh if [ $# -lt 2 ] then echo Missing nifti tool and Binary directory name exit 1 fi NT=$1 DATA=$2 OUT_DATA=$(dirname ${DATA}) #Need to write to separate directory cd ${OUT_DATA} # note the main input file and prefix for all output files prefix=out.c21.c rm -f $prefix* # -------------------------------------------------- # create a new image, and note outfile for other commands if $NT -mod_hdr -mod_field descrip 'dataset with mods' \ -new_dim 3 10 20 30 0 0 0 0 \ -infiles MAKE_IM -prefix $prefix.10.nii then echo "=== mod_hdr 1 succeeded" else echo === mod_hdr 1 failed exit 1 fi # store result for future use tfile11=$prefix.10.nii # modify slice_start and slice_duration if $NT -mod_hdr -mod_field slice_start 3 -mod_field slice_duration 0.04 \ -infiles $tfile11 -overwrite then echo "=== mod_hdr 1 slice_dur succeeded" else echo === mod_hdr 1 slice_dur failed exit 1 fi # create ASCII based image as alternate if $NT -mod_nim -mod_field descrip 'try ASCII' \ -infiles $tfile11 -prefix $prefix.11.nia -debug 3 then echo "=== disp_nim 2 succeeded" else echo === disp_nim 2 failed exit 1 fi # store result for future use tfile12=$prefix.11.nia # add some extensions, then display them if $NT -add_ext 6 'adding extension type 6 (comment)' \ -infiles $tfile12 -overwrite then echo "=== add_ext 3 succeeded" else echo === add_ext 3 failed exit 1 fi if $NT -add_comment_ext 'and now for a formal comment' \ -infiles $tfile12 -overwrite then echo "=== add_comment_ext 4 succeeded" else echo === add_comment_ext 4 failed exit 1 fi # ------------------------------------------------------------ # many tests for part 5 if $NT -rm_ext 1 -infiles $tfile12 -debug 3 -overwrite then echo "=== rm_ext 5.0 succeeded" else echo === rm_ext 5.0 failed exit 1 fi # test adding an extension from a file cat > $prefix.my_extension.txt << EOF here is some formatted extension, added via some stupid text file EOF if $NT -add_afni_ext "file:$prefix.my_extension.txt" \ -infiles $tfile12 -prefix $prefix.11.b.nii.gz then echo "=== add_afni_ext 5.1 succeeded" else echo === add_afni_ext 5.1 failed exit 1 fi # and compare if $NT -diff_hdr1 -infiles $tfile11 $prefix.11.b.nii.gz then echo === diff_hdr1 5.2 failed exit 1 else echo "=== good: diff_hdr1 5.2 showed a diff" fi # display the new exts if $NT -disp_exts -infiles $prefix.11.b.nii.gz then echo "=== diff_exts 5.3 succeeded" else echo === diff_exts 5.3 failed exit 1 fi if $NT -check_nim -infiles $prefix.11.b.nii.gz then echo "=== check_nim 5.4 succeeded" else echo === check_nim 5.4 failed exit 1 fi if $NT -disp_hdr1 -infiles $prefix.11.b.nii.gz -field descrip then echo "=== disp_hdr1 descrip 5.5 succeeded" else echo === disp_hdr1 descrip 5.5 failed exit 1 fi if $NT -disp_ana -infiles $prefix.11.b.nii.gz then echo "=== disp_ana 5.6 succeeded" else echo === disp_ana 5.6 failed exit 1 fi if $NT -strip_extras -infiles $tfile12 -debug 3 -overwrite then echo "=== strip_extras 5.7 succeeded" else echo === strip_extras 5.7 failed exit 1 fi # end part 5 # ------------------------------------------------------------ # and compare (as nim, we are not allowed to diff different hdr types) if $NT -diff_nim -debug 3 -infiles $tfile11 $tfile12 then echo === diff_nim 6 failed exit 1 else echo "=== good: diff_nim 6 showed a diff" fi # try swapping (as nifti, analzye, old) # nifti if $NT -swap_as_nifti -debug 3 -infiles $tfile11 \ -prefix $prefix.12.a.swap.nii then echo "=== swap_as_nifti 7.a succeeded" else echo === swap_as_nifti 7.a failed exit 1 fi # try swapping (as nifti, analzye, old) # analyze if $NT -swap_as_analyze -debug 3 -infiles $tfile11 \ -prefix $prefix.12.b.swap.ana.nii then echo "=== swap_as_nifti 7.b succeeded" else echo === swap_as_nifti 7.b failed exit 1 fi # try swapping (as nifti, analzye, old) # old (AND ... make nifti_tool hunt for the input file) if $NT -swap_as_old -debug 3 -infiles $prefix.12.b.swap.ana \ -prefix $prefix.13.c.swap.old.nii then echo "=== swap_as_nifti 7.c succeeded" else echo === swap_as_nifti 7.c failed exit 1 fi # collapse third dimension, writing as ascii if $NT -debug 3 -infiles $tfile12 -cci -1 -1 17 0 0 0 0 -prefix $prefix.13.nia then echo "=== cci 8 succeeded" else echo === cci 8 failed exit 1 fi nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/c21_d_misc_tests.sh000077500000000000000000000010571371325713600301400ustar00rootroot00000000000000#!/bin/sh if [ $# -lt 2 ] then echo Missing nifti tool and Binary directory name exit 1 fi NT=$1 DATA=$2 OUT_DATA=$(dirname ${DATA}) #Need to write to separate directory cd ${OUT_DATA} # note the main input file and prefix for all output files infile=$DATA/e4.60005.nii.gz # prefix=out.c21.d # rm -f $prefix* # -------------------------------------------------- # display basic nifti info stuff from existing dset if $NT -run_misc_tests -debug 2 -infiles ${infile} then echo "=== run_misc_tests succeeded" else echo === run_misc_tests failed exit 1 fi nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/comment_test.sh000077500000000000000000000023121371325713600275070ustar00rootroot00000000000000#!/bin/sh if [ $# -lt 2 ] then echo Missing nifti tool and Binary directory name exit 1 fi NT=$1 DATA=$2 OUT_DATA=$(dirname ${DATA}) #Need to write to separate directory cd ${OUT_DATA} rm -f ${OUT_DATA}/f4.comment.nii # add some comment and afni extensions, then display them if \ ${NT} -keep_hist -prefix ${OUT_DATA}/f4.comment -infiles ${DATA}/anat0.nii \ -add_comment '4 slice time series' \ -add_afni_ext 'and an AFNI extension' \ -add_comment 'how about a question AND a comment?' then echo "" else echo "add comment failed" exit 1 fi if ${NT} -disp_ext -infiles ${OUT_DATA}/f4.comment.nii then echo "" else echo "failed" exit 1 fi if ${NT} -cbl -infiles ${OUT_DATA}/f4.comment.nii -prefix ${OUT_DATA}/f4.to.clear.nii then echo "" else echo "failed" exit 1 fi if ${NT} -overwrite -strip -infiles ${OUT_DATA}/f4.to.clear.nii then echo "" else echo "failed" exit 1 fi if ${NT} -disp_ext -infiles ${OUT_DATA}/f4.to.clear.nii then echo "" else echo "failed" exit 1 fi if ${NT} -diff_nim -infiles ${OUT_DATA}/f4.comment.nii ${OUT_DATA}/f4.to.clear.nii then echo "failed -- no changes found" exit 1 else echo "diff succeed -- found changes" fi nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/dci_test.sh000077500000000000000000000020421371325713600266040ustar00rootroot00000000000000#!/bin/sh if [ $# -lt 2 ] then echo Missing nifti tool and Binary directory name exit 1 fi NT=$1 DATA=$2 OUT_DATA=$(dirname ${DATA}) #Need to write to separate directory cd ${OUT_DATA} # get the time series for a slice, get the same sub-bricks, # compare nifti_images, and display the time series again # # this should match the previous ${NT} -keep_hist -cci 3 3 3 -1 -1 -1 -1 -prefix ${OUT_DATA}/r.333 -infiles ${DATA}/run.210.nii if [ $? -ne 0 ] ; then echo cci failed fi ${NT} -keep_hist -cci 3 3 3 -1 1 1 1 -prefix ${OUT_DATA}/r.333.111 -infiles ${DATA}/run.210.nii if [ $? -ne 0 ] ; then echo cci failed fi ${NT} -disp_ci -1 -1 -1 -1 -1 -1 -1 -infiles ${OUT_DATA}/r.333.111.nii -quiet \ | tee o.10a.dci.1 if [ $? -ne 0 ] ; then echo disp_ci failed fi ${NT} -disp_ci 0 0 0 -1 1 1 1 -infiles ${OUT_DATA}/r.333.nii -quiet \ | tee o.10a.dci.2 if [ $? -ne 0 ] ; then echo disp_ci failed fi if diff o.10a.dci.? then echo "" rm -f o.10a.dci* ${OUT_DATA}/r.333* else echo '** failure, o.10a.dci timeseries files differ' exit 1 fi nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/dsets_test.sh000077500000000000000000000026701371325713600271760ustar00rootroot00000000000000#!/bin/sh if [ $# -lt 2 ] then echo Missing nifti tool and Binary directory name exit 1 fi NT=$1 DATA=$2 OUT_DATA=$(dirname ${DATA}) #Need to write to separate directory cd ${OUT_DATA} # - create datasets out of nothing # # - modify some fields and compare against other datasets rm -f ${OUT_DATA}/new_epi.nii # just test a basic make im, mostly to capture the debug output ${NT} -make_im -debug 3 -new_dim 4 64 64 21 180 0 0 0 -prefix ${OUT_DATA}/new_epi.nii if [ $? -ne 0 ] ; then echo failed exit 1 fi # compare hdr and nim in a fresh image to the existing one ${NT} -diff_hdr -new_dim 4 64 64 21 180 0 0 0 \ -infiles MAKE_IM ${DATA}/stat0.nii if [ $? = 0 ] ; then echo unexpected 0 return code in diff exit 1 fi ${NT} -diff_nim -new_dim 4 64 64 21 180 0 0 0 \ -infiles MAKE_IM ${DATA}/stat0.nii if [ $? = 0 ] ; then echo unexpected 0 return code in diff exit 1 fi rm -f ${OUT_DATA}/epi_180_pixdim.nii # clean up the nim by adjusting pixdim (from empty MAKE_IM) ${NT} -mod_hdr -new_dim 4 64 64 21 180 0 0 0 \ -mod_field pixdim '0.0 4.0 4.0 6.0 3.0 1.0 1.0 1.0' \ -prefix ${OUT_DATA}/epi_180_pixdim.nii -infiles MAKE_IM if [ $? -ne 0 ] ; then echo mod_hdr failed exit 1 fi # and compare again ${NT} -diff_nim -infiles ${DATA}/stat0.nii ${OUT_DATA}/epi_180_pixdim.nii if [ $? -ne 0 ] ; then echo found changes -- success. else echo diff failed to find differences. exit 1 fi exit 0 nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/dts_test.sh000077500000000000000000000032011371325713600266350ustar00rootroot00000000000000#!/bin/sh if [ $# -lt 2 ] then echo Missing nifti tool and Binary directory name exit 1 fi NT=$1 DATA=$2 OUT_DATA=$(dirname ${DATA}) #Need to write to separate directory cd ${OUT_DATA} ${NT} -quiet -disp_ts 19 36 11 -infiles ${DATA}/stat0.nii | tee o.08.ts.19.36.11 if [ $? -ne 0 ] ; then echo disp_ts failed exit 1 fi rm -f o.08.ts.19.36.11 ${NT} -quiet -disp_ts 19 36 11 -infiles ${DATA}/stat0.nii \ | awk '{print $(NF-1), $NF, $1, $2}' | tee o.09.ts4.1.awk if [ $? -ne 0 ] ; then echo disp_ts failed exit 1 fi ${NT} -quiet -disp_ts 19 36 11 -infiles ${OUT_DATA}/f4.nii | tee o.09.ts4.2.awk if diff o.09.ts4.1.awk o.09.ts4.2.awk then echo "" else echo '** failure, ts4 files differ' exit 1 fi rm -f 0.09.ts4.1.awk o.09.ts4.2.awk ${OUT_DATA}/f4.nii exit 0 # get the time series for a slice, get the same sub-bricks, # compare nifti_images, and display the time series again # # this should match the previous if ${NT} -keep_hist -cci 19 36 -1 -1 0 0 0 -prefix ${OUT_DATA}f.19.36 \ -infiles ${DATA}/stat0.nii then echo "" else echo cci failed exit 1 fi if ${NT} -keep_hist -cbl -prefix ${OUT_DATA}/f.19.36.t4.nii \ -infiles ${OUT_DATA}/f.19.36.nii'[178..$,0,1]' then echo "" else echo cbi failed exit 0 fi ${NT} -diff_nim -infiles ${OUT_DATA}/f.19.36.nii ${OUT_DATA}/f.19.36.t4.nii | tee o.10.diff_nim if [ $? -ne 0 ] ; then echo f.19.36.nii and f.19.36.t4.nii differ else echo f.19.36.nii and f.19.36.t4.nii do not differ fi ${NT} -quiet -disp_ci 0 0 11 -1 0 0 0 -infiles ${OUT_DATA}/f.19.36.t4.nii \ | tee o.10.dci.4 #diff o.09.ts4.1.awk o.10.dci.4 #if( $status ) echo '** failure, o.09 and o.10 ts files differ' exit 0 nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/fetch_data_test.sh000077500000000000000000000017221371325713600301330ustar00rootroot00000000000000#!/bin/sh # # arg[1] is TESTING_BINARY_DIR if [ $# -lt 1 ] then echo Missing Binary directory name exit 1 fi ## ensure that a clean download can occur # by preventing downloads with .1 .2 .3 suffix # if a previous tgz file is present rm -f nifti_regress_data.tgz* if cd $1 then echo working in `pwd` else echo can\'t cd to $1 exit 1 fi if wget -nd http://nifti.nimh.nih.gov/pub/dist/data/nifti_regress_data.tgz then echo wget succeeded else ## Note: On MacOSX, wget is not installed by default, but curl is ## so use this fall back strategy when wget can not be found if curl -O http://nifti.nimh.nih.gov/pub/dist/data/nifti_regress_data.tgz then echo curl succeeded else echo Both curl and wget failed exit 1 fi fi if tar xzvf nifti_regress_data.tgz then echo "" else echo failed tar xzvf nifti_regress_data.tgz exit 1 fi if rm -f nifti_regress_data.tgz* then echo "" else echo can\'t remove ../nifti_regress_data.tgz exit 1 fi exit 0 nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/install_linking_test.sh000077500000000000000000000014031371325713600312260ustar00rootroot00000000000000#!/bin/sh set -e # Get the build tool executable if [ $# -lt 1 ] then echo Missing build tool, guessing that make is used export BUILD_TOOL=make else export BUILD_TOOL=$1 fi # Set variables for local install export DESTDIR=installed export PATH="$PWD/$DESTDIR/usr/local/bin:$PATH" # Install and execute tools to see if linkage failures have occurred $BUILD_TOOL install nifti_tool 1>/dev/null nifti1_tool 1>/dev/null nifti_stats 1>/dev/null # Run an example of a downstream project linking against the nifti targets rm -rf downstream_example mkdir downstream_example cd downstream_example cmake \ -G 'Unix Makefiles' \ -DCMAKE_MODULE_PATH=../installed/usr/local/share \ ../../real_easy/minimal_example_of_downstream_usage make echo Success nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/mod_header_2_test.sh000077500000000000000000000026301371325713600303600ustar00rootroot00000000000000#!/bin/sh if [ $# -lt 2 ] then echo Missing nifti tool and Binary directory name exit 1 fi NT=$1 DATA=$2 OUT_DATA=$(dirname ${DATA}) #Need to write to separate directory cd ${OUT_DATA} rm -f mod.hdr2* echo "============== 1 : diff_nim" if $NT -diff_nim -infiles $DATA/Conte69.parcellations_VGD11b.32k_fs_LR.dlabel.nii \ $DATA/ones.dscalar.nii then echo diff_nim failed '(no difference seen)' exit 1 else echo "" fi echo "============== 2 : diff_hdr2" if $NT -diff_hdr2 -infiles $DATA/Conte69.parcellations_VGD11b.32k_fs_LR.dlabel.nii \ $DATA/ones.dscalar.nii then echo diff_hdr failed '(no difference seen)' exit 1 else echo "" fi echo "============== 3 : mod_hdr2" if $NT -infiles $DATA/Conte69.parcellations_VGD11b.32k_fs_LR.dlabel.nii \ -mod_hdr2 -mod_field slice_code 2 -prefix mod.hdr2.nii then echo "" else echo mod_hdr2 failed '(no difference seen)' exit 1 fi echo "============== 4 : diff_nim on mod" if $NT -diff_nim -infiles $DATA/Conte69.parcellations_VGD11b.32k_fs_LR.dlabel.nii \ mod.hdr2.nii then echo diff_nim failed on mod '(no difference seen)' exit 1 else echo "" fi echo "============== 5 : diff_hdr2 on mod" if $NT -diff_hdr2 -infiles $DATA/Conte69.parcellations_VGD11b.32k_fs_LR.dlabel.nii \ mod.hdr2.nii then echo diff_hdr2 failed on mod '(no difference seen)' exit 1 else echo "" fi nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/mod_header_test.sh000077500000000000000000000020531371325713600301360ustar00rootroot00000000000000#!/bin/sh if [ $# -lt 2 ] then echo Missing nifti tool and Binary directory name exit 1 fi NT=$1 DATA=$2 OUT_DATA=$(dirname ${DATA}) #Need to write to separate directory cd ${OUT_DATA} rm -f ${OUT_DATA}/anat1* if ${NT} -mod_hdr -prefix ${OUT_DATA}/anat1 \ -infiles ${DATA}/anat0.nii \ -mod_field qoffset_x -17.325 -mod_field slice_start 1 \ -mod_field descrip "beer, brats and cheese, mmmmm..." then echo "" else echo mod_field failed exit 1 fi if ${NT} -diff_hdr -infiles ${DATA}/anat0.nii ${OUT_DATA}/anat1.nii then echo diff_hdr failed '(no difference seen)!' exit 1 else echo "" fi if ${NT} -add_afni_ext "wow, my first extension" \ -add_afni_ext "look, my second.." \ -overwrite -infiles ${OUT_DATA}/anat1.nii then echo "" else echo add_afni_ext failed exit 1 fi if ${NT} -disp_exts -infiles ${DATA}/anat0.nii ${OUT_DATA}/anat1.nii then echo "" else echo disp_exts failed exit 1 fi if ${NT} -diff_hdr -infiles ${DATA}/anat0.nii ${OUT_DATA}/anat1.nii then echo diff_hdr failed '(no difference seen)!' exit 1 else echo "" fi exit 0 nifti_clib-3.0.1/nifti2/nifti_regress_test/cmake_testscripts/newfiles_test.sh000077500000000000000000000022001371325713600276550ustar00rootroot00000000000000#!/bin/sh if [ $# -lt 2 ] then echo Missing nifti tool and Binary directory name exit 1 fi NT=$1 DATA=$2 OUT_DATA=$(dirname ${DATA}) #Need to write to separate directory cd ${OUT_DATA} rm -f ${OUT_DATA}/new* ${OUT_DATA}/ncopy* # test writing various output file types ${NT} -make_im -prefix ${OUT_DATA}/new1.hdr ${NT} -make_im -prefix ${OUT_DATA}/new2.hdr.gz ${NT} -make_im -prefix ${OUT_DATA}/new3.img.gz ${NT} -make_im -prefix ${OUT_DATA}/new4.nii.gz ${NT} -make_im -prefix ${OUT_DATA}/new5.nia # test reading them ${NT} -copy_im -prefix ${OUT_DATA}/ncopy1.nii -infiles ${OUT_DATA}/new1.hdr ${NT} -copy_im -prefix ${OUT_DATA}/ncopy2.nii -infiles ${OUT_DATA}/new2.hdr.gz ${NT} -copy_im -prefix ${OUT_DATA}/ncopy3.nii -infiles ${OUT_DATA}/new3.img.gz ${NT} -copy_im -prefix ${OUT_DATA}/ncopy4.nii -infiles ${OUT_DATA}/new4.nii.gz ${NT} -copy_im -prefix ${OUT_DATA}/ncopy5.nii -infiles ${OUT_DATA}/new5.nia # verify that they are all the same set count = 0 for index in 2 3 4 5 ; do diff ${OUT_DATA}/ncopy1.nii ${OUT_DATA}/ncopy$index.nii if [ $? -ne 0 ] ; then echo "-- failure on test index $index --" exit 1 fi done nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/000077500000000000000000000000001371325713600225235ustar00rootroot00000000000000nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/b20.mod.hdr000066400000000000000000000021671371325713600243710ustar00rootroot00000000000000#!/bin/tcsh # written in the format of the bash scripts under cmake_testscripts # (this is not meant to be run along with the c* scritps here) if ( $#argv < 2 ) then echo "** missing nifti tool and data directory name" exit 1 endif set NT = $1 set DATA = $2 set OUT_DATA = `dirname $DATA` cd $OUT_DATA rm -f mod.hdr2* echo "==== diff_nim on Conte vs ones" $NT -diff_nim -infiles $DATA/Conte69.parcellations_VGD11b.32k_fs_LR.dlabel.nii \ $DATA/ones.dscalar.nii echo "==== diff_hdr2 on Conte vs ones" $NT -diff_hdr2 -infiles $DATA/Conte69.parcellations_VGD11b.32k_fs_LR.dlabel.nii \ $DATA/ones.dscalar.nii echo "==== mod_hdr2 on Conte" $NT -infiles $DATA/Conte69.parcellations_VGD11b.32k_fs_LR.dlabel.nii \ -mod_hdr2 -mod_field slice_code 2 -prefix mod.hdr2.nii echo "==== diff_nim on Conte vs mod" $NT -diff_nim -infiles $DATA/Conte69.parcellations_VGD11b.32k_fs_LR.dlabel.nii \ mod.hdr2.nii echo "==== diff_hdr2 on Conte vs mod" $NT -diff_hdr2 -infiles $DATA/Conte69.parcellations_VGD11b.32k_fs_LR.dlabel.nii \ mod.hdr2.nii nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c01.versions000066400000000000000000000002661371325713600247040ustar00rootroot00000000000000 # check the version numbers for the library and tool nifti_tool -nifti_ver nifti_tool -ver # also, check whether the library was compiled with zlib support nifti_tool -with_zlib nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c02.nt.help000066400000000000000000000001121371325713600243730ustar00rootroot00000000000000 nifti_tool -help nifti_tool -help_datatypes nifti_tool -help_datatypes T nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c03.hist000066400000000000000000000001051371325713600237750ustar00rootroot00000000000000 # library and tool history nifti_tool -nifti_hist nifti_tool -hist nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c04.disp.anat0.info000066400000000000000000000003201371325713600257210ustar00rootroot00000000000000 # display header, nifti_image and extensions for default anat nifti_tool -disp_hdr -infiles anat0 nifti_tool -disp_nim -infiles anat0 nifti_tool -disp_ana -infiles anat0 nifti_tool -disp_ext -infiles anat0 nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c05.mod.hdr000066400000000000000000000005241371325713600243700ustar00rootroot00000000000000 # modify the header of default anat, creating a new anat # # then compare the resulting headers nifti_tool -mod_hdr -prefix anat1 -infiles anat0.nii \ -mod_field qoffset_x -17.325 -mod_field slice_start 1 \ -mod_field descrip 'beer, brats and cheese, mmmmm...' nifti_tool -diff_hdr -infiles anat0.nii anat1.nii nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c06.add.ext000077500000000000000000000012041371325713600243640ustar00rootroot00000000000000#!/bin/tcsh # - add junk extensions to the new anat, overwriting it # - display extensions for the two files # - again, compare the headers nifti_tool -add_afni_ext 'wow, my first extension :)' \ -add_afni_ext 'look, my second..' \ -overwrite -infiles anat1.nii nifti_tool -disp_exts -infiles anat0.nii anat1.nii nifti_tool -diff_hdr -infiles anat0.nii anat1.nii # add one more, via a file cat > my.extension << EOF here is some formatted extension, added via a text file EOF nifti_tool -add_comment_ext 'file:my.extension' -overwrite -infiles anat1.nii nifti_tool -disp_exts -infiles anat1.nii nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c07.cbl.4bricks000066400000000000000000000004311371325713600251340ustar00rootroot00000000000000 # - copy some of the sub-bricks of the default stat file, # storing the history (command), and writing to a new 'f4.nii' # - compare these nifti_image structs nifti_tool -keep_hist -cbl -infiles stat0.nii'[178..$,0,1]' -prefix f4 nifti_tool -diff_nim -infiles stat0.nii f4.nii nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c08.dts.19.36.11000066400000000000000000000001741371325713600245320ustar00rootroot00000000000000 # display a time series from our stat brick nifti_tool -quiet -disp_ts 19 36 11 -infiles stat0.nii | tee o.08.ts.19.36.11 nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c09.dts4.compare000066400000000000000000000005301371325713600253410ustar00rootroot00000000000000 # get some time series values in multiple ways, and compare nifti_tool -quiet -disp_ts 19 36 11 -infiles stat0.nii \ | awk '{print $(NF-1), $NF, $1, $2}' | tee o.09.ts4.1.awk nifti_tool -quiet -disp_ts 19 36 11 -infiles f4.nii | tee o.09.ts4.2.awk diff o.09.ts4.1.awk o.09.ts4.2.awk if( $status ) echo '** failure, ts4 files differ' nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c10.dci.ts4000066400000000000000000000011311371325713600242740ustar00rootroot00000000000000 # get the time series for a slice, get the same sub-bricks, # compare nifti_images, and display the time series again # # this should match the previous nifti_tool -keep_hist -cci 19 36 -1 -1 0 0 0 -prefix f.19.36 -infiles stat0.nii nifti_tool -keep_hist -cbl -prefix f.19.36.t4.nii \ -infiles f.19.36.nii'[178..$,0,1]' nifti_tool -diff_nim -infiles f.19.36.nii f.19.36.t4.nii | tee o.10.diff_nim nifti_tool -quiet -disp_ci 0 0 11 -1 0 0 0 -infiles f.19.36.t4.nii \ | tee o.10.dci.4 diff o.09.ts4.1.awk o.10.dci.4 if( $status ) echo '** failure, o.09 and o.10 ts files differ' nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c10a.dci.run.210000066400000000000000000000011231371325713600250310ustar00rootroot00000000000000 # get the time series for a slice, get the same sub-bricks, # compare nifti_images, and display the time series again # # this should match the previous nifti_tool -keep_hist -cci 3 3 3 -1 -1 -1 -1 -prefix r.333 -infiles run.210.nii nifti_tool -keep_hist -cci 3 3 3 -1 1 1 1 -prefix r.333.111 -infiles run.210.nii nifti_tool -disp_ci -1 -1 -1 -1 -1 -1 -1 -infiles r.333.111.nii -quiet \ | tee o.10a.dci.1 nifti_tool -disp_ci 0 0 0 -1 1 1 1 -infiles r.333.nii -quiet \ | tee o.10a.dci.2 diff o.10a.dci.? if( $status ) echo '** failure, o.10a.dci timeseries files differ' nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c11.add.comment000066400000000000000000000005661371325713600252310ustar00rootroot00000000000000 # add some comment and afni extensions, then display them nifti_tool -keep_hist -prefix f4.comment -infiles f.19.36.t4.nii \ -add_comment '4 slice time series' \ -add_afni_ext 'and an AFNI extension' \ -add_comment 'how about a question AND a comment?' nifti_tool -disp_ext -infiles f4.comment.nii nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c12.check.comments000066400000000000000000000004351371325713600257350ustar00rootroot00000000000000 # duplicate a dataset, and strip the extras, then compare nifti_tool -cbl -infiles f4.comment.nii -prefix f4.to.clear.nii nifti_tool -overwrite -strip -infiles f4.to.clear.nii nifti_tool -disp_ext -infiles f4.to.clear.nii nifti_tool -diff_nim -infiles f4.comment.nii f4.to.clear.nii nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c13.check.hdrs000066400000000000000000000002221371325713600250430ustar00rootroot00000000000000 # check the nifti_1_header and nifti_image structes of the .nii files nifti_tool -check_hdr -infiles *.nii nifti_tool -check_nim -infiles *.nii nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c14.make.dsets000066400000000000000000000014641371325713600250770ustar00rootroot00000000000000 # - create datasets out of nothing # # - modify some fields and compare against other datasets # just test a basic make im, mostly to capture the debug output nifti_tool -make_im -debug 3 -new_dim 4 64 64 21 180 0 0 0 -prefix new_epi.nii # compare hdr and nim in a fresh image to the existing one nifti_tool -diff_hdr -new_dim 4 64 64 21 180 0 0 0 \ -infiles MAKE_IM stat0.nii nifti_tool -diff_nim -new_dim 4 64 64 21 180 0 0 0 \ -infiles MAKE_IM stat0.nii # clean up the nim by adjusting pixdim (from empty MAKE_IM) nifti_tool -mod_hdr -new_dim 4 64 64 21 180 0 0 0 \ -mod_field pixdim '0.0 4.0 4.0 6.0 3.0 1.0 1.0 1.0' \ -prefix epi_180_pixdim.nii -infiles MAKE_IM # and compare again nifti_tool -diff_nim -infiles stat0.nii epi_180_pixdim.nii nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c15.new.files000066400000000000000000000013311371325713600247250ustar00rootroot00000000000000 # test writing various output file types nifti_tool -make_im -prefix new1.hdr nifti_tool -make_im -prefix new2.hdr.gz nifti_tool -make_im -prefix new3.img.gz nifti_tool -make_im -prefix new4.nii.gz nifti_tool -make_im -prefix new5.nia # test reading them nifti_tool -copy_im -prefix ncopy1.nii -infiles new1.hdr nifti_tool -copy_im -prefix ncopy2.nii -infiles new2.hdr.gz nifti_tool -copy_im -prefix ncopy3.nii -infiles new3.img.gz nifti_tool -copy_im -prefix ncopy4.nii -infiles new4.nii.gz nifti_tool -copy_im -prefix ncopy5.nii -infiles new5.nia # verify that they are all the same set count = 0 foreach index ( 2 3 4 5 ) diff ncopy1.nii ncopy$index.nii if ( $status ) echo "-- failure on test index $index --" end nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c16.rand.swap000077500000000000000000000030731371325713600247410ustar00rootroot00000000000000#!/bin/tcsh echo '------------- DISP nifti_1_header -------------' nifti_tool -disp_hdr -debug 2 -infiles rand.hdr > out.rand.hdr echo '------------- DISP nifti_analyze75 ------------' nifti_tool -disp_ana -debug 2 -infiles rand.hdr > out.rand.ana cp rand.hdr swap.ana.hdr cp rand.hdr swap.nim.hdr cp rand.hdr swap.old.hdr cp rand_nifti.hdr swap.old_nifti.hdr cp rand_nifti.hdr swap.new_nifti.hdr echo '------------- SWAP nifti_1_header -------------' nifti_tool -swap_as_nifti -infiles swap.nim.hdr -overwrite -debug 2 echo '------------- SWAP nifti_analyze75 ------------' nifti_tool -swap_as_analyze -infiles swap.ana.hdr -overwrite -debug 2 echo '------------- SWAP old analyze ----------------' nifti_tool -swap_as_old -infiles swap.old.hdr -overwrite -debug 2 echo '------------- SWAP old vs new nifti ------------------' nifti_tool -swap_as_old -infiles swap.old_nifti.hdr -overwrite -debug 2 nifti_tool -swap_as_nifti -infiles swap.new_nifti.hdr -overwrite -debug 2 echo '------------- DISP nifti_1_header swapped -------------' nifti_tool -disp_hdr -debug 2 -infiles swap.nim.hdr > out.rand.swap.hdr echo '------------- DISP nifti_analyze75 swapped ------------' nifti_tool -disp_ana -debug 2 -infiles swap.ana.hdr > out.rand.swap.ana echo '------------- DIFF old/new analyze -----------' nifti_tool -diff_hdr -debug 2 -infiles swap.old.hdr swap.ana.hdr \ > out.rand.swap.compare.analyze echo '------------- DIFF old/new nifti -------------' nifti_tool -diff_hdr -debug 2 -infiles swap.new_nifti.hdr swap.old_nifti.hdr \ > out.rand.swap.compare.nifti nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c17.file.case000066400000000000000000000021331371325713600246670ustar00rootroot00000000000000 # - test read/write of datasets with various name cases # - .nii .hdr .img .NII .HDR .IMG # - compressed # - error conditions # start with a basic dataset nifti_tool -make_im -new_dim 3 3 4 5 1 0 0 0 -prefix small.nii set prefix = t17 # read/write of 3 cap cases nifti_tool -cbl -keep_hist -infiles small.nii -prefix $prefix.1.NII nifti_tool -cbl -keep_hist -infiles $prefix.1.NII -prefix $prefix.2.HDR nifti_tool -cbl -keep_hist -infiles $prefix.2.HDR -prefix $prefix.3.IMG nifti_tool -diff_hdr -infiles $prefix.2.HDR small.nii nifti_tool -diff_nim -infiles $prefix.2.HDR $prefix.3.IMG # compression cases nifti_tool -cbl -keep_hist -infiles $prefix.1.NII -prefix $prefix.4.NII.GZ nifti_tool -cbl -keep_hist -infiles $prefix.4.NII.GZ -prefix $prefix.5.HDR.GZ nifti_tool -cbl -keep_hist -infiles $prefix.5.HDR.GZ -prefix $prefix.6.IMG.GZ nifti_tool -diff_hdr -infiles $prefix.6.HDR.GZ small.nii # display last header nifti_tool -disp_hdr -infiles $prefix.6.IMG.GZ # error cases echo should be errors: nifti_tool -disp_hdr -infiles small.NII nifti_tool -disp_hdr -infiles $prefix.4.NII.gz nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c21.a.info.output000066400000000000000000000007751371325713600255540ustar00rootroot00000000000000 # print simple info and terminate echo "------ version, NIFTI version, with zlib ------" nifti_tool -ver nifti_tool -nifti_ver nifti_tool -with_zlib echo "------ history (NT), NIFTI history ------" nifti_tool -hist nifti_tool -nifti_hist echo "------ help, datatypes, hdr, nim ------" nifti_tool -help nifti_tool -help_datatypes nifti_tool -help_datatypes D nifti_tool -help_datatypes N nifti_tool -help_datatypes T nifti_tool -help_hdr1 nifti_tool -help_hdr2 nifti_tool -help_ana nifti_tool -help_nim nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c21.b.cifti.in000066400000000000000000000037321371325713600247620ustar00rootroot00000000000000 # tests based on a single CIFTI input set infile = Conte69.parcellations_VGD11b.32k_fs_LR.dlabel.nii set prefix = out.c21.b # -------------------------------------------------- # display basic nifti info stuff from existing dset nifti_tool -disp_hdr -infiles $infile -debug 3 nifti_tool -disp_nim -infiles $infile -debug 5 nifti_tool -disp_hdr2 -infiles $infile -debug 3 # allow failure? nifti_tool -disp_hdr1 -infiles $infile nifti_tool -disp_cext -infiles $infile # display some data nifti_tool -infiles $infile -disp_ci 0 0 0 0 -1 23456 0 # -------------------------------------------------- # modify an existing dset and compare # modify an image field nifti_tool -mod_hdr2 -mod_field slice_start 3 -mod_field slice_duration 0.04 \ -infiles $infile -prefix $prefix.01.a.nii nifti_tool -debug 2 -infiles $prefix.01.a.nii -prefix $prefix.01.b.nia \ -mod_nim -mod_field qform_code 2 -mod_field sform_code 2 # collapse 6th (last) dim of CIFTI input, compress output to test znz nifti_tool -cci 0 0 0 0 -1 17 0 -infiles $prefix.01.a.nii \ -debug 3 -prefix $prefix.02.nii.gz set tfile01 = $prefix.02.nii.gz # look for subsequent dimension changes (these vary in NIFTI types 2 vs 1) nifti_tool -diff_hdr2 -infiles $infile $tfile01 nifti_tool -diff_nim -infiles $infile $tfile01 # use volume index select, which requires sorting and selecting nifti_tool -copy_brick_list -infiles $infile'[2,3,3,3,1..3(2)]' \ -debug 3 \ -prefix $prefix.03.nii # test CAPS file extension nifti_tool -mod_hdr2 -mod_field slice_code 2 -infiles $infile \ -prefix $prefix.04.NII set tfile02 = $prefix.04.NII # differ in slice_code? (nim) nifti_tool -diff_nim -infiles $infile $tfile02 # differ in slice_code? (hdr) nifti_tool -diff_hdr -infiles $infile $tfile02 nifti_tool -diff_hdr2 -infiles $infile $tfile02 # try swapping nifti_tool -swap_as_nifti -debug 3 -infiles $infile -prefix $prefix.05.swap.nii nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c21.c.MAKE_IM000066400000000000000000000041751371325713600243640ustar00rootroot00000000000000 # tests based on a newly create image (via nifti_tool) set prefix = out.c21.c # create a new image, and note outfile for other commands nifti_tool -mod_hdr -mod_field descrip 'dataset with mods' \ -new_dim 3 10 20 30 0 0 0 0 \ -infiles MAKE_IM -prefix $prefix.10.nii set tfile11 = $prefix.10.nii nifti_tool -mod_hdr -mod_field slice_start 3 -mod_field slice_duration 0.04 \ -infiles $tfile11 -overwrite # create ASCII based image as alternate nifti_tool -mod_nim -mod_field descrip 'try ASCII' \ -infiles $tfile11 -prefix $prefix.11.nia -debug 3 set tfile12 = $prefix.11.nia # add some extensions, then display them nifti_tool -add_ext 6 'adding extension type 6 (comment)' \ -infiles $tfile12 -overwrite nifti_tool -add_comment_ext 'and now for a formal comment' \ -infiles $tfile12 -overwrite nifti_tool -rm_ext 1 -infiles $tfile12 -debug 3 -overwrite # ... and add an extension from a file cat > $prefix.my_extension.txt << EOF here is some formatted extension, added via some stupid text file EOF nifti_tool -add_afni_ext "file:$prefix.my_extension.txt" \ -infiles $tfile12 -prefix $prefix.11.b.nii.gz nifti_tool -diff_hdr1 -infiles $tfile11 $prefix.11.b.nii.gz nifti_tool -disp_exts -infiles $prefix.11.b.nii.gz nifti_tool -check_nim -infiles $prefix.11.b.nii.gz nifti_tool -disp_hdr1 -infiles $prefix.11.b.nii.gz -field descrip nifti_tool -disp_ana -infiles $prefix.11.b.nii.gz nifti_tool -strip_extras -infiles $tfile12 -debug 3 -overwrite # and compare (as nim, we are not allowed to diff different hdr types) nifti_tool -diff_nim -debug 3 -infiles $tfile11 $tfile12 # try swapping nifti_tool -swap_as_nifti -debug 3 -infiles $tfile11 \ -prefix $prefix.12.a.swap.nii nifti_tool -swap_as_analyze -debug 3 -infiles $tfile11 \ -prefix $prefix.12.b.swap.ana.nii nifti_tool -swap_as_old -debug 3 -infiles $prefix.12.b.swap.ana \ -prefix $prefix.13.c.swap.old.nii # collapse third dimension nifti_tool -debug 3 -infiles $tfile12 \ -cci -1 -1 17 0 0 0 0 -prefix $prefix.13.nia nifti_clib-3.0.1/nifti2/nifti_regress_test/commands/c21.d.misc.tests000066400000000000000000000003231371325713600253460ustar00rootroot00000000000000 # ------------------------------------------------------------ # misc tests, start with oblique EPI set infile2 = e4.60005.nii.gz # run some misc tests nifti_tool -run_misc_tests -debug 2 -infile $infile2 nifti_clib-3.0.1/nifti2/nifti_tool.c000066400000000000000000006324331371325713600173450ustar00rootroot00000000000000/*--------------------------------------------------------------------------*/ /*! \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 mis-match 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", "----------------------------------------------------------------------\n" }; static char g_version[] = "2.09"; static char g_version_date[] = "April 7, 2020"; static int g_debug = 1; #define _NIFTI_TOOL_C_ #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 */ field_s g_hdr1_fields[NT_HDR1_NUM_FIELDS]; /* nifti_1_header fields */ field_s g_hdr2_fields[NT_HDR2_NUM_FIELDS]; /* nifti_2_header fields */ field_s g_ana_fields [NT_ANA_NUM_FIELDS]; /* nifti_analyze75 */ field_s g_nim1_fields[NT_NIM_NUM_FIELDS]; /* nifti_image fields */ 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.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 wither 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 */ /* 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") ) { int new_ecode; ac++; CHECK_NEXT_OPT(ac, argc, "-add_ext"); new_ecode = atoll(argv[ac]); if( add_int(&opts->etypes, 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_brick_list") || ! strcmp(argv[ac], "-copy_im") || ! strcmp(argv[ac], "-cbl") ) { 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 requred"); 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 requred"); 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 requied\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 requred"); 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->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' or '-cci'\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 *----------------------------------------------------------------------*/ int fill_cmd_string( nt_opts * opts, int argc, char * argv[]) { char * cp; int len, remain = NT_CMD_LEN; /* NT_CMD_LEN is 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 = sprintf( opts->command, "\n command: %s", argv[0] ); 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 = 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 = sprintf(cp, " '%s'", argv[ac]); else len = sprintf(cp, " %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() { 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" " nifti_tool -copy_im -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( " E. copy dataset, brick list or collapsed image:\n" "\n" " 1. nifti_tool -copy_im -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" " ------------------------------\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" " -copy_brick_list : copy a list of volumes to a new dataset\n" " -cbl : (a shorter, alternative form)\n" " -copy_im : (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( " This functionality applies only to 3 or 4-dimensional datasets.\n" "\n" " e.g. to copy a dataset:\n" " nifti_tool -copy_im -prefix new.nii -infiles dset0.nii\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" " compiled: %s\n" " version %s (%s)\n\n", __DATE__, 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 ); if( !nim ) return 1; /* errors come from the library */ for( ec = 0; ec < opts->elist.len; ec++ ){ ext = opts->elist.list[ec]; elen = 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, 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); nifti_image_write(nim); 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; int len, bytes; if( !filename || !length ) { fprintf(stderr,"** bad params to read_file_text\n"); return NULL; } len = nifti_get_filesize(filename); if( len <= 0 ) { fprintf(stderr,"** RFT: file '%s' appears empty\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(len * sizeof(char)); if( !text ) { fprintf(stderr,"** RFT: failed to allocate %d bytes\n", len); fclose(fp); return NULL; } bytes = fread(text, sizeof(char), len, fp); fclose(fp); /* in any case */ if( bytes != len ) { fprintf(stderr,"** RFT: read only %d of %d bytes from %s\n", bytes, len, filename); free(text); return NULL; } /* success */ if( g_debug > 1 ) { fprintf(stderr,"++ found extension of length %d in file %s\n", len, filename); if( g_debug > 2 ) fprintf(stderr,"++ text is:\n%s\n", text); } *length = len; 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 ); 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); nifti_image_write(nim); 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 ); 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, 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); nifti_image_write(nim); 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); if( ! nim0 ) return 1; /* errors have been printed */ nim1 = nt_image_read(opts, opts->infiles.list[1], 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); 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++ ) { sprintf(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); 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); 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 ) { nim = nt_image_read(opts, fname, 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, strlen(opts->command), NIFTI_ECODE_COMMENT) ) fprintf(stderr,"** failed to add command to image as exten\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; nifti_image_write(nim); /* create the duplicate file */ /* 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 ) { nim = nt_image_read(opts, fname, 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, strlen(opts->command), NIFTI_ECODE_COMMENT) ) fprintf(stderr,"** failed to add command to image as exten\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; nifti_image_write(nim); /* create the duplicate file */ /* 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 ) { nim = nt_image_read(opts, fname, 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, strlen(opts->command), NIFTI_ECODE_COMMENT) ) fprintf(stderr,"** failed to add command to image as exten\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; nifti_image_write(nim); /* create the duplicate file */ /* 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); /* with 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, 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; } nifti_image_write(nim); /* and write it out, piece of cake :) */ 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; } /*---------------------------------------------------------------------- * 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 */ } #define NT_MAX_DT_STR_LEN 14 /*---------------------------------------------------------------------- * 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, len, err; 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); 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; } len = nifti_read_collapsed_image(nim, opts->ci_dims, &data); if( len < 0 || !data ) { fprintf(stderr,"** FAILURE for dataset '%s'\n", nim->fname); 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"); } disp_raw_data(data, nim->datatype, len / 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: printf("%d", *(short *)dp); break; case DT_INT32: printf("%d", *(int *)dp); break; case DT_INT64: printf("%"PRId64, *(int64_t *)dp); break; case DT_UINT8: printf("%u", *(unsigned char *)dp); break; case DT_UINT16: printf("%u", *(unsigned short *)dp); break; case DT_UINT32: printf("%u", *(unsigned int *)dp); break; case DT_FLOAT32: { nchar = snprintf(fbuf, NT_LOC_MAX_FLOAT_BUF, "%f", *(float *)dp); /* if it is a large number for some reason, print as is */ if( nchar >= NT_LOC_MAX_FLOAT_BUF ) { printf("%f", *(float *)dp); } else { clear_float_zeros(fbuf); printf("%s", fbuf); } break; } case DT_FLOAT64: { nchar = snprintf(fbuf, NT_LOC_MAX_FLOAT_BUF, "%lf", *(double *)dp); /* if it is a large number for some reason, print as is */ if( nchar >= NT_LOC_MAX_FLOAT_BUF ) { printf("%lf", *(double *)dp); } 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 * return 1 if something was cleared * 0 if not *----------------------------------------------------------------------*/ int clear_float_zeros( char * str ) { char * dp = strchr(str, '.'), * valp; int 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); 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); sprintf(mesg, "= qform_code = %d\n", nim->qform_code); nifti_disp_matrix_orient(mesg, nim->qto_xyz); sprintf(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); /* 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, 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) ) nifti_image_write_bricks(nim, &NBL); nifti_image_free(nim); nifti_free_NBL(&NBL); free(fname); free(selstr); 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); 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, 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) ) nifti_image_write(nim); 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" *----------------------------------------------------------------------*/ nifti_image * nt_image_read( nt_opts * opts, const char * fname, int doread ) { if( !opts || !fname ) { fprintf(stderr,"** nt_image_read: bad params (%p,%p)\n", (void *)opts, (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,doread); return nifti_image_read(fname, doread); } /* so generate an emtpy 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 doread */ return nifti_make_new_nim(opts->new_dim, opts->new_datatype, doread); } /*---------------------------------------------------------------------- * 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_n1_hdr(%s,...)\n", fname); /* 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 emtpy 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); return nifti_image_read_bricks(fname, len, list, NBL); } /* so generate an emtpy 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; } nifti_clib-3.0.1/nifti2/nifti_tool.h000066400000000000000000000323501371325713600173420ustar00rootroot00000000000000#ifndef _NIFTI_TOOL_H_ #define _NIFTI_TOOL_H_ #define NT_CMD_LEN 2048 typedef struct{ int len; const char ** list; } str_list; typedef struct{ int len; int * list; } int_list; typedef struct{ /* action options (flags) */ int check_hdr, check_nim; int diff_hdr, diff_hdr1, diff_hdr2, diff_nim; int disp_hdr1, disp_hdr2, disp_hdr, disp_nim, disp_ana; int disp_exts, add_exts, rm_exts, disp_cext; int run_misc_tests; int mod_hdr, mod_hdr2, mod_nim; int swap_hdr, swap_ana, swap_old; int strip; /* strip extras from dataset(s) */ int cbl, cci; /* -copy_XXX option flags */ int dts, dci, dci_lines; /* display collapsed img flags */ int make_im; /* create a new image on the fly */ int64_t ci_dims[8]; /* user dims list (last 7 valid) */ int64_t new_dim[8]; /* user dim list for new image */ int new_datatype; /* datatype for new image */ int debug, keep_hist; /* debug level and history flag */ int overwrite; /* overwrite flag */ char * prefix; /* for output file */ str_list elist; /* extension strings */ int_list etypes; /* extension type list */ str_list flist; /* fields (to display or modify) */ str_list vlist; /* values (to set fields to) */ str_list infiles; /* input files */ char command[NT_CMD_LEN]; /* for inserting the command */ } nt_opts; #define USE_SHORT 1 #define USE_FULL 2 #define USE_HIST 3 #define USE_FIELD_HDR1 11 #define USE_FIELD_HDR2 12 #define USE_FIELD_NIM1 21 #define USE_FIELD_NIM2 22 #define USE_FIELD_ANA 31 #define USE_DTYPES 41 #define USE_VERSION 51 #define USE_VER_MAN 52 /* for unix man-page formatting */ #define USE_SEE_ALSO 53 /* for unix man-page formatting */ #define CHECK_NEXT_OPT(n,m,str) \ do { if ( (n) >= (m) ) { \ fprintf(stderr,"** option '%s': missing parameter\n",str); \ fprintf(stderr," consider: 'nifti_tool -help'\n"); \ return 1; } \ } while(0) #define CHECK_NEXT_OPT_MSG(n,m,str,msg) \ do { if ( (n) >= (m) ) { \ fprintf(stderr,"** option '%s': %s\n",str,msg); \ fprintf(stderr," consider: 'nifti_tool -help'\n"); \ return 1; } \ } while(0) /*---------------------------------------------------------------------- * this structure and definitions will be used to process the nifti_1_header * and nifti_image structure fields (actions disp, diff, mod) *----------------------------------------------------------------------*/ #define NT_FIELD_NAME_LEN 20 /* more than length of longest name */ #define NT_HDR1_NUM_FIELDS 43 /* in the nifti_1_header struct */ #define NT_HDR2_NUM_FIELDS 37 /* in the nifti_2_header struct */ #define NT_ANA_NUM_FIELDS 47 /* in the nifti_analyze75 struct */ #define NT_NIM_NUM_FIELDS 63 /* in the nifti_image struct */ #define NT_HDR_TIME_NFIELDS 8 /* num slice timing fields in hdr */ #define NT_NIM_TIME_NFIELDS 11 /* num slice timing fields in nim */ #define NT_DT_STRING -0xfff /* some strange number to abuse... */ #define NT_DT_POINTER -0xfef /* some strange number to abuse... */ #define NT_DT_CHAR_PTR -0xfee /* another... */ #define NT_DT_EXT_PTR -0xfed /* and another... */ typedef struct { int type; /* one of the DT_* types from nifti1.h */ int offset; /* bytes from the start of the struct */ int size; /* size of one element type */ int len; /* number of elements */ char name[NT_FIELD_NAME_LEN]; /* actual structure name used */ } field_s; /* for computing the offset from the start of the struct */ #define NT_OFF(str,field) ((int)( ((char *)&str.field) - ((char *)&str) )) #define SHOW_STRUCT_OFFSET(str,field,mesg) do { str ss; \ if(mesg)printf("%s ",(char*)mesg); \ printf("%s.%s @ offset %d\n", #str, #field, NT_OFF(ss,field)); } \ while (0) /* call fill_field() for a single type, name and number of elements */ /* nstr is the base struct, and fldp is a field pointer */ #define NT_SFILL(nstr,fldp,type,name,num,rv) do{ \ rv=fill_field(fldp,type,NT_OFF(nstr,name),num,#name); \ fldp++; } while (0) #define NT_MAKE_IM_NAME "MAKE_IM" /* ================================================================= */ /* matrix operations */ /* (macros allow them to apply to either mat44 or dmat44) */ /* fill MAT44 with MAT33 fields, then pad with 0.0 and a 1.0 at 3,3 */ #define NT_MAT33_TO_MAT44(m33, m44) do { \ m44.m[0][0] = m33.m[0][0]; m44.m[0][1] = m33.m[0][1]; \ m44.m[0][2] = m33.m[0][2]; \ m44.m[1][0] = m33.m[1][0]; m44.m[1][1] = m33.m[1][1]; \ m44.m[1][2] = m33.m[1][2]; \ m44.m[2][0] = m33.m[2][0]; m44.m[2][1] = m33.m[2][1]; \ m44.m[2][2] = m33.m[2][2]; \ /* and fill out the 4x4 mat */ \ m44.m[0][3] = m44.m[1][3] = m44.m[2][3] = 0.0; \ m44.m[3][0] = m44.m[3][1] = m44.m[3][2] = 0.0; \ m44.m[3][3] = 1.0; \ } while(0) /* fill MAT33 with initial subset of MAT44 fields */ #define NT_MAT44_TO_MAT33(m44, m33) do { \ m33.m[0][0] = m44.m[0][0]; m33.m[0][1] = m44.m[0][1]; \ m33.m[0][2] = m44.m[0][2]; \ m33.m[1][0] = m44.m[1][0]; m33.m[1][1] = m44.m[1][1]; \ m33.m[1][2] = m44.m[1][2]; \ m33.m[2][0] = m44.m[2][0]; m33.m[2][1] = m44.m[2][1]; \ m33.m[2][2] = m44.m[2][2]; \ } while(0) /* subtract 2 mat44 matrices */ #define NT_MAT44_SUBTRACT(mout, min0, min1) do { \ mout.m[0][0] = min0.m[0][0] - min1.m[0][0]; \ mout.m[0][1] = min0.m[0][1] - min1.m[0][1]; \ mout.m[0][2] = min0.m[0][2] - min1.m[0][2]; \ mout.m[0][3] = min0.m[0][3] - min1.m[0][3]; \ mout.m[1][0] = min0.m[1][0] - min1.m[1][0]; \ mout.m[1][1] = min0.m[1][1] - min1.m[1][1]; \ mout.m[1][2] = min0.m[1][2] - min1.m[1][2]; \ mout.m[1][3] = min0.m[1][3] - min1.m[1][3]; \ mout.m[2][0] = min0.m[2][0] - min1.m[2][0]; \ mout.m[2][1] = min0.m[2][1] - min1.m[2][1]; \ mout.m[2][2] = min0.m[2][2] - min1.m[2][2]; \ mout.m[2][3] = min0.m[2][3] - min1.m[2][3]; \ mout.m[3][0] = min0.m[3][0] - min1.m[3][0]; \ mout.m[3][1] = min0.m[3][1] - min1.m[3][1]; \ mout.m[3][2] = min0.m[3][2] - min1.m[3][2]; \ mout.m[3][3] = min0.m[3][3] - min1.m[3][3]; \ } while(0) /* subtract 2 mat33 matrices */ #define NT_MAT33_SUBTRACT(mout, min0, min1) do { \ mout.m[0][0] = min0.m[0][0] - min1.m[0][0]; \ mout.m[0][1] = min0.m[0][1] - min1.m[0][1]; \ mout.m[0][2] = min0.m[0][2] - min1.m[0][2]; \ mout.m[1][0] = min0.m[1][0] - min1.m[1][0]; \ mout.m[1][1] = min0.m[1][1] - min1.m[1][1]; \ mout.m[1][2] = min0.m[1][2] - min1.m[1][2]; \ mout.m[2][0] = min0.m[2][0] - min1.m[2][0]; \ mout.m[2][1] = min0.m[2][1] - min1.m[2][1]; \ mout.m[2][2] = min0.m[2][2] - min1.m[2][2]; \ } while(0) /* fill with identity matrix */ #define NT_MAT44_SET_TO_IDENTITY(M) do { \ M.m[0][0] = 1.0; M.m[0][1] = 0.0; M.m[0][2] = 0.0; M.m[0][3] = 0.0; \ M.m[1][0] = 0.0; M.m[1][1] = 1.0; M.m[1][2] = 0.0; M.m[1][3] = 0.0; \ M.m[2][0] = 0.0; M.m[2][1] = 0.0; M.m[2][2] = 1.0; M.m[2][3] = 0.0; \ M.m[3][0] = 0.0; M.m[3][1] = 0.0; M.m[3][2] = 0.0; M.m[3][3] = 1.0; \ } while(0) #define NT_MAT33_SET_TO_IDENTITY(M) do { \ M.m[0][0] = 1.0; M.m[0][1] = 0.0; M.m[0][2] = 0.0; \ M.m[1][0] = 0.0; M.m[1][1] = 1.0; M.m[1][2] = 0.0; \ M.m[2][0] = 0.0; M.m[2][1] = 0.0; M.m[2][2] = 1.0; \ } while(0) /*----------------------------------------------------------------------*/ /*----- prototypes ---------------------------------------------------*/ /*----------------------------------------------------------------------*/ int act_add_exts ( nt_opts * opts ); int act_cbl ( nt_opts * opts ); /* copy brick list */ int act_cci ( nt_opts * opts ); /* copy collapsed dimensions */ int act_check_hdrs ( nt_opts * opts ); /* check for valid hdr or nim */ int act_diff_hdrs ( nt_opts * opts ); int act_diff_hdr1s ( nt_opts * opts ); int act_diff_hdr2s ( nt_opts * opts ); int act_diff_nims ( nt_opts * opts ); int act_disp_ci ( nt_opts * opts ); /* display general collapsed data */ int act_disp_exts ( nt_opts * opts ); int act_disp_cext ( nt_opts * opts ); int act_disp_hdr ( nt_opts * opts ); int act_disp_hdr1 ( nt_opts * opts ); int act_disp_hdr2 ( nt_opts * opts ); int act_disp_nims ( nt_opts * opts ); int act_disp_anas ( nt_opts * opts ); int act_disp_ts ( nt_opts * opts ); /* display time series */ int act_mod_hdrs ( nt_opts * opts ); int act_mod_hdr2s ( nt_opts * opts ); int act_mod_nims ( nt_opts * opts ); int act_swap_hdrs ( nt_opts * opts ); int act_rm_ext ( nt_opts * opts ); int act_run_misc_tests( nt_opts * opts ); int act_strip ( nt_opts * opts ); /* strip extras from datasets */ field_s * get_hdr1_field( const char * fname, int show_fail ); field_s * get_hdr2_field( const char * fname, int show_fail ); field_s * get_nim_field( const char * fname, int show_fail ); const char * field_type_str (int type); int diff_hdr1s (nifti_1_header *s0, nifti_1_header *s1, int display); int diff_hdr1s_list(nifti_1_header *s0, nifti_1_header *s1, str_list *slist, int display); int diff_hdr2s (nifti_2_header *s0, nifti_2_header *s1, int display); int diff_hdr2s_list(nifti_2_header *s0, nifti_2_header *s1, str_list *slist, int display); int diff_nims (nifti_image *s0,nifti_image *s1, int display); int diff_nims_list(nifti_image *s0,nifti_image *s1,str_list *slist,int display); int add_int (int_list * ilist, int val); int add_string (str_list * slist, const char * str); int check_total_size ( const char *mesg, field_s *fields, int nfields, int tot_size); int clear_float_zeros( char * str ); int diff_field (field_s *fieldp, void * str0, void * str1, int nfields); int disp_cifti_extension ( const char *mesg, nifti1_extension * ext, int maxlen); int disp_nifti1_extension( const char *mesg, nifti1_extension * ext, int maxlen); int disp_field (const char *mesg,field_s *fieldp,void *str,int nfields,int header); int disp_field_s_list(const char * mesg, field_s *, int nfields); int disp_nt_opts ( const char *mesg, nt_opts * opts); int disp_raw_data (void * data, int type, int nvals, char space,int newline); int fill_cmd_string (nt_opts * opts, int argc, char * argv[]); int fill_field (field_s *fp, int type, int offset, int num, const char *name); int fill_hdr1_field_array(field_s * nh_fields); int fill_hdr2_field_array(field_s * nh_fields); int fill_nim1_field_array(field_s * nim_fields); int fill_nim2_field_array(field_s * nim_fields); int fill_ana_field_array(field_s * ah_fields); int modify_all_fields(void *basep, nt_opts *opts, field_s *fields, int flen); int modify_field (void * basep, field_s * field, const char * data); int process_opts (int argc, char * argv[], nt_opts * opts); int remove_ext_list (nifti_image * nim, const char ** elist, int len); int usage (char * prog, int level); int use_full (); int verify_opts (nt_opts * opts, char * prog); int write_hdr_to_file (nifti_1_header * nhdr, const char * fname); int write_hdr2_to_file(nifti_2_header * nhdr, const char * fname); /* wrappers for nifti reading functions (allow MAKE_IM) */ nifti_image * nt_image_read (nt_opts * opts, const char * fname, int doread); nifti_image * nt_read_bricks(nt_opts * opts, char * fname, int len, int64_t * list, nifti_brick_list * NBL); void * nt_read_header(const char * fname, int * nver, int * swapped, int check, int new_datatype, int64_t new_dim[8]); /* misc functions */ int nt_run_misc_nim_tests (nifti_image * nim); static int nt_disp_mat44_orient(const char * mesg, mat44 mat); static int nt_test_dmat44_quatern(nifti_image * nim); static double dmat44_max_fabs(nifti_dmat44 m); static double mat44_max_fabs(mat44 m); #endif /* _NIFTI_TOOL_H_ */ nifti_clib-3.0.1/nifticdf/000077500000000000000000000000001371325713600154135ustar00rootroot00000000000000nifti_clib-3.0.1/nifticdf/CMakeLists.txt000066400000000000000000000063021371325713600201540ustar00rootroot00000000000000set(NIFTI_CDFLIB_NAME ${NIFTI_PACKAGE_PREFIX}nifticdf) add_nifti_library(${NIFTI_CDFLIB_NAME} nifticdf.c ) set_target_properties( ${NIFTI_CDFLIB_NAME} PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_LIST_DIR}/nifticdf.h" ) target_compile_options(${NIFTI_CDFLIB_NAME} PRIVATE "-D__COMPILE_UNUSED_FUNCTIONS__") target_link_libraries(${NIFTI_CDFLIB_NAME} PUBLIC ${NIFTI_PACKAGE_PREFIX}niftiio) get_lib_version_vars("nifticdf_version.h" NIFTICDF_VERSION NIFTICDF_MAJOR_VERSION) if(BUILD_SHARED_LIBS) set_target_properties(${NIFTI_CDFLIB_NAME} PROPERTIES ${NIFTI_LIBRARY_PROPERTIES} VERSION ${NIFTICDF_VERSION} SOVERSION ${NIFTICDF_MAJOR_VERSION} ) endif() install_nifti_target(${NIFTI_CDFLIB_NAME}) if(NIFTI_BUILD_APPLICATIONS) add_nifti_executable(${NIFTI_PACKAGE_PREFIX}nifti_stats nifti_stats.c) target_link_libraries( ${NIFTI_PACKAGE_PREFIX}nifti_stats PUBLIC ${NIFTI_PACKAGE_PREFIX}niftiio ${NIFTI_PACKAGE_PREFIX}nifticdf) install_nifti_target(${NIFTI_PACKAGE_PREFIX}nifti_stats) install_man_page( ${NIFTI_PACKAGE_PREFIX}nifti_stats OPTS "--help-option=-help;--version-string=${NIFTICDF_VERSION};--no-info" ) endif() if(NIFTI_BUILD_TESTING AND NIFTI_BUILD_APPLICATIONS) foreach(DISTRIBUTION CORREL TTEST FTEST ZSCORE CHISQ BETA BINOM GAMMA POISSON NORMAL FTEST_NONC CHISQ_NONC LOGISTIC LAPLACE UNIFORM TTEST_NONC WEIBULL CHI INVGAUSS EXTVAL PVAL LOGPVAL LOG10PVAL ) add_test( NAME ${NIFTI_PACKAGE_PREFIX}nifti_stats_${DISTRIBUTION}_test COMMAND $ 0:4:1 ${DISTRIBUTION}) add_test( NAME q${NIFTI_PACKAGE_PREFIX}nifti_stats_${DISTRIBUTION}_test COMMAND $ -q 0:4:1 ${DISTRIBUTION}) add_test( NAME q1${NIFTI_PACKAGE_PREFIX}nifti_stats_${DISTRIBUTION}_test COMMAND $ -q 0:4:1 ${DISTRIBUTION} 1 1 1) add_test( NAME d${NIFTI_PACKAGE_PREFIX}nifti_stats_${DISTRIBUTION}_test COMMAND $ -d 0:4:1 ${DISTRIBUTION}) add_test( NAME d1${NIFTI_PACKAGE_PREFIX}nifti_stats_${DISTRIBUTION}_test COMMAND $ -d 0:4:1 ${DISTRIBUTION} 1 1 1) add_test( NAME 1${NIFTI_PACKAGE_PREFIX}nifti_stats_${DISTRIBUTION}_test COMMAND $ -1 0:4:1 ${DISTRIBUTION}) add_test( NAME 11${NIFTI_PACKAGE_PREFIX}nifti_stats_${DISTRIBUTION}_test COMMAND $ -1 0:4:1 ${DISTRIBUTION} 1 1 1) add_test( NAME z${NIFTI_PACKAGE_PREFIX}nifti_stats_${DISTRIBUTION}_test COMMAND $ -z 0:4:1 ${DISTRIBUTION}) add_test( NAME z1${NIFTI_PACKAGE_PREFIX}nifti_stats_${DISTRIBUTION}_test COMMAND $ -z 0:4:1 ${DISTRIBUTION} 1 1 1) add_test( NAME h${NIFTI_PACKAGE_PREFIX}nifti_stats_${DISTRIBUTION}_test COMMAND $ -h 0:4:1 ${DISTRIBUTION}) add_test( NAME h1${NIFTI_PACKAGE_PREFIX}nifti_stats_${DISTRIBUTION}_test COMMAND $ -h 0:4:1 ${DISTRIBUTION} 1 1 1) endforeach() endif() nifti_clib-3.0.1/nifticdf/Makefile000077500000000000000000000011131371325713600170520ustar00rootroot00000000000000include ../Makefile PROJNAME = nifticdflib INCFLAGS = $(NIFTI_INC) $(NIFTICDF_INC) SRCS=nifticdf.c OBJS=nifticdf.o depend: $(RM) -f depend.mk $(MAKE) depend.mk depend.mk: $(CC) $(DEPENDFLAGS) $(INCFLAGS) $(SRCS) >> depend.mk lib: libnifticdf.a test: $(TESTXFILES) nifticdf.o: nifticdf.c nifticdf.h $(CC) -c $(CFLAGS) $(USEZLIB) $(INCFLAGS) $< libnifticdf.a: $(OBJS) $(AR) -r libnifticdf.a $(OBJS) $(RANLIB) $@ nifti_stats: nifti_stats.c $(CC) $(CFLAGS) -o nifti_stats nifti_stats.c $(NIFTI_INCS) $(ZNZ_INCS) $(NIFTICDF_LIBS) $(NIFTI_LIBS) $(ZNZ_LIBS) include depend.mk nifti_clib-3.0.1/nifticdf/nifti_stats.c000066400000000000000000000075401371325713600201140ustar00rootroot00000000000000#include "nifti1.h" /* for the NIFTI_INTENT_* constants */ #include "nifticdf.h" #include #include #include int main( int argc , char *argv[] ) { double val , p , p1=0.0,p2=0.0,p3=0.0 ; double vbot,vtop,vdel ; int code , iarg=1 , doq=0 , dod=0 , doi=0 , doz=0 , doh=0 ; /*-- print some help for the pitiful user --*/ if( argc < 3 || strstr(argv[1],"help") != NULL ){ int ii ; printf("\n") ; printf("Demo program for computing NIfTI statistical functions.\n") ; printf("Usage: nifti_stats [-q|-d|-1|-z] val CODE [p1 p2 p3]\n") ; printf(" val can be a single number or in the form bot:top:step.\n") ; printf(" default ==> output p = Prob(statistic < val).\n") ; printf(" -q ==> output is 1-p.\n") ; printf(" -d ==> output is density.\n") ; printf(" -1 ==> output is x such that Prob(statistic < x) = val.\n") ; printf(" -z ==> output is z such that Normal cdf(z) = p(val).\n") ; printf(" -h ==> output is z such that 1/2-Normal cdf(z) = p(val).\n"); printf(" Allowable CODEs:\n") ; for( ii=NIFTI_FIRST_STATCODE ; ii <= NIFTI_LAST_STATCODE ; ii++ ){ printf(" %-10s",inam[ii]); if((ii-NIFTI_FIRST_STATCODE)%6==5)printf("\n"); } printf("\n") ; printf(" Following CODE are distributional parameters, as needed.\n"); printf("\n") ; printf("Results are written to stdout, 1 number per output line.\n") ; printf("Example (piping output into AFNI program 1dplot):\n") ; printf(" nifti_stats -d 0:4:.001 INVGAUSS 1 3 | 1dplot -dx 0.001 -stdin\n"); printf("\n") ; printf("Author - RW Cox - SSCC/NIMH/NIH/DHHS/USA/EARTH - March 2004\n") ; printf("\n") ; exit(0) ; } /*-- check first arg to see if it is an output option; if so, set the appropriate output flag to determine what to compute --*/ if( strcmp(argv[iarg],"-q") == 0 ){ doq = 1 ; iarg++ ; } else if( strcmp(argv[iarg],"-d") == 0 ){ dod = 1 ; iarg++ ; } else if( strcmp(argv[iarg],"-1") == 0 ){ doi = 1 ; iarg++ ; } else if( strcmp(argv[iarg],"-z") == 0 ){ doz = 1 ; iarg++ ; } else if( strcmp(argv[iarg],"-h") == 0 ){ doh = 1 ; iarg++ ; } /*-- get the value(s) to process --*/ vbot=vtop=vdel = 0.0 ; sscanf( argv[iarg++] , "%lf:%lf:%lf" , &vbot,&vtop,&vdel ) ; if( vbot >= vtop ) vdel = 0.0 ; if( vdel <= 0.0 ) vtop = vbot ; /*-- decode the CODE into the integer signifying the distribution --*/ code = nifti_intent_code(argv[iarg++]) ; if( code < 0 ){ fprintf(stderr,"illegal code=%s\n",argv[iarg-1]); exit(1); } /*-- get the parameters, if present (defaults are 0) --*/ if( argc > iarg ) p1 = strtod(argv[iarg++],NULL) ; if( argc > iarg ) p2 = strtod(argv[iarg++],NULL) ; if( argc > iarg ) p3 = strtod(argv[iarg++],NULL) ; /*-- loop over input value(s), compute output, write to stdout --*/ for( val=vbot ; val <= vtop ; val += vdel ){ if( doq ) /* output = 1-cdf */ p = nifti_stat2rcdf( val , code,p1,p2,p3 ) ; else if( dod ) /* output = density */ p = 1000.0*( nifti_stat2cdf(val+.001,code,p1,p2,p3) -nifti_stat2cdf(val ,code,p1,p2,p3)) ; else if( doi ) /* output = inverse */ p = nifti_cdf2stat( val , code,p1,p2,p3 ) ; else if( doz ) /* output = z score */ p = nifti_stat2zscore( val , code,p1,p2,p3 ) ; else if( doh ) /* output = halfz score */ p = nifti_stat2hzscore( val , code,p1,p2,p3 ) ; else /* output = cdf */ p = nifti_stat2cdf( val , code,p1,p2,p3 ) ; printf("%.9g\n",p) ; if( vdel <= 0.0 ) break ; /* the case of just 1 value */ } /*-- terminus est --*/ exit(0) ; } nifti_clib-3.0.1/nifticdf/nifticdf.c000066400000000000000000010647121371325713600173600ustar00rootroot00000000000000 /************************************************************************/ /** Functions to compute cumulative distributions and their inverses **/ /** for the NIfTI-1 statistical types. Much of this code is taken **/ /** from other sources. In particular, the cdflib functions by **/ /** Brown and Lovato make up the bulk of this file. That code **/ /** was placed in the public domain. The code by K. Krishnamoorthy **/ /** is also released for unrestricted use. Finally, the other parts **/ /** of this file (by RW Cox) are released to the public domain. **/ /** **/ /** Most of this file comprises a set of "static" functions, to be **/ /** called by the user-level functions at the very end of the file. **/ /** At the end of the file is a simple main program to drive these **/ /** functions. **/ /** **/ /** To find the user-level functions, search forward for the string **/ /** "nifti_", which will be at about line 11000. **/ /************************************************************************/ /*****==============================================================*****/ /***** Neither the National Institutes of Health (NIH), the DFWG, *****/ /***** nor any of the members or employees of these institutions *****/ /***** imply any warranty of usefulness of this material for any *****/ /***** purpose, and do not assume any liability for damages, *****/ /***** incidental or otherwise, caused by any use of this document. *****/ /***** If these conditions are not acceptable, do not use this! *****/ /*****==============================================================*****/ /************************************************************************/ #include "nifti1.h" /* for the NIFTI_INTENT_* constants */ #include "nifticdf.h" #include "nifticdf_version.h" #include #include #include #include #include /************************************************************************/ /************ Include all the cdflib functions here and now *************/ /************ [about 9900 lines of code below here] *************/ /************************************************************************/ /***=====================================================================***/ double algdiv(const double *a,const double *b) /* ----------------------------------------------------------------------- COMPUTATION OF LN(GAMMA(B)/GAMMA(A+B)) WHEN B .GE. 8 -------- IN THIS ALGORITHM, DEL(X) IS THE FUNCTION DEFINED BY LN(GAMMA(X)) = (X - 0.5)*LN(X) - X + 0.5*LN(2*PI) + DEL(X). ----------------------------------------------------------------------- */ { static double c0 = .833333333333333e-01; static double c1 = -.277777777760991e-02; static double c2 = .793650666825390e-03; static double c3 = -.595202931351870e-03; static double c4 = .837308034031215e-03; static double c5 = -.165322962780713e-02; static double algdiv,c,d,h,s11,s3,s5,s7,s9,t,u,v,w,x,x2,T1; /* .. .. Executable Statements .. */ if(*a <= *b) goto S10; h = *b/ *a; c = 1.0e0/(1.0e0+h); x = h/(1.0e0+h); d = *a+(*b-0.5e0); goto S20; S10: h = *a/ *b; c = h/(1.0e0+h); x = 1.0e0/(1.0e0+h); d = *b+(*a-0.5e0); S20: /* SET SN = (1 - X**N)/(1 - X) */ x2 = x*x; s3 = 1.0e0+(x+x2); s5 = 1.0e0+(x+x2*s3); s7 = 1.0e0+(x+x2*s5); s9 = 1.0e0+(x+x2*s7); s11 = 1.0e0+(x+x2*s9); /* SET W = DEL(B) - DEL(A + B) */ t = pow(1.0e0/ *b,2.0); w = ((((c5*s11*t+c4*s9)*t+c3*s7)*t+c2*s5)*t+c1*s3)*t+c0; w *= (c/ *b); /* COMBINE THE RESULTS */ T1 = *a/ *b; u = d*alnrel(&T1); v = *a*(log(*b)-1.0e0); if(u <= v) goto S30; algdiv = w-v-u; return algdiv; S30: algdiv = w-u-v; return algdiv; } /* END */ /***=====================================================================***/ double alngam(const double *x) /* ********************************************************************** double alngam(double *x) double precision LN of the GAMma function Function Returns the natural logarithm of GAMMA(X). Arguments X --> value at which scaled log gamma is to be returned X is DOUBLE PRECISION Method If X .le. 6.0, then use recursion to get X below 3 then apply rational approximation number 5236 of Hart et al, Computer Approximations, John Wiley and Sons, NY, 1968. If X .gt. 6.0, then use recursion to get X to at least 12 and then use formula 5423 of the same source. ********************************************************************** */ { #define hln2pi 0.91893853320467274178e0 static double coef[5] = { 0.83333333333333023564e-1,-0.27777777768818808e-2,0.79365006754279e-3, -0.594997310889e-3,0.8065880899e-3 }; static double scoefd[4] = { 0.62003838007126989331e2,0.9822521104713994894e1,-0.8906016659497461257e1, 0.1000000000000000000e1 }; static double scoefn[9] = { 0.62003838007127258804e2,0.36036772530024836321e2,0.20782472531792126786e2, 0.6338067999387272343e1,0.215994312846059073e1,0.3980671310203570498e0, 0.1093115956710439502e0,0.92381945590275995e-2,0.29737866448101651e-2 }; static int K1 = 9; static int K3 = 4; static int K5 = 5; static double alngam,offset,prod,xx; static int i,n; static double T2,T4,T6; /* .. .. Executable Statements .. */ if(!(*x <= 6.0e0)) goto S70; prod = 1.0e0; xx = *x; if(!(*x > 3.0e0)) goto S30; S10: if(!(xx > 3.0e0)) goto S20; xx -= 1.0e0; prod *= xx; goto S10; S30: S20: if(!(*x < 2.0e0)) goto S60; S40: if(!(xx < 2.0e0)) goto S50; prod /= xx; xx += 1.0e0; goto S40; S60: S50: T2 = xx-2.0e0; T4 = xx-2.0e0; alngam = devlpl(scoefn,&K1,&T2)/devlpl(scoefd,&K3,&T4); /* COMPUTE RATIONAL APPROXIMATION TO GAMMA(X) */ alngam *= prod; alngam = log(alngam); goto S110; S70: offset = hln2pi; /* IF NECESSARY MAKE X AT LEAST 12 AND CARRY CORRECTION IN OFFSET */ n = fifidint(12.0e0-*x); if(!(n > 0)) goto S90; prod = 1.0e0; for(i=1; i<=n; i++) prod *= (*x+(double)(i-1)); offset -= log(prod); xx = *x+(double)n; goto S100; S90: xx = *x; S100: /* COMPUTE POWER SERIES */ T6 = 1.0e0/pow(xx,2.0); alngam = devlpl(coef,&K5,&T6)/xx; alngam += (offset+(xx-0.5e0)*log(xx)-xx); S110: return alngam; #undef hln2pi } /* END */ /***=====================================================================***/ double alnrel(const double *a) /* ----------------------------------------------------------------------- EVALUATION OF THE FUNCTION LN(1 + A) ----------------------------------------------------------------------- */ { static double p1 = -.129418923021993e+01; static double p2 = .405303492862024e+00; static double p3 = -.178874546012214e-01; static double q1 = -.162752256355323e+01; static double q2 = .747811014037616e+00; static double q3 = -.845104217945565e-01; static double alnrel,t,t2,w,x; /* .. .. Executable Statements .. */ if(fabs(*a) > 0.375e0) goto S10; t = *a/(*a+2.0e0); t2 = t*t; w = (((p3*t2+p2)*t2+p1)*t2+1.0e0)/(((q3*t2+q2)*t2+q1)*t2+1.0e0); alnrel = 2.0e0*t*w; return alnrel; S10: x = 1.e0+*a; alnrel = log(x); return alnrel; } /* END */ /***=====================================================================***/ double apser(const double *a,double *b,const double *x,const double *eps) /* ----------------------------------------------------------------------- APSER YIELDS THE INCOMPLETE BETA RATIO I(SUB(1-X))(B,A) FOR A .LE. MIN(EPS,EPS*B), B*X .LE. 1, AND X .LE. 0.5. USED WHEN A IS VERY SMALL. USE ONLY IF ABOVE INEQUALITIES ARE SATISFIED. ----------------------------------------------------------------------- */ { static double g = .577215664901533e0; static double apser,aj,bx,c,j,s,t,tol; /* .. .. Executable Statements .. */ bx = *b**x; t = *x-bx; if(*b**eps > 2.e-2) goto S10; c = log(*x)+psi(b)+g+t; goto S20; S10: c = log(bx)+g+t; S20: tol = 5.0e0**eps*fabs(c); j = 1.0e0; s = 0.0e0; S30: j += 1.0e0; t *= (*x-bx/j); aj = t/j; s += aj; if(fabs(aj) > tol) goto S30; apser = -(*a*(c+s)); return apser; } /* END */ /***=====================================================================***/ double basym(double *a,double *b,const double *lambda,const double *eps) /* ----------------------------------------------------------------------- ASYMPTOTIC EXPANSION FOR IX(A,B) FOR LARGE A AND B. LAMBDA = (A + B)*Y - B AND EPS IS THE TOLERANCE USED. IT IS ASSUMED THAT LAMBDA IS NONNEGATIVE AND THAT A AND B ARE GREATER THAN OR EQUAL TO 15. ----------------------------------------------------------------------- */ { static double e0 = 1.12837916709551e0; static double e1 = .353553390593274e0; static int num = 20; /* ------------------------ ****** NUM IS THE MAXIMUM VALUE THAT N CAN TAKE IN THE DO LOOP ENDING AT STATEMENT 50. IT IS REQUIRED THAT NUM BE EVEN. THE ARRAYS A0, B0, C, D HAVE DIMENSION NUM + 1. ------------------------ E0 = 2/SQRT(PI) E1 = 2**(-3/2) ------------------------ */ static int K3 = 1; static double basym,bsum,dsum,f,h,h2,hn,j0,j1,r,r0,r1,s,sum,t,t0,t1,u,w,w0,z,z0, z2,zn,znm1; static int i,im1,imj,j,m,mm1,mmj,n,np1; static double a0[21],b0[21],c[21],d[21],T1,T2; /* .. .. Executable Statements .. */ basym = 0.0e0; if(*a >= *b) goto S10; h = *a/ *b; r0 = 1.0e0/(1.0e0+h); r1 = (*b-*a)/ *b; w0 = 1.0e0/sqrt(*a*(1.0e0+h)); goto S20; S10: h = *b/ *a; r0 = 1.0e0/(1.0e0+h); r1 = (*b-*a)/ *a; w0 = 1.0e0/sqrt(*b*(1.0e0+h)); S20: T1 = -(*lambda/ *a); T2 = *lambda/ *b; f = *a*rlog1(&T1)+*b*rlog1(&T2); t = exp(-f); if(t == 0.0e0) return basym; z0 = sqrt(f); z = 0.5e0*(z0/e1); z2 = f+f; a0[0] = 2.0e0/3.0e0*r1; c[0] = -(0.5e0*a0[0]); d[0] = -c[0]; j0 = 0.5e0/e0*erfc1(&K3,&z0); j1 = e1; sum = j0+d[0]*w0*j1; s = 1.0e0; h2 = h*h; hn = 1.0e0; w = w0; znm1 = z; zn = z2; for(n=2; n<=num; n+=2) { hn = h2*hn; a0[n-1] = 2.0e0*r0*(1.0e0+h*hn)/((double)n+2.0e0); np1 = n+1; s += hn; a0[np1-1] = 2.0e0*r1*s/((double)n+3.0e0); for(i=n; i<=np1; i++) { r = -(0.5e0*((double)i+1.0e0)); b0[0] = r*a0[0]; for(m=2; m<=i; m++) { bsum = 0.0e0; mm1 = m-1; for(j=1; j<=mm1; j++) { mmj = m-j; bsum += (((double)j*r-(double)mmj)*a0[j-1]*b0[mmj-1]); } b0[m-1] = r*a0[m-1]+bsum/(double)m; } c[i-1] = b0[i-1]/((double)i+1.0e0); dsum = 0.0e0; im1 = i-1; for(j=1; j<=im1; j++) { imj = i-j; dsum += (d[imj-1]*c[j-1]); } d[i-1] = -(dsum+c[i-1]); } j0 = e1*znm1+((double)n-1.0e0)*j0; j1 = e1*zn+(double)n*j1; znm1 = z2*znm1; zn = z2*zn; w = w0*w; t0 = d[n-1]*w*j0; w = w0*w; t1 = d[np1-1]*w*j1; sum += (t0+t1); if(fabs(t0)+fabs(t1) <= *eps*sum) goto S80; } S80: u = exp(-bcorr(a,b)); basym = e0*t*u*sum; return basym; } /* END */ /***=====================================================================***/ double bcorr(const double *a0,const double *b0) /* ----------------------------------------------------------------------- EVALUATION OF DEL(A0) + DEL(B0) - DEL(A0 + B0) WHERE LN(GAMMA(A)) = (A - 0.5)*LN(A) - A + 0.5*LN(2*PI) + DEL(A). IT IS ASSUMED THAT A0 .GE. 8 AND B0 .GE. 8. ----------------------------------------------------------------------- */ { static double c0 = .833333333333333e-01; static double c1 = -.277777777760991e-02; static double c2 = .793650666825390e-03; static double c3 = -.595202931351870e-03; static double c4 = .837308034031215e-03; static double c5 = -.165322962780713e-02; static double bcorr,a,b,c,h,s11,s3,s5,s7,s9,t,w,x,x2; /* .. .. Executable Statements .. */ a = fifdmin1(*a0,*b0); b = fifdmax1(*a0,*b0); h = a/b; c = h/(1.0e0+h); x = 1.0e0/(1.0e0+h); x2 = x*x; /* SET SN = (1 - X**N)/(1 - X) */ s3 = 1.0e0+(x+x2); s5 = 1.0e0+(x+x2*s3); s7 = 1.0e0+(x+x2*s5); s9 = 1.0e0+(x+x2*s7); s11 = 1.0e0+(x+x2*s9); /* SET W = DEL(B) - DEL(A + B) */ t = pow(1.0e0/b,2.0); w = ((((c5*s11*t+c4*s9)*t+c3*s7)*t+c2*s5)*t+c1*s3)*t+c0; w *= (c/b); /* COMPUTE DEL(A) + W */ t = pow(1.0e0/a,2.0); bcorr = (((((c5*t+c4)*t+c3)*t+c2)*t+c1)*t+c0)/a+w; return bcorr; } /* END */ /***=====================================================================***/ double betaln(const double *a0,const double *b0) /* ----------------------------------------------------------------------- EVALUATION OF THE LOGARITHM OF THE BETA FUNCTION ----------------------------------------------------------------------- E = 0.5*LN(2*PI) -------------------------- */ { static double e = .918938533204673e0; static double betaln,a,b,c,h,u,v,w,z; static int i,n; static double T1; /* .. .. Executable Statements .. */ a = fifdmin1(*a0,*b0); b = fifdmax1(*a0,*b0); if(a >= 8.0e0) goto S100; if(a >= 1.0e0) goto S20; /* ----------------------------------------------------------------------- PROCEDURE WHEN A .LT. 1 ----------------------------------------------------------------------- */ if(b >= 8.0e0) goto S10; T1 = a+b; betaln = gamln(&a)+(gamln(&b)-gamln(&T1)); return betaln; S10: betaln = gamln(&a)+algdiv(&a,&b); return betaln; S20: /* ----------------------------------------------------------------------- PROCEDURE WHEN 1 .LE. A .LT. 8 ----------------------------------------------------------------------- */ if(a > 2.0e0) goto S40; if(b > 2.0e0) goto S30; betaln = gamln(&a)+gamln(&b)-gsumln(&a,&b); return betaln; S30: w = 0.0e0; if(b < 8.0e0) goto S60; betaln = gamln(&a)+algdiv(&a,&b); return betaln; S40: /* REDUCTION OF A WHEN B .LE. 1000 */ if(b > 1000.0e0) goto S80; n = a-1.0e0; w = 1.0e0; for(i=1; i<=n; i++) { a -= 1.0e0; h = a/b; w *= (h/(1.0e0+h)); } w = log(w); if(b < 8.0e0) goto S60; betaln = w+gamln(&a)+algdiv(&a,&b); return betaln; S60: /* REDUCTION OF B WHEN B .LT. 8 */ n = b-1.0e0; z = 1.0e0; for(i=1; i<=n; i++) { b -= 1.0e0; z *= (b/(a+b)); } betaln = w+log(z)+(gamln(&a)+(gamln(&b)-gsumln(&a,&b))); return betaln; S80: /* REDUCTION OF A WHEN B .GT. 1000 */ n = a-1.0e0; w = 1.0e0; for(i=1; i<=n; i++) { a -= 1.0e0; w *= (a/(1.0e0+a/b)); } betaln = log(w)-(double)n*log(b)+(gamln(&a)+algdiv(&a,&b)); return betaln; S100: /* ----------------------------------------------------------------------- PROCEDURE WHEN A .GE. 8 ----------------------------------------------------------------------- */ w = bcorr(&a,&b); h = a/b; c = h/(1.0e0+h); u = -((a-0.5e0)*log(c)); v = b*alnrel(&h); if(u <= v) goto S110; betaln = -(0.5e0*log(b))+e+w-v-u; return betaln; S110: betaln = -(0.5e0*log(b))+e+w-u-v; return betaln; } /* END */ /***=====================================================================***/ double bfrac(double *a,double *b,double *x,double *y,const double *lambda, const double *eps) /* ----------------------------------------------------------------------- CONTINUED FRACTION EXPANSION FOR IX(A,B) WHEN A,B .GT. 1. IT IS ASSUMED THAT LAMBDA = (A + B)*Y - B. ----------------------------------------------------------------------- */ { static double bfrac,alpha,an,anp1,beta,bn,bnp1,c,c0,c1,e,n,p,r,r0,s,t,w,yp1; /* .. .. Executable Statements .. */ bfrac = brcomp(a,b,x,y); if(bfrac == 0.0e0) return bfrac; c = 1.0e0+*lambda; c0 = *b/ *a; c1 = 1.0e0+1.0e0/ *a; yp1 = *y+1.0e0; n = 0.0e0; p = 1.0e0; s = *a+1.0e0; an = 0.0e0; bn = anp1 = 1.0e0; bnp1 = c/c1; r = c1/c; S10: /* CONTINUED FRACTION CALCULATION */ n += 1.0e0; t = n/ *a; w = n*(*b-n)**x; e = *a/s; alpha = p*(p+c0)*e*e*(w**x); e = (1.0e0+t)/(c1+t+t); beta = n+w/s+e*(c+n*yp1); p = 1.0e0+t; s += 2.0e0; /* UPDATE AN, BN, ANP1, AND BNP1 */ t = alpha*an+beta*anp1; an = anp1; anp1 = t; t = alpha*bn+beta*bnp1; bn = bnp1; bnp1 = t; r0 = r; r = anp1/bnp1; if(fabs(r-r0) <= *eps*r) goto S20; /* RESCALE AN, BN, ANP1, AND BNP1 */ an /= bnp1; bn /= bnp1; anp1 = r; bnp1 = 1.0e0; goto S10; S20: /* TERMINATION */ bfrac *= r; return bfrac; } /* END */ /***=====================================================================***/ void bgrat(double *a,double *b,const double *x,const double *y,double *w, double *eps,int *ierr) /* ----------------------------------------------------------------------- ASYMPTOTIC EXPANSION FOR IX(A,B) WHEN A IS LARGER THAN B. THE RESULT OF THE EXPANSION IS ADDED TO W. IT IS ASSUMED THAT A .GE. 15 AND B .LE. 1. EPS IS THE TOLERANCE USED. IERR IS A VARIABLE THAT REPORTS THE STATUS OF THE RESULTS. ----------------------------------------------------------------------- */ { static double bm1,bp2n,cn,coef,dj,j,l,lnx,n2,nu,p,q,r,s,sum,t,t2,u,v,z; static int i,n,nm1; static double c[30],d[30],T1; /* .. .. Executable Statements .. */ bm1 = *b-0.5e0-0.5e0; nu = *a+0.5e0*bm1; if(*y > 0.375e0) goto S10; T1 = -*y; lnx = alnrel(&T1); goto S20; S10: lnx = log(*x); S20: z = -(nu*lnx); if(*b*z == 0.0e0) goto S70; /* COMPUTATION OF THE EXPANSION SET R = EXP(-Z)*Z**B/GAMMA(B) */ r = *b*(1.0e0+gam1(b))*exp(*b*log(z)); r *= (exp(*a*lnx)*exp(0.5e0*bm1*lnx)); u = algdiv(b,a)+*b*log(nu); u = r*exp(-u); if(u == 0.0e0) goto S70; grat1(b,&z,&r,&p,&q,eps); v = 0.25e0*pow(1.0e0/nu,2.0); t2 = 0.25e0*lnx*lnx; l = *w/u; j = q/r; sum = j; t = cn = 1.0e0; n2 = 0.0e0; for(n=1; n<=30; n++) { bp2n = *b+n2; j = (bp2n*(bp2n+1.0e0)*j+(z+bp2n+1.0e0)*t)*v; n2 += 2.0e0; t *= t2; cn /= (n2*(n2+1.0e0)); c[n-1] = cn; s = 0.0e0; if(n == 1) goto S40; nm1 = n-1; coef = *b-(double)n; for(i=1; i<=nm1; i++) { s += (coef*c[i-1]*d[n-i-1]); coef += *b; } S40: d[n-1] = bm1*cn+s/(double)n; dj = d[n-1]*j; sum += dj; if(sum <= 0.0e0) goto S70; if(fabs(dj) <= *eps*(sum+l)) goto S60; } S60: /* ADD THE RESULTS TO W */ *ierr = 0; *w += (u*sum); return; S70: /* THE EXPANSION CANNOT BE COMPUTED */ *ierr = 1; } /* END */ /***=====================================================================***/ double bpser(double *a,double *b,const double *x,const double *eps) /* ----------------------------------------------------------------------- POWER SERIES EXPANSION FOR EVALUATING IX(A,B) WHEN B .LE. 1 OR B*X .LE. 0.7. EPS IS THE TOLERANCE USED. ----------------------------------------------------------------------- */ { static double bpser,a0,apb,b0,c,n,sum,t,tol,u,w,z; static int i,m; /* .. .. Executable Statements .. */ bpser = 0.0e0; if(*x == 0.0e0) return bpser; /* ----------------------------------------------------------------------- COMPUTE THE FACTOR X**A/(A*BETA(A,B)) ----------------------------------------------------------------------- */ a0 = fifdmin1(*a,*b); if(a0 < 1.0e0) goto S10; z = *a*log(*x)-betaln(a,b); bpser = exp(z)/ *a; goto S100; S10: b0 = fifdmax1(*a,*b); if(b0 >= 8.0e0) goto S90; if(b0 > 1.0e0) goto S40; /* PROCEDURE FOR A0 .LT. 1 AND B0 .LE. 1 */ bpser = pow(*x,*a); if(bpser == 0.0e0) return bpser; apb = *a+*b; if(apb > 1.0e0) goto S20; z = 1.0e0+gam1(&apb); goto S30; S20: u = *a+*b-1.e0; z = (1.0e0+gam1(&u))/apb; S30: c = (1.0e0+gam1(a))*(1.0e0+gam1(b))/z; bpser *= (c*(*b/apb)); goto S100; S40: /* PROCEDURE FOR A0 .LT. 1 AND 1 .LT. B0 .LT. 8 */ u = gamln1(&a0); m = b0-1.0e0; if(m < 1) goto S60; c = 1.0e0; for(i=1; i<=m; i++) { b0 -= 1.0e0; c *= (b0/(a0+b0)); } u = log(c)+u; S60: z = *a*log(*x)-u; b0 -= 1.0e0; apb = a0+b0; if(apb > 1.0e0) goto S70; t = 1.0e0+gam1(&apb); goto S80; S70: u = a0+b0-1.e0; t = (1.0e0+gam1(&u))/apb; S80: bpser = exp(z)*(a0/ *a)*(1.0e0+gam1(&b0))/t; goto S100; S90: /* PROCEDURE FOR A0 .LT. 1 AND B0 .GE. 8 */ u = gamln1(&a0)+algdiv(&a0,&b0); z = *a*log(*x)-u; bpser = a0/ *a*exp(z); S100: if(bpser == 0.0e0 || *a <= 0.1e0**eps) return bpser; /* ----------------------------------------------------------------------- COMPUTE THE SERIES ----------------------------------------------------------------------- */ sum = n = 0.0e0; c = 1.0e0; tol = *eps/ *a; S110: n += 1.0e0; c *= ((0.5e0+(0.5e0-*b/n))**x); w = c/(*a+n); sum += w; if(fabs(w) > tol) goto S110; bpser *= (1.0e0+*a*sum); return bpser; } /* END */ /***=====================================================================***/ void bratio(const double *a,const double *b,const double *x,const double *y,double *w, double *w1,int *ierr) /* ----------------------------------------------------------------------- EVALUATION OF THE INCOMPLETE BETA FUNCTION IX(A,B) -------------------- IT IS ASSUMED THAT A AND B ARE NONNEGATIVE, AND THAT X .LE. 1 AND Y = 1 - X. BRATIO ASSIGNS W AND W1 THE VALUES W = IX(A,B) W1 = 1 - IX(A,B) IERR IS A VARIABLE THAT REPORTS THE STATUS OF THE RESULTS. IF NO INPUT ERRORS ARE DETECTED THEN IERR IS SET TO 0 AND W AND W1 ARE COMPUTED. OTHERWISE, IF AN ERROR IS DETECTED, THEN W AND W1 ARE ASSIGNED THE VALUE 0 AND IERR IS SET TO ONE OF THE FOLLOWING VALUES ... IERR = 1 IF A OR B IS NEGATIVE IERR = 2 IF A = B = 0 IERR = 3 IF X .LT. 0 OR X .GT. 1 IERR = 4 IF Y .LT. 0 OR Y .GT. 1 IERR = 5 IF X + Y .NE. 1 IERR = 6 IF X = A = 0 IERR = 7 IF Y = B = 0 -------------------- WRITTEN BY ALFRED H. MORRIS, JR. NAVAL SURFACE WARFARE CENTER DAHLGREN, VIRGINIA REVISED ... NOV 1991 ----------------------------------------------------------------------- */ { static int K1 = 1; static double a0,b0,eps,lambda,t,x0,y0,z; static int ierr1,ind,n; static double T2,T3,T4,T5; /* .. .. Executable Statements .. */ /* ****** EPS IS A MACHINE DEPENDENT CONSTANT. EPS IS THE SMALLEST FLOATING POINT NUMBER FOR WHICH 1.0 + EPS .GT. 1.0 */ eps = spmpar(&K1); *w = *w1 = 0.0e0; if(*a < 0.0e0 || *b < 0.0e0) goto S270; if(*a == 0.0e0 && *b == 0.0e0) goto S280; if(*x < 0.0e0 || *x > 1.0e0) goto S290; if(*y < 0.0e0 || *y > 1.0e0) goto S300; z = *x+*y-0.5e0-0.5e0; if(fabs(z) > 3.0e0*eps) goto S310; *ierr = 0; if(*x == 0.0e0) goto S210; if(*y == 0.0e0) goto S230; if(*a == 0.0e0) goto S240; if(*b == 0.0e0) goto S220; eps = fifdmax1(eps,1.e-15); if(fifdmax1(*a,*b) < 1.e-3*eps) goto S260; ind = 0; a0 = *a; b0 = *b; x0 = *x; y0 = *y; if(fifdmin1(a0,b0) > 1.0e0) goto S40; /* PROCEDURE FOR A0 .LE. 1 OR B0 .LE. 1 */ if(*x <= 0.5e0) goto S10; ind = 1; a0 = *b; b0 = *a; x0 = *y; y0 = *x; S10: if(b0 < fifdmin1(eps,eps*a0)) goto S90; if(a0 < fifdmin1(eps,eps*b0) && b0*x0 <= 1.0e0) goto S100; if(fifdmax1(a0,b0) > 1.0e0) goto S20; if(a0 >= fifdmin1(0.2e0,b0)) goto S110; if(pow(x0,a0) <= 0.9e0) goto S110; if(x0 >= 0.3e0) goto S120; n = 20; goto S140; S20: if(b0 <= 1.0e0) goto S110; if(x0 >= 0.3e0) goto S120; if(x0 >= 0.1e0) goto S30; if(pow(x0*b0,a0) <= 0.7e0) goto S110; S30: if(b0 > 15.0e0) goto S150; n = 20; goto S140; S40: /* PROCEDURE FOR A0 .GT. 1 AND B0 .GT. 1 */ if(*a > *b) goto S50; lambda = *a-(*a+*b)**x; goto S60; S50: lambda = (*a+*b)**y-*b; S60: if(lambda >= 0.0e0) goto S70; ind = 1; a0 = *b; b0 = *a; x0 = *y; y0 = *x; lambda = fabs(lambda); S70: if(b0 < 40.0e0 && b0*x0 <= 0.7e0) goto S110; if(b0 < 40.0e0) goto S160; if(a0 > b0) goto S80; if(a0 <= 100.0e0) goto S130; if(lambda > 0.03e0*a0) goto S130; goto S200; S80: if(b0 <= 100.0e0) goto S130; if(lambda > 0.03e0*b0) goto S130; goto S200; S90: /* EVALUATION OF THE APPROPRIATE ALGORITHM */ *w = fpser(&a0,&b0,&x0,&eps); *w1 = 0.5e0+(0.5e0-*w); goto S250; S100: *w1 = apser(&a0,&b0,&x0,&eps); *w = 0.5e0+(0.5e0-*w1); goto S250; S110: *w = bpser(&a0,&b0,&x0,&eps); *w1 = 0.5e0+(0.5e0-*w); goto S250; S120: *w1 = bpser(&b0,&a0,&y0,&eps); *w = 0.5e0+(0.5e0-*w1); goto S250; S130: T2 = 15.0e0*eps; *w = bfrac(&a0,&b0,&x0,&y0,&lambda,&T2); *w1 = 0.5e0+(0.5e0-*w); goto S250; S140: *w1 = bup(&b0,&a0,&y0,&x0,&n,&eps); b0 += (double)n; S150: T3 = 15.0e0*eps; bgrat(&b0,&a0,&y0,&x0,w1,&T3,&ierr1); *w = 0.5e0+(0.5e0-*w1); goto S250; S160: n = b0; b0 -= (double)n; if(b0 != 0.0e0) goto S170; n -= 1; b0 = 1.0e0; S170: *w = bup(&b0,&a0,&y0,&x0,&n,&eps); if(x0 > 0.7e0) goto S180; *w += bpser(&a0,&b0,&x0,&eps); *w1 = 0.5e0+(0.5e0-*w); goto S250; S180: if(a0 > 15.0e0) goto S190; n = 20; *w += bup(&a0,&b0,&x0,&y0,&n,&eps); a0 += (double)n; S190: T4 = 15.0e0*eps; bgrat(&a0,&b0,&x0,&y0,w,&T4,&ierr1); *w1 = 0.5e0+(0.5e0-*w); goto S250; S200: T5 = 100.0e0*eps; *w = basym(&a0,&b0,&lambda,&T5); *w1 = 0.5e0+(0.5e0-*w); goto S250; S210: /* TERMINATION OF THE PROCEDURE */ if(*a == 0.0e0) goto S320; S220: *w = 0.0e0; *w1 = 1.0e0; return; S230: if(*b == 0.0e0) goto S330; S240: *w = 1.0e0; *w1 = 0.0e0; return; S250: if(ind == 0) return; t = *w; *w = *w1; *w1 = t; return; S260: /* PROCEDURE FOR A AND B .LT. 1.E-3*EPS */ *w = *b/(*a+*b); *w1 = *a/(*a+*b); return; S270: /* ERROR RETURN */ *ierr = 1; return; S280: *ierr = 2; return; S290: *ierr = 3; return; S300: *ierr = 4; return; S310: *ierr = 5; return; S320: *ierr = 6; return; S330: *ierr = 7; } /* END */ /***=====================================================================***/ double brcmp1(int *mu,double *a,double *b,const double *x,const double *y) /* ----------------------------------------------------------------------- EVALUATION OF EXP(MU) * (X**A*Y**B/BETA(A,B)) ----------------------------------------------------------------------- */ { static double Const = .398942280401433e0; static double brcmp1,a0,apb,b0,c,e,h,lambda,lnx,lny,t,u,v,x0,y0,z; static int i,n; /* ----------------- CONST = 1/SQRT(2*PI) ----------------- */ static double T1,T2,T3,T4; /* .. .. Executable Statements .. */ a0 = fifdmin1(*a,*b); if(a0 >= 8.0e0) goto S130; if(*x > 0.375e0) goto S10; lnx = log(*x); T1 = -*x; lny = alnrel(&T1); goto S30; S10: if(*y > 0.375e0) goto S20; T2 = -*y; lnx = alnrel(&T2); lny = log(*y); goto S30; S20: lnx = log(*x); lny = log(*y); S30: z = *a*lnx+*b*lny; if(a0 < 1.0e0) goto S40; z -= betaln(a,b); brcmp1 = esum(mu,&z); return brcmp1; S40: /* ----------------------------------------------------------------------- PROCEDURE FOR A .LT. 1 OR B .LT. 1 ----------------------------------------------------------------------- */ b0 = fifdmax1(*a,*b); if(b0 >= 8.0e0) goto S120; if(b0 > 1.0e0) goto S70; /* ALGORITHM FOR B0 .LE. 1 */ brcmp1 = esum(mu,&z); if(brcmp1 == 0.0e0) return brcmp1; apb = *a+*b; if(apb > 1.0e0) goto S50; z = 1.0e0+gam1(&apb); goto S60; S50: u = *a+*b-1.e0; z = (1.0e0+gam1(&u))/apb; S60: c = (1.0e0+gam1(a))*(1.0e0+gam1(b))/z; brcmp1 = brcmp1*(a0*c)/(1.0e0+a0/b0); return brcmp1; S70: /* ALGORITHM FOR 1 .LT. B0 .LT. 8 */ u = gamln1(&a0); n = b0-1.0e0; if(n < 1) goto S90; c = 1.0e0; for(i=1; i<=n; i++) { b0 -= 1.0e0; c *= (b0/(a0+b0)); } u = log(c)+u; S90: z -= u; b0 -= 1.0e0; apb = a0+b0; if(apb > 1.0e0) goto S100; t = 1.0e0+gam1(&apb); goto S110; S100: u = a0+b0-1.e0; t = (1.0e0+gam1(&u))/apb; S110: brcmp1 = a0*esum(mu,&z)*(1.0e0+gam1(&b0))/t; return brcmp1; S120: /* ALGORITHM FOR B0 .GE. 8 */ u = gamln1(&a0)+algdiv(&a0,&b0); T3 = z-u; brcmp1 = a0*esum(mu,&T3); return brcmp1; S130: /* ----------------------------------------------------------------------- PROCEDURE FOR A .GE. 8 AND B .GE. 8 ----------------------------------------------------------------------- */ if(*a > *b) goto S140; h = *a/ *b; x0 = h/(1.0e0+h); y0 = 1.0e0/(1.0e0+h); lambda = *a-(*a+*b)**x; goto S150; S140: h = *b/ *a; x0 = 1.0e0/(1.0e0+h); y0 = h/(1.0e0+h); lambda = (*a+*b)**y-*b; S150: e = -(lambda/ *a); if(fabs(e) > 0.6e0) goto S160; u = rlog1(&e); goto S170; S160: u = e-log(*x/x0); S170: e = lambda/ *b; if(fabs(e) > 0.6e0) goto S180; v = rlog1(&e); goto S190; S180: v = e-log(*y/y0); S190: T4 = -(*a*u+*b*v); z = esum(mu,&T4); brcmp1 = Const*sqrt(*b*x0)*z*exp(-bcorr(a,b)); return brcmp1; } /* END */ /***=====================================================================***/ double brcomp(double *a,double *b,const double *x,const double *y) /* ----------------------------------------------------------------------- EVALUATION OF X**A*Y**B/BETA(A,B) ----------------------------------------------------------------------- */ { static double Const = .398942280401433e0; static double brcomp,a0,apb,b0,c,e,h,lambda,lnx,lny,t,u,v,x0,y0,z; static int i,n; /* ----------------- CONST = 1/SQRT(2*PI) ----------------- */ static double T1,T2; /* .. .. Executable Statements .. */ brcomp = 0.0e0; if(*x == 0.0e0 || *y == 0.0e0) return brcomp; a0 = fifdmin1(*a,*b); if(a0 >= 8.0e0) goto S130; if(*x > 0.375e0) goto S10; lnx = log(*x); T1 = -*x; lny = alnrel(&T1); goto S30; S10: if(*y > 0.375e0) goto S20; T2 = -*y; lnx = alnrel(&T2); lny = log(*y); goto S30; S20: lnx = log(*x); lny = log(*y); S30: z = *a*lnx+*b*lny; if(a0 < 1.0e0) goto S40; z -= betaln(a,b); brcomp = exp(z); return brcomp; S40: /* ----------------------------------------------------------------------- PROCEDURE FOR A .LT. 1 OR B .LT. 1 ----------------------------------------------------------------------- */ b0 = fifdmax1(*a,*b); if(b0 >= 8.0e0) goto S120; if(b0 > 1.0e0) goto S70; /* ALGORITHM FOR B0 .LE. 1 */ brcomp = exp(z); if(brcomp == 0.0e0) return brcomp; apb = *a+*b; if(apb > 1.0e0) goto S50; z = 1.0e0+gam1(&apb); goto S60; S50: u = *a+*b-1.e0; z = (1.0e0+gam1(&u))/apb; S60: c = (1.0e0+gam1(a))*(1.0e0+gam1(b))/z; brcomp = brcomp*(a0*c)/(1.0e0+a0/b0); return brcomp; S70: /* ALGORITHM FOR 1 .LT. B0 .LT. 8 */ u = gamln1(&a0); n = b0-1.0e0; if(n < 1) goto S90; c = 1.0e0; for(i=1; i<=n; i++) { b0 -= 1.0e0; c *= (b0/(a0+b0)); } u = log(c)+u; S90: z -= u; b0 -= 1.0e0; apb = a0+b0; if(apb > 1.0e0) goto S100; t = 1.0e0+gam1(&apb); goto S110; S100: u = a0+b0-1.e0; t = (1.0e0+gam1(&u))/apb; S110: brcomp = a0*exp(z)*(1.0e0+gam1(&b0))/t; return brcomp; S120: /* ALGORITHM FOR B0 .GE. 8 */ u = gamln1(&a0)+algdiv(&a0,&b0); brcomp = a0*exp(z-u); return brcomp; S130: /* ----------------------------------------------------------------------- PROCEDURE FOR A .GE. 8 AND B .GE. 8 ----------------------------------------------------------------------- */ if(*a > *b) goto S140; h = *a/ *b; x0 = h/(1.0e0+h); y0 = 1.0e0/(1.0e0+h); lambda = *a-(*a+*b)**x; goto S150; S140: h = *b/ *a; x0 = 1.0e0/(1.0e0+h); y0 = h/(1.0e0+h); lambda = (*a+*b)**y-*b; S150: e = -(lambda/ *a); if(fabs(e) > 0.6e0) goto S160; u = rlog1(&e); goto S170; S160: u = e-log(*x/x0); S170: e = lambda/ *b; if(fabs(e) > 0.6e0) goto S180; v = rlog1(&e); goto S190; S180: v = e-log(*y/y0); S190: z = exp(-(*a*u+*b*v)); brcomp = Const*sqrt(*b*x0)*z*exp(-bcorr(a,b)); return brcomp; } /* END */ /***=====================================================================***/ double bup(double *a,double *b,double *x,double *y,const int *n,const double *eps) /* ----------------------------------------------------------------------- EVALUATION OF IX(A,B) - IX(A+N,B) WHERE N IS A POSITIVE INTEGER. EPS IS THE TOLERANCE USED. ----------------------------------------------------------------------- */ { static int K1 = 1; static int K2 = 0; static double bup,ap1,apb,d,l,r,t,w; static int i,k,kp1,mu,nm1; /* .. .. Executable Statements .. */ /* OBTAIN THE SCALING FACTOR EXP(-MU) AND EXP(MU)*(X**A*Y**B/BETA(A,B))/A */ apb = *a+*b; ap1 = *a+1.0e0; mu = 0; d = 1.0e0; if(*n == 1 || *a < 1.0e0) goto S10; if(apb < 1.1e0*ap1) goto S10; mu = fabs(exparg(&K1)); k = exparg(&K2); if(k < mu) mu = k; t = mu; d = exp(-t); S10: bup = brcmp1(&mu,a,b,x,y)/ *a; if(*n == 1 || bup == 0.0e0) return bup; nm1 = *n-1; w = d; /* LET K BE THE INDEX OF THE MAXIMUM TERM */ k = 0; if(*b <= 1.0e0) goto S50; if(*y > 1.e-4) goto S20; k = nm1; goto S30; S20: r = (*b-1.0e0)**x/ *y-*a; if(r < 1.0e0) goto S50; k = t = nm1; if(r < t) k = r; S30: /* ADD THE INCREASING TERMS OF THE SERIES */ for(i=1; i<=k; i++) { l = i-1; d = (apb+l)/(ap1+l)**x*d; w += d; } if(k == nm1) goto S70; S50: /* ADD THE REMAINING TERMS OF THE SERIES */ kp1 = k+1; for(i=kp1; i<=nm1; i++) { l = i-1; d = (apb+l)/(ap1+l)**x*d; w += d; if(d <= *eps*w) goto S70; } S70: /* TERMINATE THE PROCEDURE */ bup *= w; return bup; } /* END */ /***=====================================================================***/ void cdfbet(const int *which,double *p,double *q,double *x,double *y, double *a,double *b,int *status,double *bound) /********************************************************************** void cdfbet(int *which,double *p,double *q,double *x,double *y, double *a,double *b,int *status,double *bound) Cumulative Distribution Function BETa Distribution Function Calculates any one parameter of the beta distribution given values for the others. Arguments WHICH --> Integer indicating which of the next four argument values is to be calculated from the others. Legal range: 1..4 iwhich = 1 : Calculate P and Q from X,Y,A and B iwhich = 2 : Calculate X and Y from P,Q,A and B iwhich = 3 : Calculate A from P,Q,X,Y and B iwhich = 4 : Calculate B from P,Q,X,Y and A P <--> The integral from 0 to X of the chi-square distribution. Input range: [0, 1]. Q <--> 1-P. Input range: [0, 1]. P + Q = 1.0. X <--> Upper limit of integration of beta density. Input range: [0,1]. Search range: [0,1] Y <--> 1-X. Input range: [0,1]. Search range: [0,1] X + Y = 1.0. A <--> The first parameter of the beta density. Input range: (0, +infinity). Search range: [1D-300,1D300] B <--> The second parameter of the beta density. Input range: (0, +infinity). Search range: [1D-300,1D300] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 4 if X + Y .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Cumulative distribution function (P) is calculated directly by code associated with the following reference. DiDinato, A. R. and Morris, A. H. Algorithm 708: Significant Digit Computation of the Incomplete Beta Function Ratios. ACM Trans. Math. Softw. 18 (1993), 360-373. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. Note The beta density is proportional to t^(A-1) * (1-t)^(B-1) **********************************************************************/ { #define tol (1.0e-8) #define atol (1.0e-50) #define zero (1.0e-300) #define inf 1.0e300 #define one 1.0e0 static int K1 = 1; static double K2 = 0.0e0; static double K3 = 1.0e0; static double K8 = 0.5e0; static double K9 = 5.0e0; static double fx,xhi,xlo,cum,ccum,xy,pq; static unsigned long qhi,qleft,qporq; static double T4,T5,T6,T7,T10,T11,T12,T13,T14,T15; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q < 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q < 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 2) goto S150; /* X */ if(!(*x < 0.0e0 || *x > 1.0e0)) goto S140; if(!(*x < 0.0e0)) goto S120; *bound = 0.0e0; goto S130; S120: *bound = 1.0e0; S130: *status = -4; return; S150: S140: if(*which == 2) goto S190; /* Y */ if(!(*y < 0.0e0 || *y > 1.0e0)) goto S180; if(!(*y < 0.0e0)) goto S160; *bound = 0.0e0; goto S170; S160: *bound = 1.0e0; S170: *status = -5; return; S190: S180: if(*which == 3) goto S210; /* A */ if(!(*a <= 0.0e0)) goto S200; *bound = 0.0e0; *status = -6; return; S210: S200: if(*which == 4) goto S230; /* B */ if(!(*b <= 0.0e0)) goto S220; *bound = 0.0e0; *status = -7; return; S230: S220: if(*which == 1) goto S270; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S260; if(!(pq < 0.0e0)) goto S240; *bound = 0.0e0; goto S250; S240: *bound = 1.0e0; S250: *status = 3; return; S270: S260: if(*which == 2) goto S310; /* X + Y */ xy = *x+*y; if(!(fabs(xy-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S300; if(!(xy < 0.0e0)) goto S280; *bound = 0.0e0; goto S290; S280: *bound = 1.0e0; S290: *status = 4; return; S310: S300: if(!(*which == 1)) qporq = *p <= *q; /* Select the minimum of P or Q Calculate ANSWERS */ if(1 == *which) { /* Calculating P and Q */ cumbet(x,y,a,b,p,q); *status = 0; } else if(2 == *which) { /* Calculating X and Y */ T4 = atol; T5 = tol; dstzr(&K2,&K3,&T4,&T5); if(!qporq) goto S340; *status = 0; dzror(status,x,&fx,&xlo,&xhi,&qleft,&qhi); *y = one-*x; S320: if(!(*status == 1)) goto S330; cumbet(x,y,a,b,&cum,&ccum); fx = cum-*p; dzror(status,x,&fx,&xlo,&xhi,&qleft,&qhi); *y = one-*x; goto S320; S330: goto S370; S340: *status = 0; dzror(status,y,&fx,&xlo,&xhi,&qleft,&qhi); *x = one-*y; S350: if(!(*status == 1)) goto S360; cumbet(x,y,a,b,&cum,&ccum); fx = ccum-*q; dzror(status,y,&fx,&xlo,&xhi,&qleft,&qhi); *x = one-*y; goto S350; S370: S360: if(!(*status == -1)) goto S400; if(!qleft) goto S380; *status = 1; *bound = 0.0e0; goto S390; S380: *status = 2; *bound = 1.0e0; S400: S390: ; } else if(3 == *which) { /* Computing A */ *a = 5.0e0; T6 = zero; T7 = inf; T10 = atol; T11 = tol; dstinv(&T6,&T7,&K8,&K8,&K9,&T10,&T11); *status = 0; dinvr(status,a,&fx,&qleft,&qhi); S410: if(!(*status == 1)) goto S440; cumbet(x,y,a,b,&cum,&ccum); if(!qporq) goto S420; fx = cum-*p; goto S430; S420: fx = ccum-*q; S430: dinvr(status,a,&fx,&qleft,&qhi); goto S410; S440: if(!(*status == -1)) goto S470; if(!qleft) goto S450; *status = 1; *bound = zero; goto S460; S450: *status = 2; *bound = inf; S470: S460: ; } else if(4 == *which) { /* Computing B */ *b = 5.0e0; T12 = zero; T13 = inf; T14 = atol; T15 = tol; dstinv(&T12,&T13,&K8,&K8,&K9,&T14,&T15); *status = 0; dinvr(status,b,&fx,&qleft,&qhi); S480: if(!(*status == 1)) goto S510; cumbet(x,y,a,b,&cum,&ccum); if(!qporq) goto S490; fx = cum-*p; goto S500; S490: fx = ccum-*q; S500: dinvr(status,b,&fx,&qleft,&qhi); goto S480; S510: if(!(*status == -1)) goto S540; if(!qleft) goto S520; *status = 1; *bound = zero; goto S530; S520: *status = 2; *bound = inf; S530: ; } S540: return; #undef tol #undef atol #undef zero #undef inf #undef one } /* END */ /***=====================================================================***/ void cdfbin(const int *which,double *p,double *q,double *s,double *xn, double *pr,double *ompr,int *status,double *bound) /********************************************************************** void cdfbin(int *which,double *p,double *q,double *s,double *xn, double *pr,double *ompr,int *status,double *bound) Cumulative Distribution Function BINomial distribution Function Calculates any one parameter of the binomial distribution given values for the others. Arguments WHICH --> Integer indicating which of the next four argument values is to be calculated from the others. Legal range: 1..4 iwhich = 1 : Calculate P and Q from S,XN,PR and OMPR iwhich = 2 : Calculate S from P,Q,XN,PR and OMPR iwhich = 3 : Calculate XN from P,Q,S,PR and OMPR iwhich = 4 : Calculate PR and OMPR from P,Q,S and XN P <--> The cumulation from 0 to S of the binomial distribution. (Probablility of S or fewer successes in XN trials each with probability of success PR.) Input range: [0,1]. Q <--> 1-P. Input range: [0, 1]. P + Q = 1.0. S <--> The number of successes observed. Input range: [0, XN] Search range: [0, XN] XN <--> The number of binomial trials. Input range: (0, +infinity). Search range: [1E-300, 1E300] PR <--> The probability of success in each binomial trial. Input range: [0,1]. Search range: [0,1] OMPR <--> 1-PR Input range: [0,1]. Search range: [0,1] PR + OMPR = 1.0 STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 4 if PR + OMPR .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.5.24 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the binomial distribution to the cumulative incomplete beta distribution. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. **********************************************************************/ { #define atol (1.0e-50) #define tol (1.0e-8) #define zero (1.0e-300) #define inf 1.0e300 #define one 1.0e0 static int K1 = 1; static double K2 = 0.0e0; static double K3 = 0.5e0; static double K4 = 5.0e0; static double K11 = 1.0e0; static double fx,xhi,xlo,cum,ccum,pq,prompr; static unsigned long qhi,qleft,qporq; static double T5,T6,T7,T8,T9,T10,T12,T13; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 && *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q < 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q < 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 3) goto S130; /* XN */ if(!(*xn <= 0.0e0)) goto S120; *bound = 0.0e0; *status = -5; return; S130: S120: if(*which == 2) goto S170; /* S */ if(!( *s < 0.0e0 || ( *which != 3 && *s > *xn ))) goto S160; if(!(*s < 0.0e0)) goto S140; *bound = 0.0e0; goto S150; S140: *bound = *xn; S150: *status = -4; return; S170: S160: if(*which == 4) goto S210; /* PR */ if(!(*pr < 0.0e0 || *pr > 1.0e0)) goto S200; if(!(*pr < 0.0e0)) goto S180; *bound = 0.0e0; goto S190; S180: *bound = 1.0e0; S190: *status = -6; return; S210: S200: if(*which == 4) goto S250; /* OMPR */ if(!(*ompr < 0.0e0 || *ompr > 1.0e0)) goto S240; if(!(*ompr < 0.0e0)) goto S220; *bound = 0.0e0; goto S230; S220: *bound = 1.0e0; S230: *status = -7; return; S250: S240: if(*which == 1) goto S290; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S280; if(!(pq < 0.0e0)) goto S260; *bound = 0.0e0; goto S270; S260: *bound = 1.0e0; S270: *status = 3; return; S290: S280: if(*which == 4) goto S330; /* PR + OMPR */ prompr = *pr+*ompr; if(!(fabs(prompr-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S320; if(!(prompr < 0.0e0)) goto S300; *bound = 0.0e0; goto S310; S300: *bound = 1.0e0; S310: *status = 4; return; S330: S320: if(!(*which == 1)) qporq = *p <= *q; /* Select the minimum of P or Q Calculate ANSWERS */ if(1 == *which) { /* Calculating P */ cumbin(s,xn,pr,ompr,p,q); *status = 0; } else if(2 == *which) { /* Calculating S */ *s = 5.0e0; T5 = atol; T6 = tol; dstinv(&K2,xn,&K3,&K3,&K4,&T5,&T6); *status = 0; dinvr(status,s,&fx,&qleft,&qhi); S340: if(!(*status == 1)) goto S370; cumbin(s,xn,pr,ompr,&cum,&ccum); if(!qporq) goto S350; fx = cum-*p; goto S360; S350: fx = ccum-*q; S360: dinvr(status,s,&fx,&qleft,&qhi); goto S340; S370: if(!(*status == -1)) goto S400; if(!qleft) goto S380; *status = 1; *bound = 0.0e0; goto S390; S380: *status = 2; *bound = *xn; S400: S390: ; } else if(3 == *which) { /* Calculating XN */ *xn = 5.0e0; T7 = zero; T8 = inf; T9 = atol; T10 = tol; dstinv(&T7,&T8,&K3,&K3,&K4,&T9,&T10); *status = 0; dinvr(status,xn,&fx,&qleft,&qhi); S410: if(!(*status == 1)) goto S440; cumbin(s,xn,pr,ompr,&cum,&ccum); if(!qporq) goto S420; fx = cum-*p; goto S430; S420: fx = ccum-*q; S430: dinvr(status,xn,&fx,&qleft,&qhi); goto S410; S440: if(!(*status == -1)) goto S470; if(!qleft) goto S450; *status = 1; *bound = zero; goto S460; S450: *status = 2; *bound = inf; S470: S460: ; } else if(4 == *which) { /* Calculating PR and OMPR */ T12 = atol; T13 = tol; dstzr(&K2,&K11,&T12,&T13); if(!qporq) goto S500; *status = 0; dzror(status,pr,&fx,&xlo,&xhi,&qleft,&qhi); *ompr = one-*pr; S480: if(!(*status == 1)) goto S490; cumbin(s,xn,pr,ompr,&cum,&ccum); fx = cum-*p; dzror(status,pr,&fx,&xlo,&xhi,&qleft,&qhi); *ompr = one-*pr; goto S480; S490: goto S530; S500: *status = 0; dzror(status,ompr,&fx,&xlo,&xhi,&qleft,&qhi); *pr = one-*ompr; S510: if(!(*status == 1)) goto S520; cumbin(s,xn,pr,ompr,&cum,&ccum); fx = ccum-*q; dzror(status,ompr,&fx,&xlo,&xhi,&qleft,&qhi); *pr = one-*ompr; goto S510; S530: S520: if(!(*status == -1)) goto S560; if(!qleft) goto S540; *status = 1; *bound = 0.0e0; goto S550; S540: *status = 2; *bound = 1.0e0; S550: ; } S560: return; #undef atol #undef tol #undef zero #undef inf #undef one } /* END */ /***=====================================================================***/ void cdfchi(const int *which,double *p,double *q,double *x,double *df, int *status,double *bound) /********************************************************************** void cdfchi(int *which,double *p,double *q,double *x,double *df, int *status,double *bound) Cumulative Distribution Function CHI-Square distribution Function Calculates any one parameter of the chi-square distribution given values for the others. Arguments WHICH --> Integer indicating which of the next three argument values is to be calculated from the others. Legal range: 1..3 iwhich = 1 : Calculate P and Q from X and DF iwhich = 2 : Calculate X from P,Q and DF iwhich = 3 : Calculate DF from P,Q and X P <--> The integral from 0 to X of the chi-square distribution. Input range: [0, 1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. X <--> Upper limit of integration of the non-central chi-square distribution. Input range: [0, +infinity). Search range: [0,1E300] DF <--> Degrees of freedom of the chi-square distribution. Input range: (0, +infinity). Search range: [ 1E-300, 1E300] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 10 indicates error returned from cumgam. See references in cdfgam BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.4.19 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the chisqure distribution to the incomplete distribution. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. **********************************************************************/ { #define tol (1.0e-8) #define atol (1.0e-50) #define zero (1.0e-300) #define inf 1.0e300 static int K1 = 1; static double K2 = 0.0e0; static double K4 = 0.5e0; static double K5 = 5.0e0; static double fx,cum,ccum,pq,porq; static unsigned long qhi,qleft,qporq; static double T3,T6,T7,T8,T9,T10,T11; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 3)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 3.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 2) goto S130; /* X */ if(!(*x < 0.0e0)) goto S120; *bound = 0.0e0; *status = -4; return; S130: S120: if(*which == 3) goto S150; /* DF */ if(!(*df <= 0.0e0)) goto S140; *bound = 0.0e0; *status = -5; return; S150: S140: if(*which == 1) goto S190; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S180; if(!(pq < 0.0e0)) goto S160; *bound = 0.0e0; goto S170; S160: *bound = 1.0e0; S170: *status = 3; return; S190: S180: if(*which == 1) goto S220; /* Select the minimum of P or Q */ qporq = *p <= *q; if(!qporq) goto S200; porq = *p; goto S210; S200: porq = *q; S220: S210: /* Calculate ANSWERS */ if(1 == *which) { /* Calculating P and Q */ *status = 0; cumchi(x,df,p,q); if(porq > 1.5e0) { *status = 10; return; } } else if(2 == *which) { /* Calculating X */ *x = 5.0e0; T3 = inf; T6 = atol; T7 = tol; dstinv(&K2,&T3,&K4,&K4,&K5,&T6,&T7); *status = 0; dinvr(status,x,&fx,&qleft,&qhi); S230: if(!(*status == 1)) goto S270; cumchi(x,df,&cum,&ccum); if(!qporq) goto S240; fx = cum-*p; goto S250; S240: fx = ccum-*q; S250: if(!(fx+porq > 1.5e0)) goto S260; *status = 10; return; S260: dinvr(status,x,&fx,&qleft,&qhi); goto S230; S270: if(!(*status == -1)) goto S300; if(!qleft) goto S280; *status = 1; *bound = 0.0e0; goto S290; S280: *status = 2; *bound = inf; S300: S290: ; } else if(3 == *which) { /* Calculating DF */ *df = 5.0e0; T8 = zero; T9 = inf; T10 = atol; T11 = tol; dstinv(&T8,&T9,&K4,&K4,&K5,&T10,&T11); *status = 0; dinvr(status,df,&fx,&qleft,&qhi); S310: if(!(*status == 1)) goto S350; cumchi(x,df,&cum,&ccum); if(!qporq) goto S320; fx = cum-*p; goto S330; S320: fx = ccum-*q; S330: if(!(fx+porq > 1.5e0)) goto S340; *status = 10; return; S340: dinvr(status,df,&fx,&qleft,&qhi); goto S310; S350: if(!(*status == -1)) goto S380; if(!qleft) goto S360; *status = 1; *bound = zero; goto S370; S360: *status = 2; *bound = inf; S370: ; } S380: return; #undef tol #undef atol #undef zero #undef inf } /* END */ /***=====================================================================***/ void cdfchn(const int *which,double *p,double *q,double *x,double *df, double *pnonc,int *status,double *bound) /********************************************************************** void cdfchn(int *which,double *p,double *q,double *x,double *df, double *pnonc,int *status,double *bound) Cumulative Distribution Function Non-central Chi-Square Function Calculates any one parameter of the non-central chi-square distribution given values for the others. Arguments WHICH --> Integer indicating which of the next three argument values is to be calculated from the others. Input range: 1..4 iwhich = 1 : Calculate P and Q from X and DF iwhich = 2 : Calculate X from P,DF and PNONC iwhich = 3 : Calculate DF from P,X and PNONC iwhich = 3 : Calculate PNONC from P,X and DF P <--> The integral from 0 to X of the non-central chi-square distribution. Input range: [0, 1-1E-16). Q <--> 1-P. Q is not used by this subroutine and is only included for similarity with other cdf* routines. X <--> Upper limit of integration of the non-central chi-square distribution. Input range: [0, +infinity). Search range: [0,1E300] DF <--> Degrees of freedom of the non-central chi-square distribution. Input range: (0, +infinity). Search range: [ 1E-300, 1E300] PNONC <--> Non-centrality parameter of the non-central chi-square distribution. Input range: [0, +infinity). Search range: [0,1E4] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.4.25 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to compute the cumulative distribution function. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. WARNING The computation time required for this routine is proportional to the noncentrality parameter (PNONC). Very large values of this parameter can consume immense computer resources. This is why the search range is bounded by 10,000. **********************************************************************/ { #define tent4 1.0e4 #define tol (1.0e-8) #define atol (1.0e-50) #define zero (1.0e-300) #define one (1.0e0-1.0e-16) #define inf 1.0e300 static double K1 = 0.0e0; static double K3 = 0.5e0; static double K4 = 5.0e0; static double fx,cum,ccum; static unsigned long qhi,qleft; static double T2,T5,T6,T7,T8,T9,T10,T11,T12,T13; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > one)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = one; S50: *status = -2; return; S70: S60: if(*which == 2) goto S90; /* X */ if(!(*x < 0.0e0)) goto S80; *bound = 0.0e0; *status = -4; return; S90: S80: if(*which == 3) goto S110; /* DF */ if(!(*df <= 0.0e0)) goto S100; *bound = 0.0e0; *status = -5; return; S110: S100: if(*which == 4) goto S130; /* PNONC */ if(!(*pnonc < 0.0e0)) goto S120; *bound = 0.0e0; *status = -6; return; S130: S120: /* Calculate ANSWERS */ if(1 == *which) { /* Calculating P and Q */ cumchn(x,df,pnonc,p,q); *status = 0; } else if(2 == *which) { /* Calculating X */ *x = 5.0e0; T2 = inf; T5 = atol; T6 = tol; dstinv(&K1,&T2,&K3,&K3,&K4,&T5,&T6); *status = 0; dinvr(status,x,&fx,&qleft,&qhi); S140: if(!(*status == 1)) goto S150; cumchn(x,df,pnonc,&cum,&ccum); fx = cum-*p; dinvr(status,x,&fx,&qleft,&qhi); goto S140; S150: if(!(*status == -1)) goto S180; if(!qleft) goto S160; *status = 1; *bound = 0.0e0; goto S170; S160: *status = 2; *bound = inf; S180: S170: ; } else if(3 == *which) { /* Calculating DF */ *df = 5.0e0; T7 = zero; T8 = inf; T9 = atol; T10 = tol; dstinv(&T7,&T8,&K3,&K3,&K4,&T9,&T10); *status = 0; dinvr(status,df,&fx,&qleft,&qhi); S190: if(!(*status == 1)) goto S200; cumchn(x,df,pnonc,&cum,&ccum); fx = cum-*p; dinvr(status,df,&fx,&qleft,&qhi); goto S190; S200: if(!(*status == -1)) goto S230; if(!qleft) goto S210; *status = 1; *bound = zero; goto S220; S210: *status = 2; *bound = inf; S230: S220: ; } else if(4 == *which) { /* Calculating PNONC */ *pnonc = 5.0e0; T11 = tent4; T12 = atol; T13 = tol; dstinv(&K1,&T11,&K3,&K3,&K4,&T12,&T13); *status = 0; dinvr(status,pnonc,&fx,&qleft,&qhi); S240: if(!(*status == 1)) goto S250; cumchn(x,df,pnonc,&cum,&ccum); fx = cum-*p; dinvr(status,pnonc,&fx,&qleft,&qhi); goto S240; S250: if(!(*status == -1)) goto S280; if(!qleft) goto S260; *status = 1; *bound = zero; goto S270; S260: *status = 2; *bound = tent4; S270: ; } S280: return; #undef tent4 #undef tol #undef atol #undef zero #undef one #undef inf } /* END */ /***=====================================================================***/ void cdff(const int *which,double *p,double *q,double *f,double *dfn, double *dfd,int *status,double *bound) /********************************************************************** void cdff(int *which,double *p,double *q,double *f,double *dfn, double *dfd,int *status,double *bound) Cumulative Distribution Function F distribution Function Calculates any one parameter of the F distribution given values for the others. Arguments WHICH --> Integer indicating which of the next four argument values is to be calculated from the others. Legal range: 1..4 iwhich = 1 : Calculate P and Q from F,DFN and DFD iwhich = 2 : Calculate F from P,Q,DFN and DFD iwhich = 3 : Calculate DFN from P,Q,F and DFD iwhich = 4 : Calculate DFD from P,Q,F and DFN P <--> The integral from 0 to F of the f-density. Input range: [0,1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. F <--> Upper limit of integration of the f-density. Input range: [0, +infinity). Search range: [0,1E300] DFN < --> Degrees of freedom of the numerator sum of squares. Input range: (0, +infinity). Search range: [ 1E-300, 1E300] DFD < --> Degrees of freedom of the denominator sum of squares. Input range: (0, +infinity). Search range: [ 1E-300, 1E300] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.6.2 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the computation of the cumulative distribution function for the F variate to that of an incomplete beta. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. WARNING The value of the cumulative F distribution is not necessarily monotone in either degrees of freedom. There thus may be two values that provide a given CDF value. This routine assumes monotonicity and will find an arbitrary one of the two values. **********************************************************************/ { #define tol (1.0e-8) #define atol (1.0e-50) #define zero (1.0e-300) #define inf 1.0e300 static int K1 = 1; static double K2 = 0.0e0; static double K4 = 0.5e0; static double K5 = 5.0e0; static double pq,fx,cum,ccum; static unsigned long qhi,qleft,qporq; static double T3,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 2) goto S130; /* F */ if(!(*f < 0.0e0)) goto S120; *bound = 0.0e0; *status = -4; return; S130: S120: if(*which == 3) goto S150; /* DFN */ if(!(*dfn <= 0.0e0)) goto S140; *bound = 0.0e0; *status = -5; return; S150: S140: if(*which == 4) goto S170; /* DFD */ if(!(*dfd <= 0.0e0)) goto S160; *bound = 0.0e0; *status = -6; return; S170: S160: if(*which == 1) goto S210; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S200; if(!(pq < 0.0e0)) goto S180; *bound = 0.0e0; goto S190; S180: *bound = 1.0e0; S190: *status = 3; return; S210: S200: if(!(*which == 1)) qporq = *p <= *q; /* Select the minimum of P or Q Calculate ANSWERS */ if(1 == *which) { /* Calculating P */ cumf(f,dfn,dfd,p,q); *status = 0; } else if(2 == *which) { /* Calculating F */ *f = 5.0e0; T3 = inf; T6 = atol; T7 = tol; dstinv(&K2,&T3,&K4,&K4,&K5,&T6,&T7); *status = 0; dinvr(status,f,&fx,&qleft,&qhi); S220: if(!(*status == 1)) goto S250; cumf(f,dfn,dfd,&cum,&ccum); if(!qporq) goto S230; fx = cum-*p; goto S240; S230: fx = ccum-*q; S240: dinvr(status,f,&fx,&qleft,&qhi); goto S220; S250: if(!(*status == -1)) goto S280; if(!qleft) goto S260; *status = 1; *bound = 0.0e0; goto S270; S260: *status = 2; *bound = inf; S280: S270: ; } else if(3 == *which) { /* Calculating DFN */ *dfn = 5.0e0; T8 = zero; T9 = inf; T10 = atol; T11 = tol; dstinv(&T8,&T9,&K4,&K4,&K5,&T10,&T11); *status = 0; dinvr(status,dfn,&fx,&qleft,&qhi); S290: if(!(*status == 1)) goto S320; cumf(f,dfn,dfd,&cum,&ccum); if(!qporq) goto S300; fx = cum-*p; goto S310; S300: fx = ccum-*q; S310: dinvr(status,dfn,&fx,&qleft,&qhi); goto S290; S320: if(!(*status == -1)) goto S350; if(!qleft) goto S330; *status = 1; *bound = zero; goto S340; S330: *status = 2; *bound = inf; S350: S340: ; } else if(4 == *which) { /* Calculating DFD */ *dfd = 5.0e0; T12 = zero; T13 = inf; T14 = atol; T15 = tol; dstinv(&T12,&T13,&K4,&K4,&K5,&T14,&T15); *status = 0; dinvr(status,dfd,&fx,&qleft,&qhi); S360: if(!(*status == 1)) goto S390; cumf(f,dfn,dfd,&cum,&ccum); if(!qporq) goto S370; fx = cum-*p; goto S380; S370: fx = ccum-*q; S380: dinvr(status,dfd,&fx,&qleft,&qhi); goto S360; S390: if(!(*status == -1)) goto S420; if(!qleft) goto S400; *status = 1; *bound = zero; goto S410; S400: *status = 2; *bound = inf; S410: ; } S420: return; #undef tol #undef atol #undef zero #undef inf } /* END */ /***=====================================================================***/ void cdffnc(const int *which,double *p,double *q,double *f,double *dfn, double *dfd,double *phonc,int *status,double *bound) /********************************************************************** void cdffnc(int *which,double *p,double *q,double *f,double *dfn, double *dfd,double *phonc,int *status,double *bound) Cumulative Distribution Function Non-central F distribution Function Calculates any one parameter of the Non-central F distribution given values for the others. Arguments WHICH --> Integer indicating which of the next five argument values is to be calculated from the others. Legal range: 1..5 iwhich = 1 : Calculate P and Q from F,DFN,DFD and PNONC iwhich = 2 : Calculate F from P,Q,DFN,DFD and PNONC iwhich = 3 : Calculate DFN from P,Q,F,DFD and PNONC iwhich = 4 : Calculate DFD from P,Q,F,DFN and PNONC iwhich = 5 : Calculate PNONC from P,Q,F,DFN and DFD P <--> The integral from 0 to F of the non-central f-density. Input range: [0,1-1E-16). Q <--> 1-P. Q is not used by this subroutine and is only included for similarity with other cdf* routines. F <--> Upper limit of integration of the non-central f-density. Input range: [0, +infinity). Search range: [0,1E300] DFN < --> Degrees of freedom of the numerator sum of squares. Input range: (0, +infinity). Search range: [ 1E-300, 1E300] DFD < --> Degrees of freedom of the denominator sum of squares. Must be in range: (0, +infinity). Input range: (0, +infinity). Search range: [ 1E-300, 1E300] PNONC <-> The non-centrality parameter Input range: [0,infinity) Search range: [0,1E4] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.6.20 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to compute the cumulative distribution function. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. WARNING The computation time required for this routine is proportional to the noncentrality parameter (PNONC). Very large values of this parameter can consume immense computer resources. This is why the search range is bounded by 10,000. WARNING The value of the cumulative noncentral F distribution is not necessarily monotone in either degrees of freedom. There thus may be two values that provide a given CDF value. This routine assumes monotonicity and will find an arbitrary one of the two values. **********************************************************************/ { #define tent4 1.0e4 #define tol (1.0e-8) #define atol (1.0e-50) #define zero (1.0e-300) #define one (1.0e0-1.0e-16) #define inf 1.0e300 static double K1 = 0.0e0; static double K3 = 0.5e0; static double K4 = 5.0e0; static double fx,cum,ccum; static unsigned long qhi,qleft; static double T2,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 5)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 5.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > one)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = one; S50: *status = -2; return; S70: S60: if(*which == 2) goto S90; /* F */ if(!(*f < 0.0e0)) goto S80; *bound = 0.0e0; *status = -4; return; S90: S80: if(*which == 3) goto S110; /* DFN */ if(!(*dfn <= 0.0e0)) goto S100; *bound = 0.0e0; *status = -5; return; S110: S100: if(*which == 4) goto S130; /* DFD */ if(!(*dfd <= 0.0e0)) goto S120; *bound = 0.0e0; *status = -6; return; S130: S120: if(*which == 5) goto S150; /* PHONC */ if(!(*phonc < 0.0e0)) goto S140; *bound = 0.0e0; *status = -7; return; S150: S140: /* Calculate ANSWERS */ if(1 == *which) { /* Calculating P */ cumfnc(f,dfn,dfd,phonc,p,q); *status = 0; } else if(2 == *which) { /* Calculating F */ *f = 5.0e0; T2 = inf; T5 = atol; T6 = tol; dstinv(&K1,&T2,&K3,&K3,&K4,&T5,&T6); *status = 0; dinvr(status,f,&fx,&qleft,&qhi); S160: if(!(*status == 1)) goto S170; cumfnc(f,dfn,dfd,phonc,&cum,&ccum); fx = cum-*p; dinvr(status,f,&fx,&qleft,&qhi); goto S160; S170: if(!(*status == -1)) goto S200; if(!qleft) goto S180; *status = 1; *bound = 0.0e0; goto S190; S180: *status = 2; *bound = inf; S200: S190: ; } else if(3 == *which) { /* Calculating DFN */ *dfn = 5.0e0; T7 = zero; T8 = inf; T9 = atol; T10 = tol; dstinv(&T7,&T8,&K3,&K3,&K4,&T9,&T10); *status = 0; dinvr(status,dfn,&fx,&qleft,&qhi); S210: if(!(*status == 1)) goto S220; cumfnc(f,dfn,dfd,phonc,&cum,&ccum); fx = cum-*p; dinvr(status,dfn,&fx,&qleft,&qhi); goto S210; S220: if(!(*status == -1)) goto S250; if(!qleft) goto S230; *status = 1; *bound = zero; goto S240; S230: *status = 2; *bound = inf; S250: S240: ; } else if(4 == *which) { /* Calculating DFD */ *dfd = 5.0e0; T11 = zero; T12 = inf; T13 = atol; T14 = tol; dstinv(&T11,&T12,&K3,&K3,&K4,&T13,&T14); *status = 0; dinvr(status,dfd,&fx,&qleft,&qhi); S260: if(!(*status == 1)) goto S270; cumfnc(f,dfn,dfd,phonc,&cum,&ccum); fx = cum-*p; dinvr(status,dfd,&fx,&qleft,&qhi); goto S260; S270: if(!(*status == -1)) goto S300; if(!qleft) goto S280; *status = 1; *bound = zero; goto S290; S280: *status = 2; *bound = inf; S300: S290: ; } else if(5 == *which) { /* Calculating PHONC */ *phonc = 5.0e0; T15 = tent4; T16 = atol; T17 = tol; dstinv(&K1,&T15,&K3,&K3,&K4,&T16,&T17); *status = 0; dinvr(status,phonc,&fx,&qleft,&qhi); S310: if(!(*status == 1)) goto S320; cumfnc(f,dfn,dfd,phonc,&cum,&ccum); fx = cum-*p; dinvr(status,phonc,&fx,&qleft,&qhi); goto S310; S320: if(!(*status == -1)) goto S350; if(!qleft) goto S330; *status = 1; *bound = 0.0e0; goto S340; S330: *status = 2; *bound = tent4; S340: ; } S350: return; #undef tent4 #undef tol #undef atol #undef zero #undef one #undef inf } /* END */ /***=====================================================================***/ void cdfgam(const int *which,double *p,double *q,double *x,double *shape, double *scale,int *status,double *bound) /********************************************************************** void cdfgam(int *which,double *p,double *q,double *x,double *shape, double *scale,int *status,double *bound) Cumulative Distribution Function GAMma Distribution Function Calculates any one parameter of the gamma distribution given values for the others. Arguments WHICH --> Integer indicating which of the next four argument values is to be calculated from the others. Legal range: 1..4 iwhich = 1 : Calculate P and Q from X,SHAPE and SCALE iwhich = 2 : Calculate X from P,Q,SHAPE and SCALE iwhich = 3 : Calculate SHAPE from P,Q,X and SCALE iwhich = 4 : Calculate SCALE from P,Q,X and SHAPE P <--> The integral from 0 to X of the gamma density. Input range: [0,1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. X <--> The upper limit of integration of the gamma density. Input range: [0, +infinity). Search range: [0,1E300] SHAPE <--> The shape parameter of the gamma density. Input range: (0, +infinity). Search range: [1E-300,1E300] SCALE <--> The scale parameter of the gamma density. Input range: (0, +infinity). Search range: (1E-300,1E300] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 10 if the gamma or inverse gamma routine cannot compute the answer. Usually happens only for X and SHAPE very large (gt 1E10 or more) BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Cumulative distribution function (P) is calculated directly by the code associated with: DiDinato, A. R. and Morris, A. H. Computation of the incomplete gamma function ratios and their inverse. ACM Trans. Math. Softw. 12 (1986), 377-393. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. Note The gamma density is proportional to T**(SHAPE - 1) * EXP(- SCALE * T) **********************************************************************/ { #define tol (1.0e-8) #define atol (1.0e-50) #define zero (1.0e-300) #define inf 1.0e300 static int K1 = 1; static double K5 = 0.5e0; static double K6 = 5.0e0; static double xx,fx,xscale,cum,ccum,pq,porq; static int ierr; static unsigned long qhi,qleft,qporq; static double T2,T3,T4,T7,T8,T9; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 2) goto S130; /* X */ if(!(*x < 0.0e0)) goto S120; *bound = 0.0e0; *status = -4; return; S130: S120: if(*which == 3) goto S150; /* SHAPE */ if(!(*shape <= 0.0e0)) goto S140; *bound = 0.0e0; *status = -5; return; S150: S140: if(*which == 4) goto S170; /* SCALE */ if(!(*scale <= 0.0e0)) goto S160; *bound = 0.0e0; *status = -6; return; S170: S160: if(*which == 1) goto S210; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S200; if(!(pq < 0.0e0)) goto S180; *bound = 0.0e0; goto S190; S180: *bound = 1.0e0; S190: *status = 3; return; S210: S200: if(*which == 1) goto S240; /* Select the minimum of P or Q */ qporq = *p <= *q; if(!qporq) goto S220; porq = *p; goto S230; S220: porq = *q; S240: S230: /* Calculate ANSWERS */ if(1 == *which) { /* Calculating P */ *status = 0; xscale = *x**scale; cumgam(&xscale,shape,p,q); if(porq > 1.5e0) *status = 10; } else if(2 == *which) { /* Computing X */ T2 = -1.0e0; gaminv(shape,&xx,&T2,p,q,&ierr); if(ierr < 0.0e0) { *status = 10; return; } else { *x = xx/ *scale; *status = 0; } } else if(3 == *which) { /* Computing SHAPE */ *shape = 5.0e0; xscale = *x**scale; T3 = zero; T4 = inf; T7 = atol; T8 = tol; dstinv(&T3,&T4,&K5,&K5,&K6,&T7,&T8); *status = 0; dinvr(status,shape,&fx,&qleft,&qhi); S250: if(!(*status == 1)) goto S290; cumgam(&xscale,shape,&cum,&ccum); if(!qporq) goto S260; fx = cum-*p; goto S270; S260: fx = ccum-*q; S270: if(!(( qporq && cum > 1.5e0 ) || (!qporq && ccum > 1.5e0 ))) goto S280; *status = 10; return; S280: dinvr(status,shape,&fx,&qleft,&qhi); goto S250; S290: if(!(*status == -1)) goto S320; if(!qleft) goto S300; *status = 1; *bound = zero; goto S310; S300: *status = 2; *bound = inf; S320: S310: ; } else if(4 == *which) { /* Computing SCALE */ T9 = -1.0e0; gaminv(shape,&xx,&T9,p,q,&ierr); if(ierr < 0.0e0) { *status = 10; return; } else { *scale = xx/ *x; *status = 0; } } #undef tol #undef atol #undef zero #undef inf } /* END */ #if defined(__COMPILE_UNUSED_FUNCTIONS__) /***=====================================================================***/ void cdfnbn(int *which,double *p,double *q,double *s,double *xn, double *pr,double *ompr,int *status,double *bound) /********************************************************************** void cdfnbn(int *which,double *p,double *q,double *s,double *xn, double *pr,double *ompr,int *status,double *bound) Cumulative Distribution Function Negative BiNomial distribution Function Calculates any one parameter of the negative binomial distribution given values for the others. The cumulative negative binomial distribution returns the probability that there will be F or fewer failures before the XNth success in binomial trials each of which has probability of success PR. The individual term of the negative binomial is the probability of S failures before XN successes and is Choose( S, XN+S-1 ) * PR^(XN) * (1-PR)^S Arguments WHICH --> Integer indicating which of the next four argument values is to be calculated from the others. Legal range: 1..4 iwhich = 1 : Calculate P and Q from S,XN,PR and OMPR iwhich = 2 : Calculate S from P,Q,XN,PR and OMPR iwhich = 3 : Calculate XN from P,Q,S,PR and OMPR iwhich = 4 : Calculate PR and OMPR from P,Q,S and XN P <--> The cumulation from 0 to S of the negative binomial distribution. Input range: [0,1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. S <--> The upper limit of cumulation of the binomial distribution. There are F or fewer failures before the XNth success. Input range: [0, +infinity). Search range: [0, 1E300] XN <--> The number of successes. Input range: [0, +infinity). Search range: [0, 1E300] PR <--> The probability of success in each binomial trial. Input range: [0,1]. Search range: [0,1]. OMPR <--> 1-PR Input range: [0,1]. Search range: [0,1] PR + OMPR = 1.0 STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 4 if PR + OMPR .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.5.26 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce calculation of the cumulative distribution function to that of an incomplete beta. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. **********************************************************************/ { #define tol (1.0e-8) #define atol (1.0e-50) #define inf 1.0e300 #define one 1.0e0 static int K1 = 1; static double K2 = 0.0e0; static double K4 = 0.5e0; static double K5 = 5.0e0; static double K11 = 1.0e0; static double fx,xhi,xlo,pq,prompr,cum,ccum; static unsigned long qhi,qleft,qporq; static double T3,T6,T7,T8,T9,T10,T12,T13; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 2) goto S130; /* S */ if(!(*s < 0.0e0)) goto S120; *bound = 0.0e0; *status = -4; return; S130: S120: if(*which == 3) goto S150; /* XN */ if(!(*xn < 0.0e0)) goto S140; *bound = 0.0e0; *status = -5; return; S150: S140: if(*which == 4) goto S190; /* PR */ if(!(*pr < 0.0e0 || *pr > 1.0e0)) goto S180; if(!(*pr < 0.0e0)) goto S160; *bound = 0.0e0; goto S170; S160: *bound = 1.0e0; S170: *status = -6; return; S190: S180: if(*which == 4) goto S230; /* OMPR */ if(!(*ompr < 0.0e0 || *ompr > 1.0e0)) goto S220; if(!(*ompr < 0.0e0)) goto S200; *bound = 0.0e0; goto S210; S200: *bound = 1.0e0; S210: *status = -7; return; S230: S220: if(*which == 1) goto S270; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S260; if(!(pq < 0.0e0)) goto S240; *bound = 0.0e0; goto S250; S240: *bound = 1.0e0; S250: *status = 3; return; S270: S260: if(*which == 4) goto S310; /* PR + OMPR */ prompr = *pr+*ompr; if(!(fabs(prompr-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S300; if(!(prompr < 0.0e0)) goto S280; *bound = 0.0e0; goto S290; S280: *bound = 1.0e0; S290: *status = 4; return; S310: S300: if(!(*which == 1)) qporq = *p <= *q; /* Select the minimum of P or Q Calculate ANSWERS */ if(1 == *which) { /* Calculating P */ cumnbn(s,xn,pr,ompr,p,q); *status = 0; } else if(2 == *which) { /* Calculating S */ *s = 5.0e0; T3 = inf; T6 = atol; T7 = tol; dstinv(&K2,&T3,&K4,&K4,&K5,&T6,&T7); *status = 0; dinvr(status,s,&fx,&qleft,&qhi); S320: if(!(*status == 1)) goto S350; cumnbn(s,xn,pr,ompr,&cum,&ccum); if(!qporq) goto S330; fx = cum-*p; goto S340; S330: fx = ccum-*q; S340: dinvr(status,s,&fx,&qleft,&qhi); goto S320; S350: if(!(*status == -1)) goto S380; if(!qleft) goto S360; *status = 1; *bound = 0.0e0; goto S370; S360: *status = 2; *bound = inf; S380: S370: ; } else if(3 == *which) { /* Calculating XN */ *xn = 5.0e0; T8 = inf; T9 = atol; T10 = tol; dstinv(&K2,&T8,&K4,&K4,&K5,&T9,&T10); *status = 0; dinvr(status,xn,&fx,&qleft,&qhi); S390: if(!(*status == 1)) goto S420; cumnbn(s,xn,pr,ompr,&cum,&ccum); if(!qporq) goto S400; fx = cum-*p; goto S410; S400: fx = ccum-*q; S410: dinvr(status,xn,&fx,&qleft,&qhi); goto S390; S420: if(!(*status == -1)) goto S450; if(!qleft) goto S430; *status = 1; *bound = 0.0e0; goto S440; S430: *status = 2; *bound = inf; S450: S440: ; } else if(4 == *which) { /* Calculating PR and OMPR */ T12 = atol; T13 = tol; dstzr(&K2,&K11,&T12,&T13); if(!qporq) goto S480; *status = 0; dzror(status,pr,&fx,&xlo,&xhi,&qleft,&qhi); *ompr = one-*pr; S460: if(!(*status == 1)) goto S470; cumnbn(s,xn,pr,ompr,&cum,&ccum); fx = cum-*p; dzror(status,pr,&fx,&xlo,&xhi,&qleft,&qhi); *ompr = one-*pr; goto S460; S470: goto S510; S480: *status = 0; dzror(status,ompr,&fx,&xlo,&xhi,&qleft,&qhi); *pr = one-*ompr; S490: if(!(*status == 1)) goto S500; cumnbn(s,xn,pr,ompr,&cum,&ccum); fx = ccum-*q; dzror(status,ompr,&fx,&xlo,&xhi,&qleft,&qhi); *pr = one-*ompr; goto S490; S510: S500: if(!(*status == -1)) goto S540; if(!qleft) goto S520; *status = 1; *bound = 0.0e0; goto S530; S520: *status = 2; *bound = 1.0e0; S530: ; } S540: return; #undef tol #undef atol #undef inf #undef one } /* END */ /***=====================================================================***/ void cdfnor(int *which,double *p,double *q,double *x,double *mean, double *sd,int *status,double *bound) /********************************************************************** void cdfnor(int *which,double *p,double *q,double *x,double *mean, double *sd,int *status,double *bound) Cumulative Distribution Function NORmal distribution Function Calculates any one parameter of the normal distribution given values for the others. Arguments WHICH --> Integer indicating which of the next parameter values is to be calculated using values of the others. Legal range: 1..4 iwhich = 1 : Calculate P and Q from X,MEAN and SD iwhich = 2 : Calculate X from P,Q,MEAN and SD iwhich = 3 : Calculate MEAN from P,Q,X and SD iwhich = 4 : Calculate SD from P,Q,X and MEAN P <--> The integral from -infinity to X of the normal density. Input range: (0,1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. X < --> Upper limit of integration of the normal-density. Input range: ( -infinity, +infinity) MEAN <--> The mean of the normal density. Input range: (-infinity, +infinity) SD <--> Standard Deviation of the normal density. Input range: (0, +infinity). STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method A slightly modified version of ANORM from Cody, W.D. (1993). "ALGORITHM 715: SPECFUN - A Portabel FORTRAN Package of Special Function Routines and Test Drivers" acm Transactions on Mathematical Software. 19, 22-32. is used to calulate the cumulative standard normal distribution. The rational functions from pages 90-95 of Kennedy and Gentle, Statistical Computing, Marcel Dekker, NY, 1980 are used as starting values to Newton's Iterations which compute the inverse standard normal. Therefore no searches are necessary for any parameter. For X < -15, the asymptotic expansion for the normal is used as the starting value in finding the inverse standard normal. This is formula 26.2.12 of Abramowitz and Stegun. Note The normal density is proportional to exp( - 0.5 * (( X - MEAN)/SD)**2) **********************************************************************/ { static int K1 = 1; static double z,pq; /* .. .. Executable Statements .. */ /* Check arguments */ *status = 0; if(!(*which < 1 || *which > 4)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 4.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p <= 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p <= 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 1) goto S150; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S140; if(!(pq < 0.0e0)) goto S120; *bound = 0.0e0; goto S130; S120: *bound = 1.0e0; S130: *status = 3; return; S150: S140: if(*which == 4) goto S170; /* SD */ if(!(*sd <= 0.0e0)) goto S160; *bound = 0.0e0; *status = -6; return; S170: S160: /* Calculate ANSWERS */ if(1 == *which) { /* Computing P */ z = (*x-*mean)/ *sd; cumnor(&z,p,q); } else if(2 == *which) { /* Computing X */ z = dinvnr(p,q); *x = *sd*z+*mean; } else if(3 == *which) { /* Computing the MEAN */ z = dinvnr(p,q); *mean = *x-*sd*z; } else if(4 == *which) { /* Computing SD */ z = dinvnr(p,q); *sd = (*x-*mean)/z; } return; } /* END */ #endif /* defined(__COMPILE_UNUSED_FUNCTIONS__) */ /***=====================================================================***/ void cdfpoi(const int *which,double *p,double *q,double *s,double *xlam, int *status,double *bound) /********************************************************************** void cdfpoi(int *which,double *p,double *q,double *s,double *xlam, int *status,double *bound) Cumulative Distribution Function POIsson distribution Function Calculates any one parameter of the Poisson distribution given values for the others. Arguments WHICH --> Integer indicating which argument value is to be calculated from the others. Legal range: 1..3 iwhich = 1 : Calculate P and Q from S and XLAM iwhich = 2 : Calculate A from P,Q and XLAM iwhich = 3 : Calculate XLAM from P,Q and S P <--> The cumulation from 0 to S of the poisson density. Input range: [0,1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. S <--> Upper limit of cumulation of the Poisson. Input range: [0, +infinity). Search range: [0,1E300] XLAM <--> Mean of the Poisson distribution. Input range: [0, +infinity). Search range: [0,1E300] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.4.21 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the computation of the cumulative distribution function to that of computing a chi-square, hence an incomplete gamma function. Cumulative distribution function (P) is calculated directly. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. **********************************************************************/ { #define tol (1.0e-8) #define atol (1.0e-50) #define inf 1.0e300 static int K1 = 1; static double K2 = 0.0e0; static double K4 = 0.5e0; static double K5 = 5.0e0; static double fx,cum,ccum,pq; static unsigned long qhi,qleft,qporq; static double T3,T6,T7,T8,T9,T10; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 3)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 3.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p < 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p < 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 2) goto S130; /* S */ if(!(*s < 0.0e0)) goto S120; *bound = 0.0e0; *status = -4; return; S130: S120: if(*which == 3) goto S150; /* XLAM */ if(!(*xlam < 0.0e0)) goto S140; *bound = 0.0e0; *status = -5; return; S150: S140: if(*which == 1) goto S190; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S180; if(!(pq < 0.0e0)) goto S160; *bound = 0.0e0; goto S170; S160: *bound = 1.0e0; S170: *status = 3; return; S190: S180: if(!(*which == 1)) qporq = *p <= *q; /* Select the minimum of P or Q Calculate ANSWERS */ if(1 == *which) { /* Calculating P */ cumpoi(s,xlam,p,q); *status = 0; } else if(2 == *which) { /* Calculating S */ *s = 5.0e0; T3 = inf; T6 = atol; T7 = tol; dstinv(&K2,&T3,&K4,&K4,&K5,&T6,&T7); *status = 0; dinvr(status,s,&fx,&qleft,&qhi); S200: if(!(*status == 1)) goto S230; cumpoi(s,xlam,&cum,&ccum); if(!qporq) goto S210; fx = cum-*p; goto S220; S210: fx = ccum-*q; S220: dinvr(status,s,&fx,&qleft,&qhi); goto S200; S230: if(!(*status == -1)) goto S260; if(!qleft) goto S240; *status = 1; *bound = 0.0e0; goto S250; S240: *status = 2; *bound = inf; S260: S250: ; } else if(3 == *which) { /* Calculating XLAM */ *xlam = 5.0e0; T8 = inf; T9 = atol; T10 = tol; dstinv(&K2,&T8,&K4,&K4,&K5,&T9,&T10); *status = 0; dinvr(status,xlam,&fx,&qleft,&qhi); S270: if(!(*status == 1)) goto S300; cumpoi(s,xlam,&cum,&ccum); if(!qporq) goto S280; fx = cum-*p; goto S290; S280: fx = ccum-*q; S290: dinvr(status,xlam,&fx,&qleft,&qhi); goto S270; S300: if(!(*status == -1)) goto S330; if(!qleft) goto S310; *status = 1; *bound = 0.0e0; goto S320; S310: *status = 2; *bound = inf; S320: ; } S330: return; #undef tol #undef atol #undef inf } /* END */ /***=====================================================================***/ void cdft(const int *which,double *p,double *q,double *t,double *df, int *status,double *bound) /********************************************************************** void cdft(int *which,double *p,double *q,double *t,double *df, int *status,double *bound) Cumulative Distribution Function T distribution Function Calculates any one parameter of the t distribution given values for the others. Arguments WHICH --> Integer indicating which argument values is to be calculated from the others. Legal range: 1..3 iwhich = 1 : Calculate P and Q from T and DF iwhich = 2 : Calculate T from P,Q and DF iwhich = 3 : Calculate DF from P,Q and T P <--> The integral from -infinity to t of the t-density. Input range: (0,1]. Q <--> 1-P. Input range: (0, 1]. P + Q = 1.0. T <--> Upper limit of integration of the t-density. Input range: ( -infinity, +infinity). Search range: [ -1E300, 1E300 ] DF <--> Degrees of freedom of the t-distribution. Input range: (0 , +infinity). Search range: [1e-300, 1E10] STATUS <-- 0 if calculation completed correctly -I if input parameter number I is out of range 1 if answer appears to be lower than lowest search bound 2 if answer appears to be higher than greatest search bound 3 if P + Q .ne. 1 BOUND <-- Undefined if STATUS is 0 Bound exceeded by parameter number I if STATUS is negative. Lower search bound if STATUS is 1. Upper search bound if STATUS is 2. Method Formula 26.5.27 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the computation of the cumulative distribution function to that of an incomplete beta. Computation of other parameters involve a seach for a value that produces the desired value of P. The search relies on the monotinicity of P with the other parameter. **********************************************************************/ { #define tol (1.0e-8) #define atol (1.0e-50) #define zero (1.0e-300) #define inf 1.0e300 #define maxdf 1.0e10 static int K1 = 1; static double K4 = 0.5e0; static double K5 = 5.0e0; static double fx,cum,ccum,pq; static unsigned long qhi,qleft,qporq; static double T2,T3,T6,T7,T8,T9,T10,T11; /* .. .. Executable Statements .. */ /* Check arguments */ if(!(*which < 1 || *which > 3)) goto S30; if(!(*which < 1)) goto S10; *bound = 1.0e0; goto S20; S10: *bound = 3.0e0; S20: *status = -1; return; S30: if(*which == 1) goto S70; /* P */ if(!(*p <= 0.0e0 || *p > 1.0e0)) goto S60; if(!(*p <= 0.0e0)) goto S40; *bound = 0.0e0; goto S50; S40: *bound = 1.0e0; S50: *status = -2; return; S70: S60: if(*which == 1) goto S110; /* Q */ if(!(*q <= 0.0e0 || *q > 1.0e0)) goto S100; if(!(*q <= 0.0e0)) goto S80; *bound = 0.0e0; goto S90; S80: *bound = 1.0e0; S90: *status = -3; return; S110: S100: if(*which == 3) goto S130; /* DF */ if(!(*df <= 0.0e0)) goto S120; *bound = 0.0e0; *status = -5; return; S130: S120: if(*which == 1) goto S170; /* P + Q */ pq = *p+*q; if(!(fabs(pq-0.5e0-0.5e0) > 3.0e0*spmpar(&K1))) goto S160; if(!(pq < 0.0e0)) goto S140; *bound = 0.0e0; goto S150; S140: *bound = 1.0e0; S150: *status = 3; return; S170: S160: if(!(*which == 1)) qporq = *p <= *q; /* Select the minimum of P or Q Calculate ANSWERS */ if(1 == *which) { /* Computing P and Q */ cumt(t,df,p,q); *status = 0; } else if(2 == *which) { /* Computing T .. Get initial approximation for T */ *t = dt1(p,q,df); T2 = -inf; T3 = inf; T6 = atol; T7 = tol; dstinv(&T2,&T3,&K4,&K4,&K5,&T6,&T7); *status = 0; dinvr(status,t,&fx,&qleft,&qhi); S180: if(!(*status == 1)) goto S210; cumt(t,df,&cum,&ccum); if(!qporq) goto S190; fx = cum-*p; goto S200; S190: fx = ccum-*q; S200: dinvr(status,t,&fx,&qleft,&qhi); goto S180; S210: if(!(*status == -1)) goto S240; if(!qleft) goto S220; *status = 1; *bound = -inf; goto S230; S220: *status = 2; *bound = inf; S240: S230: ; } else if(3 == *which) { /* Computing DF */ *df = 5.0e0; T8 = zero; T9 = maxdf; T10 = atol; T11 = tol; dstinv(&T8,&T9,&K4,&K4,&K5,&T10,&T11); *status = 0; dinvr(status,df,&fx,&qleft,&qhi); S250: if(!(*status == 1)) goto S280; cumt(t,df,&cum,&ccum); if(!qporq) goto S260; fx = cum-*p; goto S270; S260: fx = ccum-*q; S270: dinvr(status,df,&fx,&qleft,&qhi); goto S250; S280: if(!(*status == -1)) goto S310; if(!qleft) goto S290; *status = 1; *bound = zero; goto S300; S290: *status = 2; *bound = maxdf; S300: ; } S310: return; #undef tol #undef atol #undef zero #undef inf #undef maxdf } /* END */ /***=====================================================================***/ void cumbet(double *x,double *y,double *a,double *b,double *cum, double *ccum) /* ********************************************************************** void cumbet(double *x,double *y,double *a,double *b,double *cum, double *ccum) Double precision cUMulative incomplete BETa distribution Function Calculates the cdf to X of the incomplete beta distribution with parameters a and b. This is the integral from 0 to x of (1/B(a,b))*f(t)) where f(t) = t**(a-1) * (1-t)**(b-1) Arguments X --> Upper limit of integration. X is DOUBLE PRECISION Y --> 1 - X. Y is DOUBLE PRECISION A --> First parameter of the beta distribution. A is DOUBLE PRECISION B --> Second parameter of the beta distribution. B is DOUBLE PRECISION CUM <-- Cumulative incomplete beta distribution. CUM is DOUBLE PRECISION CCUM <-- Compliment of Cumulative incomplete beta distribution. CCUM is DOUBLE PRECISION Method Calls the routine BRATIO. References Didonato, Armido R. and Morris, Alfred H. Jr. (1992) Algorithim 708 Significant Digit Computation of the Incomplete Beta Function Ratios. ACM ToMS, Vol.18, No. 3, Sept. 1992, 360-373. ********************************************************************** */ { static int ierr; /* .. .. Executable Statements .. */ if(!(*x <= 0.0e0)) goto S10; *cum = 0.0e0; *ccum = 1.0e0; return; S10: if(!(*y <= 0.0e0)) goto S20; *cum = 1.0e0; *ccum = 0.0e0; return; S20: bratio(a,b,x,y,cum,ccum,&ierr); } /* END */ /***=====================================================================***/ void cumbin(const double *s,const double *xn,double *pr,double *ompr, double *cum,double *ccum) /* ********************************************************************** void cumbin(double *s,double *xn,double *pr,double *ompr, double *cum,double *ccum) CUmulative BINomial distribution Function Returns the probability of 0 to S successes in XN binomial trials, each of which has a probability of success, PBIN. Arguments S --> The upper limit of cumulation of the binomial distribution. S is DOUBLE PRECISION XN --> The number of binomial trials. XN is DOUBLE PRECISIO PBIN --> The probability of success in each binomial trial. PBIN is DOUBLE PRECIS OMPR --> 1 - PBIN OMPR is DOUBLE PRECIS CUM <-- Cumulative binomial distribution. CUM is DOUBLE PRECISI CCUM <-- Compliment of Cumulative binomial distribution. CCUM is DOUBLE PRECIS Method Formula 26.5.24 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the binomial distribution to the cumulative beta distribution. ********************************************************************** */ { static double T1,T2; /* .. .. Executable Statements .. */ if(!(*s < *xn)) goto S10; T1 = *s+1.0e0; T2 = *xn-*s; cumbet(pr,ompr,&T1,&T2,ccum,cum); goto S20; S10: *cum = 1.0e0; *ccum = 0.0e0; S20: return; } /* END */ /***=====================================================================***/ void cumchi(const double *x,const double *df,double *cum,double *ccum) /* ********************************************************************** void cumchi(double *x,double *df,double *cum,double *ccum) CUMulative of the CHi-square distribution Function Calculates the cumulative chi-square distribution. Arguments X --> Upper limit of integration of the chi-square distribution. X is DOUBLE PRECISION DF --> Degrees of freedom of the chi-square distribution. DF is DOUBLE PRECISION CUM <-- Cumulative chi-square distribution. CUM is DOUBLE PRECISIO CCUM <-- Compliment of Cumulative chi-square distribution. CCUM is DOUBLE PRECISI Method Calls incomplete gamma function (CUMGAM) ********************************************************************** */ { static double a,xx; /* .. .. Executable Statements .. */ a = *df*0.5e0; xx = *x*0.5e0; cumgam(&xx,&a,cum,ccum); } /* END */ /***=====================================================================***/ void cumchn(double *x,double *df,const double *pnonc,double *cum, double *ccum) /* ********************************************************************** void cumchn(double *x,double *df,double *pnonc,double *cum, double *ccum) CUMulative of the Non-central CHi-square distribution Function Calculates the cumulative non-central chi-square distribution, i.e., the probability that a random variable which follows the non-central chi-square distribution, with non-centrality parameter PNONC and continuous degrees of freedom DF, is less than or equal to X. Arguments X --> Upper limit of integration of the non-central chi-square distribution. X is DOUBLE PRECISION DF --> Degrees of freedom of the non-central chi-square distribution. DF is DOUBLE PRECISION PNONC --> Non-centrality parameter of the non-central chi-square distribution. PNONC is DOUBLE PRECIS CUM <-- Cumulative non-central chi-square distribution. CUM is DOUBLE PRECISIO CCUM <-- Compliment of Cumulative non-central chi-square distribut CCUM is DOUBLE PRECISI Method Uses formula 26.4.25 of Abramowitz and Stegun, Handbook of Mathematical Functions, US NBS (1966) to calculate the non-central chi-square. Variables EPS --- Convergence criterion. The sum stops when a term is less than EPS*SUM. EPS is DOUBLE PRECISIO NTIRED --- Maximum number of terms to be evaluated in each sum. NTIRED is INTEGER QCONV --- .TRUE. if convergence achieved - i.e., program did not stop on NTIRED criterion. QCONV is LOGICAL CCUM <-- Compliment of Cumulative non-central chi-square distribution. CCUM is DOUBLE PRECISI ********************************************************************** */ { #define dg(i) (*df+2.0e0*(double)(i)) #define qsmall(xx) (int)(sum < 1.0e-20 || (xx) < eps*sum) #define qtired(i) (int)((i) > ntired) static double eps = 1.0e-5; static int ntired = 1000; static double adj,centaj,centwt,chid2,dfd2,lcntaj,lcntwt,lfact,pcent,pterm,sum, sumadj,term,wt,xnonc; static int i,icent,iterb,iterf; static double T1,T2,T3; /* .. .. Executable Statements .. */ if(!(*x <= 0.0e0)) goto S10; *cum = 0.0e0; *ccum = 1.0e0; return; S10: if(!(*pnonc <= 1.0e-10)) goto S20; /* When non-centrality parameter is (essentially) zero, use cumulative chi-square distribution */ cumchi(x,df,cum,ccum); return; S20: xnonc = *pnonc/2.0e0; /* ********************************************************************** The following code calcualtes the weight, chi-square, and adjustment term for the central term in the infinite series. The central term is the one in which the poisson weight is greatest. The adjustment term is the amount that must be subtracted from the chi-square to move up two degrees of freedom. ********************************************************************** */ icent = fifidint(xnonc); if(icent == 0) icent = 1; chid2 = *x/2.0e0; /* Calculate central weight term */ T1 = (double)(icent+1); lfact = alngam(&T1); lcntwt = -xnonc+(double)icent*log(xnonc)-lfact; centwt = exp(lcntwt); /* Calculate central chi-square */ T2 = dg(icent); cumchi(x,&T2,&pcent,ccum); /* Calculate central adjustment term */ dfd2 = dg(icent)/2.0e0; T3 = 1.0e0+dfd2; lfact = alngam(&T3); lcntaj = dfd2*log(chid2)-chid2-lfact; centaj = exp(lcntaj); sum = centwt*pcent; /* ********************************************************************** Sum backwards from the central term towards zero. Quit whenever either (1) the zero term is reached, or (2) the term gets small relative to the sum, or (3) More than NTIRED terms are totaled. ********************************************************************** */ iterb = 0; sumadj = 0.0e0; adj = centaj; wt = centwt; i = icent; goto S40; S30: if(qtired(iterb) || qsmall(term) || i == 0) goto S50; S40: dfd2 = dg(i)/2.0e0; /* Adjust chi-square for two fewer degrees of freedom. The adjusted value ends up in PTERM. */ adj = adj*dfd2/chid2; sumadj += adj; pterm = pcent+sumadj; /* Adjust poisson weight for J decreased by one */ wt *= ((double)i/xnonc); term = wt*pterm; sum += term; i -= 1; iterb += 1; goto S30; S50: iterf = 0; /* ********************************************************************** Now sum forward from the central term towards infinity. Quit when either (1) the term gets small relative to the sum, or (2) More than NTIRED terms are totaled. ********************************************************************** */ sumadj = adj = centaj; wt = centwt; i = icent; goto S70; S60: if(qtired(iterf) || qsmall(term)) goto S80; S70: /* Update weights for next higher J */ wt *= (xnonc/(double)(i+1)); /* Calculate PTERM and add term to sum */ pterm = pcent-sumadj; term = wt*pterm; sum += term; /* Update adjustment term for DF for next iteration */ i += 1; dfd2 = dg(i)/2.0e0; adj = adj*chid2/dfd2; sumadj += adj; iterf += 1; goto S60; S80: *cum = sum; *ccum = 0.5e0+(0.5e0-*cum); #undef dg #undef qsmall #undef qtired } /* END */ /***=====================================================================***/ void cumf(const double *f,const double *dfn,const double *dfd,double *cum,double *ccum) /* ********************************************************************** void cumf(double *f,double *dfn,double *dfd,double *cum,double *ccum) CUMulative F distribution Function Computes the integral from 0 to F of the f-density with DFN and DFD degrees of freedom. Arguments F --> Upper limit of integration of the f-density. F is DOUBLE PRECISION DFN --> Degrees of freedom of the numerator sum of squares. DFN is DOUBLE PRECISI DFD --> Degrees of freedom of the denominator sum of squares. DFD is DOUBLE PRECISI CUM <-- Cumulative f distribution. CUM is DOUBLE PRECISI CCUM <-- Compliment of Cumulative f distribution. CCUM is DOUBLE PRECIS Method Formula 26.5.28 of Abramowitz and Stegun is used to reduce the cumulative F to a cumulative beta distribution. Note If F is less than or equal to 0, 0 is returned. ********************************************************************** */ { #define half 0.5e0 #define done 1.0e0 static double dsum,prod,xx,yy; static int ierr; static double T1,T2; /* .. .. Executable Statements .. */ if(!(*f <= 0.0e0)) goto S10; *cum = 0.0e0; *ccum = 1.0e0; return; S10: prod = *dfn**f; /* XX is such that the incomplete beta with parameters DFD/2 and DFN/2 evaluated at XX is 1 - CUM or CCUM YY is 1 - XX Calculate the smaller of XX and YY accurately */ dsum = *dfd+prod; xx = *dfd/dsum; if(xx > half) { yy = prod/dsum; xx = done-yy; } else yy = done-xx; T1 = *dfd*half; T2 = *dfn*half; bratio(&T1,&T2,&xx,&yy,ccum,cum,&ierr); #undef half #undef done } /* END */ /***=====================================================================***/ void cumfnc(double *f,double *dfn,double *dfd,const double *pnonc, double *cum,double *ccum) /* ********************************************************************** F -NON- -C-ENTRAL F DISTRIBUTION Function COMPUTES NONCENTRAL F DISTRIBUTION WITH DFN AND DFD DEGREES OF FREEDOM AND NONCENTRALITY PARAMETER PNONC Arguments X --> UPPER LIMIT OF INTEGRATION OF NONCENTRAL F IN EQUATION DFN --> DEGREES OF FREEDOM OF NUMERATOR DFD --> DEGREES OF FREEDOM OF DENOMINATOR PNONC --> NONCENTRALITY PARAMETER. CUM <-- CUMULATIVE NONCENTRAL F DISTRIBUTION CCUM <-- COMPLIMENT OF CUMMULATIVE Method USES FORMULA 26.6.20 OF REFERENCE FOR INFINITE SERIES. SERIES IS CALCULATED BACKWARD AND FORWARD FROM J = LAMBDA/2 (THIS IS THE TERM WITH THE LARGEST POISSON WEIGHT) UNTIL THE CONVERGENCE CRITERION IS MET. FOR SPEED, THE INCOMPLETE BETA FUNCTIONS ARE EVALUATED BY FORMULA 26.5.16. REFERENCE HANDBOOD OF MATHEMATICAL FUNCTIONS EDITED BY MILTON ABRAMOWITZ AND IRENE A. STEGUN NATIONAL BUREAU OF STANDARDS APPLIED MATEMATICS SERIES - 55 MARCH 1965 P 947, EQUATIONS 26.6.17, 26.6.18 Note THE SUM CONTINUES UNTIL A SUCCEEDING TERM IS LESS THAN EPS TIMES THE SUM (OR THE SUM IS LESS THAN 1.0E-20). EPS IS SET TO 1.0E-4 IN A DATA STATEMENT WHICH CAN BE CHANGED. ********************************************************************** */ { #define qsmall(x) (int)(sum < 1.0e-20 || (x) < eps*sum) #define half 0.5e0 #define done 1.0e0 static double eps = 1.0e-4; static double dsum,dummy,prod,xx,yy,adn,aup,b,betdn,betup,centwt,dnterm,sum, upterm,xmult,xnonc; static int i,icent,ierr; static double T1,T2,T3,T4,T5,T6; /* .. .. Executable Statements .. */ if(!(*f <= 0.0e0)) goto S10; *cum = 0.0e0; *ccum = 1.0e0; return; S10: if(!(*pnonc < 1.0e-10)) goto S20; /* Handle case in which the non-centrality parameter is (essentially) zero. */ cumf(f,dfn,dfd,cum,ccum); return; S20: xnonc = *pnonc/2.0e0; /* Calculate the central term of the poisson weighting factor. */ icent = xnonc; if(icent == 0) icent = 1; /* Compute central weight term */ T1 = (double)(icent+1); centwt = exp(-xnonc+(double)icent*log(xnonc)-alngam(&T1)); /* Compute central incomplete beta term Assure that minimum of arg to beta and 1 - arg is computed accurately. */ prod = *dfn**f; dsum = *dfd+prod; yy = *dfd/dsum; if(yy > half) { xx = prod/dsum; yy = done-xx; } else xx = done-yy; T2 = *dfn*half+(double)icent; T3 = *dfd*half; bratio(&T2,&T3,&xx,&yy,&betdn,&dummy,&ierr); adn = *dfn/2.0e0+(double)icent; aup = adn; b = *dfd/2.0e0; betup = betdn; sum = centwt*betdn; /* Now sum terms backward from icent until convergence or all done */ xmult = centwt; i = icent; T4 = adn+b; T5 = adn+1.0e0; dnterm = exp(alngam(&T4)-alngam(&T5)-alngam(&b)+adn*log(xx)+b*log(yy)); S30: if(qsmall(xmult*betdn) || i <= 0) goto S40; xmult *= ((double)i/xnonc); i -= 1; adn -= 1.0; dnterm = (adn+1.0)/((adn+b)*xx)*dnterm; betdn += dnterm; sum += (xmult*betdn); goto S30; S40: i = icent+1; /* Now sum forwards until convergence */ xmult = centwt; if(aup-1.0+b == 0) upterm = exp(-alngam(&aup)-alngam(&b)+(aup-1.0)*log(xx)+ b*log(yy)); else { T6 = aup-1.0+b; upterm = exp(alngam(&T6)-alngam(&aup)-alngam(&b)+(aup-1.0)*log(xx)+b* log(yy)); } goto S60; S50: if(qsmall(xmult*betup)) goto S70; S60: xmult *= (xnonc/(double)i); i += 1; aup += 1.0; upterm = (aup+b-2.0e0)*xx/(aup-1.0)*upterm; betup -= upterm; sum += (xmult*betup); goto S50; S70: *cum = sum; *ccum = 0.5e0+(0.5e0-*cum); #undef qsmall #undef half #undef done } /* END */ /***=====================================================================***/ void cumgam(double *x,double *a,double *cum,double *ccum) /* ********************************************************************** void cumgam(double *x,double *a,double *cum,double *ccum) Double precision cUMulative incomplete GAMma distribution Function Computes the cumulative of the incomplete gamma distribution, i.e., the integral from 0 to X of (1/GAM(A))*EXP(-T)*T**(A-1) DT where GAM(A) is the complete gamma function of A, i.e., GAM(A) = integral from 0 to infinity of EXP(-T)*T**(A-1) DT Arguments X --> The upper limit of integration of the incomplete gamma. X is DOUBLE PRECISION A --> The shape parameter of the incomplete gamma. A is DOUBLE PRECISION CUM <-- Cumulative incomplete gamma distribution. CUM is DOUBLE PRECISION CCUM <-- Compliment of Cumulative incomplete gamma distribution. CCUM is DOUBLE PRECISIO Method Calls the routine GRATIO. ********************************************************************** */ { static int K1 = 0; /* .. .. Executable Statements .. */ if(!(*x <= 0.0e0)) goto S10; *cum = 0.0e0; *ccum = 1.0e0; return; S10: gratio(a,x,cum,ccum,&K1); } /* END */ #if defined(__COMPILE_UNUSED_FUNCTIONS__) /***=====================================================================***/ void cumnbn(double *s,double *xn,double *pr,double *ompr, double *cum,double *ccum) /* ********************************************************************** void cumnbn(double *s,double *xn,double *pr,double *ompr, double *cum,double *ccum) CUmulative Negative BINomial distribution Function Returns the probability that it there will be S or fewer failures before there are XN successes, with each binomial trial having a probability of success PR. Prob(# failures = S | XN successes, PR) = ( XN + S - 1 ) ( ) * PR^XN * (1-PR)^S ( S ) Arguments S --> The number of failures S is DOUBLE PRECISION XN --> The number of successes XN is DOUBLE PRECISIO PR --> The probability of success in each binomial trial. PR is DOUBLE PRECISIO OMPR --> 1 - PR OMPR is DOUBLE PRECIS CUM <-- Cumulative negative binomial distribution. CUM is DOUBLE PRECISI CCUM <-- Compliment of Cumulative negative binomial distribution. CCUM is DOUBLE PRECIS Method Formula 26.5.26 of Abramowitz and Stegun, Handbook of Mathematical Functions (1966) is used to reduce the negative binomial distribution to the cumulative beta distribution. ********************************************************************** */ { static double T1; /* .. .. Executable Statements .. */ T1 = *s+1.e0; cumbet(pr,ompr,xn,&T1,cum,ccum); return; } /* END */ #endif /*defined(__COMPILE_UNUSED_FUNCTIONS__)*/ /***=====================================================================***/ void cumnor(const double *arg,double *result,double *ccum) /* ********************************************************************** void cumnor(double *arg,double *result,double *ccum) Function Computes the cumulative of the normal distribution, i.e., the integral from -infinity to x of (1/sqrt(2*pi)) exp(-u*u/2) du X --> Upper limit of integration. X is DOUBLE PRECISION RESULT <-- Cumulative normal distribution. RESULT is DOUBLE PRECISION CCUM <-- Compliment of Cumulative normal distribution. CCUM is DOUBLE PRECISION Renaming of function ANORM from: Cody, W.D. (1993). "ALGORITHM 715: SPECFUN - A Portabel FORTRAN Package of Special Function Routines and Test Drivers" acm Transactions on Mathematical Software. 19, 22-32. with slight modifications to return ccum and to deal with machine constants. ********************************************************************** Original Comments: ------------------------------------------------------------------ This function evaluates the normal distribution function: / x 1 | -t*t/2 P(x) = ----------- | e dt sqrt(2 pi) | /-oo The main computation evaluates near-minimax approximations derived from those in "Rational Chebyshev approximations for the error function" by W. J. Cody, Math. Comp., 1969, 631-637. This transportable program uses rational functions that theoretically approximate the normal distribution function to at least 18 significant decimal digits. The accuracy achieved depends on the arithmetic system, the compiler, the intrinsic functions, and proper selection of the machine-dependent constants. ******************************************************************* ******************************************************************* Explanation of machine-dependent constants. MIN = smallest machine representable number. EPS = argument below which anorm(x) may be represented by 0.5 and above which x*x will not underflow. A conservative value is the largest machine number X such that 1.0 + X = 1.0 to machine precision. ******************************************************************* ******************************************************************* Error returns The program returns ANORM = 0 for ARG .LE. XLOW. Intrinsic functions required are: ABS, AINT, EXP Author: W. J. Cody Mathematics and Computer Science Division Argonne National Laboratory Argonne, IL 60439 Latest modification: March 15, 1992 ------------------------------------------------------------------ */ { static double a[5] = { 2.2352520354606839287e00,1.6102823106855587881e02,1.0676894854603709582e03, 1.8154981253343561249e04,6.5682337918207449113e-2 }; static double b[4] = { 4.7202581904688241870e01,9.7609855173777669322e02,1.0260932208618978205e04, 4.5507789335026729956e04 }; static double c[9] = { 3.9894151208813466764e-1,8.8831497943883759412e00,9.3506656132177855979e01, 5.9727027639480026226e02,2.4945375852903726711e03,6.8481904505362823326e03, 1.1602651437647350124e04,9.8427148383839780218e03,1.0765576773720192317e-8 }; static double d[8] = { 2.2266688044328115691e01,2.3538790178262499861e02,1.5193775994075548050e03, 6.4855582982667607550e03,1.8615571640885098091e04,3.4900952721145977266e04, 3.8912003286093271411e04,1.9685429676859990727e04 }; static double half = 0.5e0; static double p[6] = { 2.1589853405795699e-1,1.274011611602473639e-1,2.2235277870649807e-2, 1.421619193227893466e-3,2.9112874951168792e-5,2.307344176494017303e-2 }; static double one = 1.0e0; static double q[5] = { 1.28426009614491121e00,4.68238212480865118e-1,6.59881378689285515e-2, 3.78239633202758244e-3,7.29751555083966205e-5 }; static double sixten = 1.60e0; static double sqrpi = 3.9894228040143267794e-1; static double thrsh = 0.66291e0; static double root32 = 5.656854248e0; static double zero = 0.0e0; static int K1 = 1; static int K2 = 2; static int i; static double del,eps,temp,x,xden,xnum,y,xsq,min; /* ------------------------------------------------------------------ Machine dependent constants ------------------------------------------------------------------ */ eps = spmpar(&K1)*0.5e0; min = spmpar(&K2); x = *arg; y = fabs(x); if(y <= thrsh) { /* ------------------------------------------------------------------ Evaluate anorm for |X| <= 0.66291 ------------------------------------------------------------------ */ xsq = zero; if(y > eps) xsq = x*x; xnum = a[4]*xsq; xden = xsq; for(i=0; i<3; i++) { xnum = (xnum+a[i])*xsq; xden = (xden+b[i])*xsq; } *result = x*(xnum+a[3])/(xden+b[3]); temp = *result; *result = half+temp; *ccum = half-temp; } /* ------------------------------------------------------------------ Evaluate anorm for 0.66291 <= |X| <= sqrt(32) ------------------------------------------------------------------ */ else if(y <= root32) { xnum = c[8]*y; xden = y; for(i=0; i<7; i++) { xnum = (xnum+c[i])*y; xden = (xden+d[i])*y; } *result = (xnum+c[7])/(xden+d[7]); xsq = fifdint(y*sixten)/sixten; del = (y-xsq)*(y+xsq); *result = exp(-(xsq*xsq*half))*exp(-(del*half))**result; *ccum = one-*result; if(x > zero) { temp = *result; *result = *ccum; *ccum = temp; } } /* ------------------------------------------------------------------ Evaluate anorm for |X| > sqrt(32) ------------------------------------------------------------------ */ else { *result = zero; xsq = one/(x*x); xnum = p[5]*xsq; xden = xsq; for(i=0; i<4; i++) { xnum = (xnum+p[i])*xsq; xden = (xden+q[i])*xsq; } *result = xsq*(xnum+p[4])/(xden+q[4]); *result = (sqrpi-*result)/y; xsq = fifdint(x*sixten)/sixten; del = (x-xsq)*(x+xsq); *result = exp(-(xsq*xsq*half))*exp(-(del*half))**result; *ccum = one-*result; if(x > zero) { temp = *result; *result = *ccum; *ccum = temp; } } if(*result < min) *result = 0.0e0; /* ------------------------------------------------------------------ Fix up for negative argument, erf, etc. ------------------------------------------------------------------ ----------Last card of ANORM ---------- */ if(*ccum < min) *ccum = 0.0e0; } /* END */ /***=====================================================================***/ void cumpoi(const double *s,const double *xlam,double *cum,double *ccum) /* ********************************************************************** void cumpoi(double *s,double *xlam,double *cum,double *ccum) CUMulative POIsson distribution Function Returns the probability of S or fewer events in a Poisson distribution with mean XLAM. Arguments S --> Upper limit of cumulation of the Poisson. S is DOUBLE PRECISION XLAM --> Mean of the Poisson distribution. XLAM is DOUBLE PRECIS CUM <-- Cumulative poisson distribution. CUM is DOUBLE PRECISION CCUM <-- Compliment of Cumulative poisson distribution. CCUM is DOUBLE PRECIS Method Uses formula 26.4.21 of Abramowitz and Stegun, Handbook of Mathematical Functions to reduce the cumulative Poisson to the cumulative chi-square distribution. ********************************************************************** */ { static double chi,df; /* .. .. Executable Statements .. */ df = 2.0e0*(*s+1.0e0); chi = 2.0e0**xlam; cumchi(&chi,&df,ccum,cum); } /* END */ /***=====================================================================***/ void cumt(const double *t,const double *df,double *cum,double *ccum) /* ********************************************************************** void cumt(double *t,double *df,double *cum,double *ccum) CUMulative T-distribution Function Computes the integral from -infinity to T of the t-density. Arguments T --> Upper limit of integration of the t-density. T is DOUBLE PRECISION DF --> Degrees of freedom of the t-distribution. DF is DOUBLE PRECISIO CUM <-- Cumulative t-distribution. CCUM is DOUBLE PRECIS CCUM <-- Compliment of Cumulative t-distribution. CCUM is DOUBLE PRECIS Method Formula 26.5.27 of Abramowitz and Stegun, Handbook of Mathematical Functions is used to reduce the t-distribution to an incomplete beta. ********************************************************************** */ { static double K2 = 0.5e0; static double xx,a,oma,tt,yy,dfptt,T1; /* .. .. Executable Statements .. */ tt = *t**t; dfptt = *df+tt; xx = *df/dfptt; yy = tt/dfptt; T1 = 0.5e0**df; cumbet(&xx,&yy,&T1,&K2,&a,&oma); if(!(*t <= 0.0e0)) goto S10; *cum = 0.5e0*a; *ccum = oma+*cum; goto S20; S10: *ccum = 0.5e0*a; *cum = oma+*ccum; S20: return; } /* END */ #if defined(__COMPILE_UNUSED_FUNCTIONS__) /***=====================================================================***/ double dbetrm(double *a,double *b) /* ********************************************************************** double dbetrm(double *a,double *b) Double Precision Sterling Remainder for Complete Beta Function Function Log(Beta(A,B)) = Lgamma(A) + Lgamma(B) - Lgamma(A+B) where Lgamma is the log of the (complete) gamma function Let ZZ be approximation obtained if each log gamma is approximated by Sterling's formula, i.e., Sterling(Z) = LOG( SQRT( 2*PI ) ) + ( Z-0.5 ) * LOG( Z ) - Z Returns Log(Beta(A,B)) - ZZ Arguments A --> One argument of the Beta DOUBLE PRECISION A B --> The other argument of the Beta DOUBLE PRECISION B ********************************************************************** */ { static double dbetrm,T1,T2,T3; /* .. .. Executable Statements .. */ /* Try to sum from smallest to largest */ T1 = *a+*b; dbetrm = -dstrem(&T1); T2 = fifdmax1(*a,*b); dbetrm += dstrem(&T2); T3 = fifdmin1(*a,*b); dbetrm += dstrem(&T3); return dbetrm; } /* END */ #endif /* defined(__COMPILE_UNUSED_FUNCTIONS__) */ /***=====================================================================***/ double devlpl(const double a[],const int *n,const double *x) /* ********************************************************************** double devlpl(double a[],int *n,double *x) Double precision EVALuate a PoLynomial at X Function returns A(1) + A(2)*X + ... + A(N)*X**(N-1) Arguments A --> Array of coefficients of the polynomial. A is DOUBLE PRECISION(N) N --> Length of A, also degree of polynomial - 1. N is INTEGER X --> Point at which the polynomial is to be evaluated. X is DOUBLE PRECISION ********************************************************************** */ { static double devlpl,term; static int i; /* .. .. Executable Statements .. */ term = a[*n-1]; for(i= *n-1-1; i>=0; i--) term = a[i]+term**x; devlpl = term; return devlpl; } /* END */ #if defined(__COMPILE_UNUSED_FUNCTIONS__) /***=====================================================================***/ double dexpm1(double *x) /* ********************************************************************** double dexpm1(double *x) Evaluation of the function EXP(X) - 1 Arguments X --> Argument at which exp(x)-1 desired DOUBLE PRECISION X Method Renaming of function rexp from code of: DiDinato, A. R. and Morris, A. H. Algorithm 708: Significant Digit Computation of the Incomplete Beta Function Ratios. ACM Trans. Math. Softw. 18 (1993), 360-373. ********************************************************************** */ { static double p1 = .914041914819518e-09; static double p2 = .238082361044469e-01; static double q1 = -.499999999085958e+00; static double q2 = .107141568980644e+00; static double q3 = -.119041179760821e-01; static double q4 = .595130811860248e-03; static double dexpm1,w; /* .. .. Executable Statements .. */ if(fabs(*x) > 0.15e0) goto S10; dexpm1 = *x*(((p2**x+p1)**x+1.0e0)/((((q4**x+q3)**x+q2)**x+q1)**x+1.0e0)); return dexpm1; S10: w = exp(*x); if(*x > 0.0e0) goto S20; dexpm1 = w-0.5e0-0.5e0; return dexpm1; S20: dexpm1 = w*(0.5e0+(0.5e0-1.0e0/w)); return dexpm1; } /* END */ #endif /*defined(__COMPILE_UNUSED_FUNCTIONS__)*/ /***=====================================================================***/ double dinvnr(const double *p,const double *q) /* ********************************************************************** double dinvnr(double *p,double *q) Double precision NoRmal distribution INVerse Function Returns X such that CUMNOR(X) = P, i.e., the integral from - infinity to X of (1/SQRT(2*PI)) EXP(-U*U/2) dU is P Arguments P --> The probability whose normal deviate is sought. P is DOUBLE PRECISION Q --> 1-P P is DOUBLE PRECISION Method The rational function on page 95 of Kennedy and Gentle, Statistical Computing, Marcel Dekker, NY , 1980 is used as a start value for the Newton method of finding roots. Note If P or Q .lt. machine EPS returns +/- DINVNR(EPS) ********************************************************************** */ { #define maxit 100 #define eps (1.0e-13) #define r2pi 0.3989422804014326e0 #define nhalf (-0.5e0) #define dennor(x) (r2pi*exp(nhalf*(x)*(x))) static double dinvnr,strtx,xcur,cum,ccum,pp,dx; static int i; static unsigned long qporq; /* .. .. Executable Statements .. */ /* FIND MINIMUM OF P AND Q */ qporq = *p <= *q; if(!qporq) goto S10; pp = *p; goto S20; S10: pp = *q; S20: /* INITIALIZATION STEP */ strtx = stvaln(&pp); xcur = strtx; /* NEWTON INTERATIONS */ for(i=1; i<=maxit; i++) { cumnor(&xcur,&cum,&ccum); dx = (cum-pp)/dennor(xcur); xcur -= dx; if(fabs(dx/xcur) < eps) goto S40; } dinvnr = strtx; /* IF WE GET HERE, NEWTON HAS FAILED */ if(!qporq) dinvnr = -dinvnr; return dinvnr; S40: /* IF WE GET HERE, NEWTON HAS SUCCEDED */ dinvnr = xcur; if(!qporq) dinvnr = -dinvnr; return dinvnr; #undef maxit #undef eps #undef r2pi #undef nhalf #undef dennor } /* END */ /***=====================================================================***/ void E0000(int IENTRY,int *status,double *x,double *fx, unsigned long *qleft,unsigned long *qhi,const double *zabsst, const double *zabsto,const double *zbig,const double *zrelst, const double *zrelto,const double *zsmall,const double *zstpmu) { #define qxmon(zx,zy,zz) (int)((zx) <= (zy) && (zy) <= (zz)) static double absstp,abstol,big,fbig,fsmall,relstp,reltol,small,step,stpmul,xhi, xlb,xlo,xsave,xub,yy; static int i99999; static unsigned long qbdd,qcond,qdum1,qdum2,qincr,qlim,/*qok,*/qup; switch(IENTRY){case 0: goto DINVR; case 1: goto DSTINV;} DINVR: if(*status > 0) goto S310; qcond = !qxmon(small,*x,big); if(qcond){ ftnstop("SMALL,X,BIG nonmonotone in E0000"); *status=-1; return;} xsave = *x; /* See that SMALL and BIG bound the zero and set QINCR */ *x = small; /* GET-FUNCTION-VALUE */ i99999 = 1; goto S300; S10: fsmall = *fx; *x = big; /* GET-FUNCTION-VALUE */ i99999 = 2; goto S300; S20: fbig = *fx; qincr = fbig > fsmall; if(!qincr) goto S50; if(fsmall <= 0.0e0) goto S30; *status = -1; *qleft = *qhi = 1; return; S30: if(fbig >= 0.0e0) goto S40; *status = -1; *qleft = *qhi = 0; return; S40: goto S80; S50: if(fsmall >= 0.0e0) goto S60; *status = -1; *qleft = 1; *qhi = 0; return; S60: if(fbig <= 0.0e0) goto S70; *status = -1; *qleft = 0; *qhi = 1; return; S80: S70: *x = xsave; step = fifdmax1(absstp,relstp*fabs(*x)); /* YY = F(X) - Y GET-FUNCTION-VALUE */ i99999 = 3; goto S300; S90: yy = *fx; if(!(yy == 0.0e0)) goto S100; *status = 0; /* qok = 1; result never used */ return; S100: qup = ( qincr && yy < 0.0e0 ) || ( !qincr && yy > 0.0e0 ); /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ HANDLE CASE IN WHICH WE MUST STEP HIGHER ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ if(!qup) goto S170; xlb = xsave; xub = fifdmin1(xlb+step,big); goto S120; S110: if(qcond) goto S150; S120: /* YY = F(XUB) - Y */ *x = xub; /* GET-FUNCTION-VALUE */ i99999 = 4; goto S300; S130: yy = *fx; qbdd = ( qincr && yy >= 0.0e0 ) || (!qincr && yy <= 0.0e0 ); qlim = xub >= big; qcond = qbdd || qlim; if(qcond) goto S140; step = stpmul*step; xlb = xub; xub = fifdmin1(xlb+step,big); S140: goto S110; S150: if(!(qlim && !qbdd)) goto S160; *status = -1; *qleft = 0; *qhi = !qincr; *x = big; return; S160: goto S240; S170: /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ HANDLE CASE IN WHICH WE MUST STEP LOWER ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ xub = xsave; xlb = fifdmax1(xub-step,small); goto S190; S180: if(qcond) goto S220; S190: /* YY = F(XLB) - Y */ *x = xlb; /* GET-FUNCTION-VALUE */ i99999 = 5; goto S300; S200: yy = *fx; qbdd = ( qincr && yy <= 0.0e0 ) || (!qincr && yy >= 0.0e0 ); qlim = xlb <= small; qcond = qbdd || qlim; if(qcond) goto S210; step = stpmul*step; xub = xlb; xlb = fifdmax1(xub-step,small); S210: goto S180; S220: if(!(qlim && !qbdd)) goto S230; *status = -1; *qleft = 1; *qhi = qincr; *x = small; return; S240: S230: dstzr(&xlb,&xub,&abstol,&reltol); /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ IF WE REACH HERE, XLB AND XUB BOUND THE ZERO OF F. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ *status = 0; goto S260; S250: if(!(*status == 1)) goto S290; S260: dzror(status,x,fx,&xlo,&xhi,&qdum1,&qdum2); if(!(*status == 1)) goto S280; /* GET-FUNCTION-VALUE */ i99999 = 6; goto S300; S280: S270: goto S250; S290: *x = xlo; *status = 0; return; DSTINV: small = *zsmall; big = *zbig; absstp = *zabsst; relstp = *zrelst; stpmul = *zstpmu; abstol = *zabsto; reltol = *zrelto; return; S300: /* TO GET-FUNCTION-VALUE */ *status = 1; return; S310: switch((int)i99999){case 1: goto S10;case 2: goto S20;case 3: goto S90;case 4: goto S130;case 5: goto S200;case 6: goto S270;default: break;} #undef qxmon } /* END */ /***=====================================================================***/ void dinvr(int *status,double *x,double *fx, unsigned long *qleft,unsigned long *qhi) /* ********************************************************************** void dinvr(int *status,double *x,double *fx, unsigned long *qleft,unsigned long *qhi) Double precision bounds the zero of the function and invokes zror Reverse Communication Function Bounds the function and invokes ZROR to perform the zero finding. STINVR must have been called before this routine in order to set its parameters. Arguments STATUS <--> At the beginning of a zero finding problem, STATUS should be set to 0 and INVR invoked. (The value of parameters other than X will be ignored on this cal When INVR needs the function evaluated, it will set STATUS to 1 and return. The value of the function should be set in FX and INVR again called without changing any of its other parameters. When INVR has finished without error, it will return with STATUS 0. In that case X is approximately a root of F(X). If INVR cannot bound the function, it returns status -1 and sets QLEFT and QHI. INTEGER STATUS X <-- The value of X at which F(X) is to be evaluated. DOUBLE PRECISION X FX --> The value of F(X) calculated when INVR returns with STATUS = 1. DOUBLE PRECISION FX QLEFT <-- Defined only if QMFINV returns .FALSE. In that case it is .TRUE. If the stepping search terminated unsucessfully at SMALL. If it is .FALSE. the search terminated unsucessfully at BIG. QLEFT is LOGICAL QHI <-- Defined only if QMFINV returns .FALSE. In that case it is .TRUE. if F(X) .GT. Y at the termination of the search and .FALSE. if F(X) .LT. Y at the termination of the search. QHI is LOGICAL ********************************************************************** */ { E0000(0,status,x,fx,qleft,qhi,NULL,NULL,NULL,NULL,NULL,NULL,NULL); } /* END */ /***=====================================================================***/ void dstinv(double *zsmall,double *zbig,double *zabsst, double *zrelst,double *zstpmu,double *zabsto, double *zrelto) /* ********************************************************************** void dstinv(double *zsmall,double *zbig,double *zabsst, double *zrelst,double *zstpmu,double *zabsto, double *zrelto) Double Precision - SeT INverse finder - Reverse Communication Function Concise Description - Given a monotone function F finds X such that F(X) = Y. Uses Reverse communication -- see invr. This routine sets quantities needed by INVR. More Precise Description of INVR - F must be a monotone function, the results of QMFINV are otherwise undefined. QINCR must be .TRUE. if F is non- decreasing and .FALSE. if F is non-increasing. QMFINV will return .TRUE. if and only if F(SMALL) and F(BIG) bracket Y, i. e., QINCR is .TRUE. and F(SMALL).LE.Y.LE.F(BIG) or QINCR is .FALSE. and F(BIG).LE.Y.LE.F(SMALL) if QMFINV returns .TRUE., then the X returned satisfies the following condition. let TOL(X) = MAX(ABSTOL,RELTOL*ABS(X)) then if QINCR is .TRUE., F(X-TOL(X)) .LE. Y .LE. F(X+TOL(X)) and if QINCR is .FALSE. F(X-TOL(X)) .GE. Y .GE. F(X+TOL(X)) Arguments SMALL --> The left endpoint of the interval to be searched for a solution. SMALL is DOUBLE PRECISION BIG --> The right endpoint of the interval to be searched for a solution. BIG is DOUBLE PRECISION ABSSTP, RELSTP --> The initial step size in the search is MAX(ABSSTP,RELSTP*ABS(X)). See algorithm. ABSSTP is DOUBLE PRECISION RELSTP is DOUBLE PRECISION STPMUL --> When a step doesn't bound the zero, the step size is multiplied by STPMUL and another step taken. A popular value is 2.0 DOUBLE PRECISION STPMUL ABSTOL, RELTOL --> Two numbers that determine the accuracy of the solution. See function for a precise definition. ABSTOL is DOUBLE PRECISION RELTOL is DOUBLE PRECISION Method Compares F(X) with Y for the input value of X then uses QINCR to determine whether to step left or right to bound the desired x. the initial step size is MAX(ABSSTP,RELSTP*ABS(S)) for the input value of X. Iteratively steps right or left until it bounds X. At each step which doesn't bound X, the step size is doubled. The routine is careful never to step beyond SMALL or BIG. If it hasn't bounded X at SMALL or BIG, QMFINV returns .FALSE. after setting QLEFT and QHI. If X is successfully bounded then Algorithm R of the paper 'Two Efficient Algorithms with Guaranteed Convergence for Finding a Zero of a Function' by J. C. P. Bus and T. J. Dekker in ACM Transactions on Mathematical Software, Volume 1, No. 4 page 330 (DEC. '75) is employed to find the zero of the function F(X)-Y. This is routine QRZERO. ********************************************************************** */ { E0000(1,NULL,NULL,NULL,NULL,NULL,zabsst,zabsto,zbig,zrelst,zrelto,zsmall, zstpmu); } /* END */ #if defined(__COMPILE_UNUSED_FUNCTIONS__) /***=====================================================================***/ double dlanor(double *x) /* ********************************************************************** double dlanor(double *x) Double precision Logarith of the Asymptotic Normal Function Computes the logarithm of the cumulative normal distribution from abs( x ) to infinity for abs( x ) >= 5. Arguments X --> Value at which cumulative normal to be evaluated DOUBLE PRECISION X Method 23 term expansion of formula 26.2.12 of Abramowitz and Stegun. The relative error at X = 5 is about 0.5E-5. Note ABS(X) must be >= 5 else there is an error stop. ********************************************************************** */ { #define dlsqpi 0.91893853320467274177e0 static double coef[12] = { -1.0e0,3.0e0,-15.0e0,105.0e0,-945.0e0,10395.0e0,-135135.0e0,2027025.0e0, -34459425.0e0,654729075.0e0,-13749310575.e0,316234143225.0e0 }; static int K1 = 12; static double dlanor,approx,correc,xx,xx2,T2; /* .. .. Executable Statements .. */ xx = fabs(*x); if(xx < 5.0e0){ ftnstop("Argument too small in DLANOR"); return 66.6; } approx = -dlsqpi-0.5e0*xx*xx-log(xx); xx2 = xx*xx; T2 = 1.0e0/xx2; correc = devlpl(coef,&K1,&T2)/xx2; correc = dln1px(&correc); dlanor = approx+correc; return dlanor; #undef dlsqpi } /* END */ /***=====================================================================***/ double dln1mx(double *x) /* ********************************************************************** double dln1mx(double *x) Double precision LN(1-X) Function Returns ln(1-x) for small x (good accuracy if x .le. 0.1). Note that the obvious code of LOG(1.0-X) won't work for small X because 1.0-X loses accuracy Arguments X --> Value for which ln(1-x) is desired. X is DOUBLE PRECISION Method If X > 0.1, the obvious code above is used ELSE The Taylor series for 1-x is expanded to 20 terms. ********************************************************************** */ { static double dln1mx,T1; /* .. .. Executable Statements .. */ T1 = -*x; dln1mx = dln1px(&T1); return dln1mx; } /* END */ /***=====================================================================***/ double dln1px(double *a) /* ********************************************************************** double dln1px(double *a) Double precision LN(1+X) Function Returns ln(1+x) Note that the obvious code of LOG(1.0+X) won't work for small X because 1.0+X loses accuracy Arguments X --> Value for which ln(1-x) is desired. X is DOUBLE PRECISION Method Renames ALNREL from: DiDinato, A. R. and Morris, A. H. Algorithm 708: Significant Digit Computation of the Incomplete Beta Function Ratios. ACM Trans. Math. Softw. 18 (1993), 360-373. ********************************************************************** ----------------------------------------------------------------------- EVALUATION OF THE FUNCTION LN(1 + A) ----------------------------------------------------------------------- */ { static double p1 = -.129418923021993e+01; static double p2 = .405303492862024e+00; static double p3 = -.178874546012214e-01; static double q1 = -.162752256355323e+01; static double q2 = .747811014037616e+00; static double q3 = -.845104217945565e-01; static double dln1px,t,t2,w,x; /* .. .. Executable Statements .. */ if(fabs(*a) > 0.375e0) goto S10; t = *a/(*a+2.0e0); t2 = t*t; w = (((p3*t2+p2)*t2+p1)*t2+1.0e0)/(((q3*t2+q2)*t2+q1)*t2+1.0e0); dln1px = 2.0e0*t*w; return dln1px; S10: x = 1.e0+*a; dln1px = log(x); return dln1px; } /* END */ /***=====================================================================***/ double dlnbet(double *a0,double *b0) /* ********************************************************************** double dlnbet(a0,b0) Double precision LN of the complete BETa Function Returns the natural log of the complete beta function, i.e., ln( Gamma(a)*Gamma(b) / Gamma(a+b) Arguments A,B --> The (symmetric) arguments to the complete beta DOUBLE PRECISION A, B Method Renames BETALN from: DiDinato, A. R. and Morris, A. H. Algorithm 708: Significant Digit Computation of the Incomplete Beta Function Ratios. ACM Trans. Math. Softw. 18 (1993), 360-373. ********************************************************************** ----------------------------------------------------------------------- EVALUATION OF THE LOGARITHM OF THE BETA FUNCTION ----------------------------------------------------------------------- E = 0.5*LN(2*PI) -------------------------- */ { static double e = .918938533204673e0; static double dlnbet,a,b,c,h,u,v,w,z; static int i,n; static double T1; /* .. .. Executable Statements .. */ a = fifdmin1(*a0,*b0); b = fifdmax1(*a0,*b0); if(a >= 8.0e0) goto S100; if(a >= 1.0e0) goto S20; /* ----------------------------------------------------------------------- PROCEDURE WHEN A .LT. 1 ----------------------------------------------------------------------- */ if(b >= 8.0e0) goto S10; T1 = a+b; dlnbet = gamln(&a)+(gamln(&b)-gamln(&T1)); return dlnbet; S10: dlnbet = gamln(&a)+algdiv(&a,&b); return dlnbet; S20: /* ----------------------------------------------------------------------- PROCEDURE WHEN 1 .LE. A .LT. 8 ----------------------------------------------------------------------- */ if(a > 2.0e0) goto S40; if(b > 2.0e0) goto S30; dlnbet = gamln(&a)+gamln(&b)-gsumln(&a,&b); return dlnbet; S30: w = 0.0e0; if(b < 8.0e0) goto S60; dlnbet = gamln(&a)+algdiv(&a,&b); return dlnbet; S40: /* REDUCTION OF A WHEN B .LE. 1000 */ if(b > 1000.0e0) goto S80; n = a-1.0e0; w = 1.0e0; for(i=1; i<=n; i++) { a -= 1.0e0; h = a/b; w *= (h/(1.0e0+h)); } w = log(w); if(b < 8.0e0) goto S60; dlnbet = w+gamln(&a)+algdiv(&a,&b); return dlnbet; S60: /* REDUCTION OF B WHEN B .LT. 8 */ n = b-1.0e0; z = 1.0e0; for(i=1; i<=n; i++) { b -= 1.0e0; z *= (b/(a+b)); } dlnbet = w+log(z)+(gamln(&a)+(gamln(&b)-gsumln(&a,&b))); return dlnbet; S80: /* REDUCTION OF A WHEN B .GT. 1000 */ n = a-1.0e0; w = 1.0e0; for(i=1; i<=n; i++) { a -= 1.0e0; w *= (a/(1.0e0+a/b)); } dlnbet = log(w)-(double)n*log(b)+(gamln(&a)+algdiv(&a,&b)); return dlnbet; S100: /* ----------------------------------------------------------------------- PROCEDURE WHEN A .GE. 8 ----------------------------------------------------------------------- */ w = bcorr(&a,&b); h = a/b; c = h/(1.0e0+h); u = -((a-0.5e0)*log(c)); v = b*alnrel(&h); if(u <= v) goto S110; dlnbet = -(0.5e0*log(b))+e+w-v-u; return dlnbet; S110: dlnbet = -(0.5e0*log(b))+e+w-u-v; return dlnbet; } /* END */ /***=====================================================================***/ double dlngam(double *a) /* ********************************************************************** double dlngam(double *a) Double precision LN of the GAMma function Function Returns the natural logarithm of GAMMA(X). Arguments X --> value at which scaled log gamma is to be returned X is DOUBLE PRECISION Method Renames GAMLN from: DiDinato, A. R. and Morris, A. H. Algorithm 708: Significant Digit Computation of the Incomplete Beta Function Ratios. ACM Trans. Math. Softw. 18 (1993), 360-373. ********************************************************************** ----------------------------------------------------------------------- EVALUATION OF LN(GAMMA(A)) FOR POSITIVE A ----------------------------------------------------------------------- WRITTEN BY ALFRED H. MORRIS NAVAL SURFACE WARFARE CENTER DAHLGREN, VIRGINIA -------------------------- D = 0.5*(LN(2*PI) - 1) -------------------------- */ { static double c0 = .833333333333333e-01; static double c1 = -.277777777760991e-02; static double c2 = .793650666825390e-03; static double c3 = -.595202931351870e-03; static double c4 = .837308034031215e-03; static double c5 = -.165322962780713e-02; static double d = .418938533204673e0; static double dlngam,t,w; static int i,n; static double T1; /* .. .. Executable Statements .. */ if(*a > 0.8e0) goto S10; dlngam = gamln1(a)-log(*a); return dlngam; S10: if(*a > 2.25e0) goto S20; t = *a-0.5e0-0.5e0; dlngam = gamln1(&t); return dlngam; S20: if(*a >= 10.0e0) goto S40; n = *a-1.25e0; t = *a; w = 1.0e0; for(i=1; i<=n; i++) { t -= 1.0e0; w = t*w; } T1 = t-1.0e0; dlngam = gamln1(&T1)+log(w); return dlngam; S40: t = pow(1.0e0/ *a,2.0); w = (((((c5*t+c4)*t+c3)*t+c2)*t+c1)*t+c0)/ *a; dlngam = d+w+(*a-0.5e0)*(log(*a)-1.0e0); return dlngam; } /* END */ /***=====================================================================***/ double dstrem(double *z) { /* ********************************************************************** double dstrem(double *z) Double precision Sterling Remainder Function Returns Log(Gamma(Z)) - Sterling(Z) where Sterling(Z) is Sterling's Approximation to Log(Gamma(Z)) Sterling(Z) = LOG( SQRT( 2*PI ) ) + ( Z-0.5 ) * LOG( Z ) - Z Arguments Z --> Value at which Sterling remainder calculated Must be positive. DOUBLE PRECISION Z Method If Z >= 6 uses 9 terms of series in Bernoulli numbers (Values calculated using Maple) Otherwise computes difference explicitly ********************************************************************** */ #define hln2pi 0.91893853320467274178e0 #define ncoef 10 static double coef[ncoef] = { 0.0e0,0.0833333333333333333333333333333e0, -0.00277777777777777777777777777778e0,0.000793650793650793650793650793651e0, -0.000595238095238095238095238095238e0, 0.000841750841750841750841750841751e0,-0.00191752691752691752691752691753e0, 0.00641025641025641025641025641026e0,-0.0295506535947712418300653594771e0, 0.179644372368830573164938490016e0 }; static int K1 = 10; static double dstrem,sterl,T2; /* .. .. Executable Statements .. */ /* For information, here are the next 11 coefficients of the remainder term in Sterling's formula -1.39243221690590111642743221691 13.4028640441683919944789510007 -156.848284626002017306365132452 2193.10333333333333333333333333 -36108.7712537249893571732652192 691472.268851313067108395250776 -0.152382215394074161922833649589D8 0.382900751391414141414141414141D9 -0.108822660357843910890151491655D11 0.347320283765002252252252252252D12 -0.123696021422692744542517103493D14 */ if(*z <= 0.0e0){ ftnstop("nonpositive argument in DSTREM"); return 66.6; } if(!(*z > 6.0e0)) goto S10; T2 = 1.0e0/pow(*z,2.0); dstrem = devlpl(coef,&K1,&T2)**z; goto S20; S10: sterl = hln2pi+(*z-0.5e0)*log(*z)-*z; dstrem = dlngam(z)-sterl; S20: return dstrem; #undef hln2pi #undef ncoef } /* END */ #endif /*defined(__COMPILE_UNUSED_FUNCTIONS__)*/ /***=====================================================================***/ double dt1(double *p,double *q,const double *df) /* ********************************************************************** double dt1(double *p,double *q,double *df) Double precision Initalize Approximation to INVerse of the cumulative T distribution Function Returns the inverse of the T distribution function, i.e., the integral from 0 to INVT of the T density is P. This is an initial approximation Arguments P --> The p-value whose inverse from the T distribution is desired. P is DOUBLE PRECISION Q --> 1-P. Q is DOUBLE PRECISION DF --> Degrees of freedom of the T distribution. DF is DOUBLE PRECISION ********************************************************************** */ { static double coef[4][5] = { {1.0e0,1.0e0,0.0e0,0.0e0,0.0e0}, {3.0e0,16.0e0,5.0e0,0.0e0,0.0e0}, {-15.0e0,17.0e0,19.0e0,3.0e0,0.0e0}, {-945.0e0,-1920.0e0,1482.0e0,776.0e0,79.0e0} }; static double denom[4] = { 4.0e0,96.0e0,384.0e0,92160.0e0 }; static int ideg[4] = { 2,3,4,5 }; static double dt1,denpow,sum,term,x,xp,xx; static int i; /* .. .. Executable Statements .. */ x = fabs(dinvnr(p,q)); xx = x*x; sum = x; denpow = 1.0e0; for(i=0; i<4; i++) { term = devlpl(&coef[i][0],&ideg[i],&xx)*x; denpow *= *df; sum += (term/(denpow*denom[i])); } if(!(*p >= 0.5e0)) goto S20; xp = sum; goto S30; S20: xp = -sum; S30: dt1 = xp; return dt1; } /* END */ /***=====================================================================***/ void E0001(int IENTRY,int *status,double *x,const double *fx, double *xlo,double *xhi,unsigned long *qleft, unsigned long *qhi,const double *zabstl,const double *zreltl, const double *zxhi,const double *zxlo) { #define ftol(zx) (0.5e0*fifdmax1(abstol,reltol*fabs((zx)))) static double a,abstol,b,c,d,fa,fb,fc,fd,fda,fdb,m,mb,p,q,reltol,tol,w,xxhi,xxlo; static int ext,i99999; static unsigned long first,qrzero; switch(IENTRY){case 0: goto DZROR; case 1: goto DSTZR;} DZROR: if(*status > 0) goto S280; *xlo = xxlo; *xhi = xxhi; b = *x = *xlo; /* GET-FUNCTION-VALUE */ i99999 = 1; goto S270; S10: fb = *fx; *xlo = *xhi; a = *x = *xlo; /* GET-FUNCTION-VALUE */ i99999 = 2; goto S270; S20: /* Check that F(ZXLO) < 0 < F(ZXHI) or F(ZXLO) > 0 > F(ZXHI) */ if(!(fb < 0.0e0)) goto S40; if(!(*fx < 0.0e0)) goto S30; *status = -1; *qleft = *fx < fb; *qhi = 0; return; S40: S30: if(!(fb > 0.0e0)) goto S60; if(!(*fx > 0.0e0)) goto S50; *status = -1; *qleft = *fx > fb; *qhi = 1; return; S60: S50: fa = *fx; first = 1; S70: c = a; fc = fa; ext = 0; S80: if(!(fabs(fc) < fabs(fb))) goto S100; if(!(c != a)) goto S90; d = a; fd = fa; S90: a = b; fa = fb; *xlo = c; b = *xlo; fb = fc; c = a; fc = fa; S100: tol = ftol(*xlo); m = (c+b)*.5e0; mb = m-b; if(!(fabs(mb) > tol)) goto S240; if(!(ext > 3)) goto S110; w = mb; goto S190; S110: tol = fifdsign(tol,mb); p = (b-a)*fb; if(!first) goto S120; q = fa-fb; first = 0; goto S130; S120: fdb = (fd-fb)/(d-b); fda = (fd-fa)/(d-a); p = fda*p; q = fdb*fa-fda*fb; S130: if(!(p < 0.0e0)) goto S140; p = -p; q = -q; S140: if(ext == 3) p *= 2.0e0; if(!(p*1.0e0 == 0.0e0 || p <= q*tol)) goto S150; w = tol; goto S180; S150: if(!(p < mb*q)) goto S160; w = p/q; goto S170; S160: w = mb; S190: S180: S170: d = a; fd = fa; a = b; fa = fb; b += w; *xlo = b; *x = *xlo; /* GET-FUNCTION-VALUE */ i99999 = 3; goto S270; S200: fb = *fx; if(!(fc*fb >= 0.0e0)) goto S210; goto S70; S210: if(!(w == mb)) goto S220; ext = 0; goto S230; S220: ext += 1; S230: goto S80; S240: *xhi = c; qrzero = ((fc >= 0.0e0 && fb <= 0.0e0 ) || (fc < 0.0e0 && fb >= 0.0e0)); if(!qrzero) goto S250; *status = 0; goto S260; S250: *status = -1; S260: return; DSTZR: xxlo = *zxlo; xxhi = *zxhi; abstol = *zabstl; reltol = *zreltl; return; S270: /* TO GET-FUNCTION-VALUE */ *status = 1; return; S280: switch((int)i99999){case 1: goto S10;case 2: goto S20;case 3: goto S200; default: break;} #undef ftol } /* END */ /***=====================================================================***/ void dzror(int *status,double *x,double *fx,double *xlo, double *xhi,unsigned long *qleft,unsigned long *qhi) /* ********************************************************************** void dzror(int *status,double *x,double *fx,double *xlo, double *xhi,unsigned long *qleft,unsigned long *qhi) Double precision ZeRo of a function -- Reverse Communication Function Performs the zero finding. STZROR must have been called before this routine in order to set its parameters. Arguments STATUS <--> At the beginning of a zero finding problem, STATUS should be set to 0 and ZROR invoked. (The value of other parameters will be ignored on this call.) When ZROR needs the function evaluated, it will set STATUS to 1 and return. The value of the function should be set in FX and ZROR again called without changing any of its other parameters. When ZROR has finished without error, it will return with STATUS 0. In that case (XLO,XHI) bound the answe If ZROR finds an error (which implies that F(XLO)-Y an F(XHI)-Y have the same sign, it returns STATUS -1. In this case, XLO and XHI are undefined. INTEGER STATUS X <-- The value of X at which F(X) is to be evaluated. DOUBLE PRECISION X FX --> The value of F(X) calculated when ZROR returns with STATUS = 1. DOUBLE PRECISION FX XLO <-- When ZROR returns with STATUS = 0, XLO bounds the inverval in X containing the solution below. DOUBLE PRECISION XLO XHI <-- When ZROR returns with STATUS = 0, XHI bounds the inverval in X containing the solution above. DOUBLE PRECISION XHI QLEFT <-- .TRUE. if the stepping search terminated unsucessfully at XLO. If it is .FALSE. the search terminated unsucessfully at XHI. QLEFT is LOGICAL QHI <-- .TRUE. if F(X) .GT. Y at the termination of the search and .FALSE. if F(X) .LT. Y at the termination of the search. QHI is LOGICAL ********************************************************************** */ { E0001(0,status,x,fx,xlo,xhi,qleft,qhi,NULL,NULL,NULL,NULL); } /* END */ /***=====================================================================***/ void dstzr(double *zxlo,double *zxhi,double *zabstl,double *zreltl) /* ********************************************************************** void dstzr(double *zxlo,double *zxhi,double *zabstl,double *zreltl) Double precision SeT ZeRo finder - Reverse communication version Function Sets quantities needed by ZROR. The function of ZROR and the quantities set is given here. Concise Description - Given a function F find XLO such that F(XLO) = 0. More Precise Description - Input condition. F is a double precision function of a single double precision argument and XLO and XHI are such that F(XLO)*F(XHI) .LE. 0.0 If the input condition is met, QRZERO returns .TRUE. and output values of XLO and XHI satisfy the following F(XLO)*F(XHI) .LE. 0. ABS(F(XLO) .LE. ABS(F(XHI) ABS(XLO-XHI) .LE. TOL(X) where TOL(X) = MAX(ABSTOL,RELTOL*ABS(X)) If this algorithm does not find XLO and XHI satisfying these conditions then QRZERO returns .FALSE. This implies that the input condition was not met. Arguments XLO --> The left endpoint of the interval to be searched for a solution. XLO is DOUBLE PRECISION XHI --> The right endpoint of the interval to be for a solution. XHI is DOUBLE PRECISION ABSTOL, RELTOL --> Two numbers that determine the accuracy of the solution. See function for a precise definition. ABSTOL is DOUBLE PRECISION RELTOL is DOUBLE PRECISION Method Algorithm R of the paper 'Two Efficient Algorithms with Guaranteed Convergence for Finding a Zero of a Function' by J. C. P. Bus and T. J. Dekker in ACM Transactions on Mathematical Software, Volume 1, no. 4 page 330 (Dec. '75) is employed to find the zero of F(X)-Y. ********************************************************************** */ { E0001(1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,zabstl,zreltl,zxhi,zxlo); } /* END */ /***=====================================================================***/ double erf1(const double *x) /* ----------------------------------------------------------------------- EVALUATION OF THE REAL ERROR FUNCTION ----------------------------------------------------------------------- */ { static double c = .564189583547756e0; static double a[5] = { .771058495001320e-04,-.133733772997339e-02,.323076579225834e-01, .479137145607681e-01,.128379167095513e+00 }; static double b[3] = { .301048631703895e-02,.538971687740286e-01,.375795757275549e+00 }; static double p[8] = { -1.36864857382717e-07,5.64195517478974e-01,7.21175825088309e+00, 4.31622272220567e+01,1.52989285046940e+02,3.39320816734344e+02, 4.51918953711873e+02,3.00459261020162e+02 }; static double q[8] = { 1.00000000000000e+00,1.27827273196294e+01,7.70001529352295e+01, 2.77585444743988e+02,6.38980264465631e+02,9.31354094850610e+02, 7.90950925327898e+02,3.00459260956983e+02 }; static double r[5] = { 2.10144126479064e+00,2.62370141675169e+01,2.13688200555087e+01, 4.65807828718470e+00,2.82094791773523e-01 }; static double s[4] = { 9.41537750555460e+01,1.87114811799590e+02,9.90191814623914e+01, 1.80124575948747e+01 }; static double erf1,ax,bot,t,top,x2; /* .. .. Executable Statements .. */ ax = fabs(*x); if(ax > 0.5e0) goto S10; t = *x**x; top = (((a[0]*t+a[1])*t+a[2])*t+a[3])*t+a[4]+1.0e0; bot = ((b[0]*t+b[1])*t+b[2])*t+1.0e0; erf1 = *x*(top/bot); return erf1; S10: if(ax > 4.0e0) goto S20; top = ((((((p[0]*ax+p[1])*ax+p[2])*ax+p[3])*ax+p[4])*ax+p[5])*ax+p[6])*ax+p[ 7]; bot = ((((((q[0]*ax+q[1])*ax+q[2])*ax+q[3])*ax+q[4])*ax+q[5])*ax+q[6])*ax+q[ 7]; erf1 = 0.5e0+(0.5e0-exp(-(*x**x))*top/bot); if(*x < 0.0e0) erf1 = -erf1; return erf1; S20: if(ax >= 5.8e0) goto S30; x2 = *x**x; t = 1.0e0/x2; top = (((r[0]*t+r[1])*t+r[2])*t+r[3])*t+r[4]; bot = (((s[0]*t+s[1])*t+s[2])*t+s[3])*t+1.0e0; erf1 = (c-top/(x2*bot))/ax; erf1 = 0.5e0+(0.5e0-exp(-x2)*erf1); if(*x < 0.0e0) erf1 = -erf1; return erf1; S30: erf1 = fifdsign(1.0e0,*x); return erf1; } /* END */ /***=====================================================================***/ double erfc1(const int *ind,const double *x) /* ----------------------------------------------------------------------- EVALUATION OF THE COMPLEMENTARY ERROR FUNCTION ERFC1(IND,X) = ERFC(X) IF IND = 0 ERFC1(IND,X) = EXP(X*X)*ERFC(X) OTHERWISE ----------------------------------------------------------------------- */ { static double c = .564189583547756e0; static double a[5] = { .771058495001320e-04,-.133733772997339e-02,.323076579225834e-01, .479137145607681e-01,.128379167095513e+00 }; static double b[3] = { .301048631703895e-02,.538971687740286e-01,.375795757275549e+00 }; static double p[8] = { -1.36864857382717e-07,5.64195517478974e-01,7.21175825088309e+00, 4.31622272220567e+01,1.52989285046940e+02,3.39320816734344e+02, 4.51918953711873e+02,3.00459261020162e+02 }; static double q[8] = { 1.00000000000000e+00,1.27827273196294e+01,7.70001529352295e+01, 2.77585444743988e+02,6.38980264465631e+02,9.31354094850610e+02, 7.90950925327898e+02,3.00459260956983e+02 }; static double r[5] = { 2.10144126479064e+00,2.62370141675169e+01,2.13688200555087e+01, 4.65807828718470e+00,2.82094791773523e-01 }; static double s[4] = { 9.41537750555460e+01,1.87114811799590e+02,9.90191814623914e+01, 1.80124575948747e+01 }; static int K1 = 1; static double erfc1,ax,bot,e,t,top,w; /* .. .. Executable Statements .. */ /* ABS(X) .LE. 0.5 */ ax = fabs(*x); if(ax > 0.5e0) goto S10; t = *x**x; top = (((a[0]*t+a[1])*t+a[2])*t+a[3])*t+a[4]+1.0e0; bot = ((b[0]*t+b[1])*t+b[2])*t+1.0e0; erfc1 = 0.5e0+(0.5e0-*x*(top/bot)); if(*ind != 0) erfc1 = exp(t)*erfc1; return erfc1; S10: /* 0.5 .LT. ABS(X) .LE. 4 */ if(ax > 4.0e0) goto S20; top = ((((((p[0]*ax+p[1])*ax+p[2])*ax+p[3])*ax+p[4])*ax+p[5])*ax+p[6])*ax+p[ 7]; bot = ((((((q[0]*ax+q[1])*ax+q[2])*ax+q[3])*ax+q[4])*ax+q[5])*ax+q[6])*ax+q[ 7]; erfc1 = top/bot; goto S40; S20: /* ABS(X) .GT. 4 */ if(*x <= -5.6e0) goto S60; if(*ind != 0) goto S30; if(*x > 100.0e0) goto S70; if(*x**x > -exparg(&K1)) goto S70; S30: t = pow(1.0e0/ *x,2.0); top = (((r[0]*t+r[1])*t+r[2])*t+r[3])*t+r[4]; bot = (((s[0]*t+s[1])*t+s[2])*t+s[3])*t+1.0e0; erfc1 = (c-t*top/bot)/ax; S40: /* FINAL ASSEMBLY */ if(*ind == 0) goto S50; if(*x < 0.0e0) erfc1 = 2.0e0*exp(*x**x)-erfc1; return erfc1; S50: w = *x**x; t = w; e = w-t; erfc1 = (0.5e0+(0.5e0-e))*exp(-t)*erfc1; if(*x < 0.0e0) erfc1 = 2.0e0-erfc1; return erfc1; S60: /* LIMIT VALUE FOR LARGE NEGATIVE X */ erfc1 = 2.0e0; if(*ind != 0) erfc1 = 2.0e0*exp(*x**x); return erfc1; S70: /* LIMIT VALUE FOR LARGE POSITIVE X WHEN IND = 0 */ erfc1 = 0.0e0; return erfc1; } /* END */ /***=====================================================================***/ double esum(const int *mu,const double *x) /* ----------------------------------------------------------------------- EVALUATION OF EXP(MU + X) ----------------------------------------------------------------------- */ { static double esum,w; /* .. .. Executable Statements .. */ if(*x > 0.0e0) goto S10; if(*mu < 0) goto S20; w = (double)*mu+*x; if(w > 0.0e0) goto S20; esum = exp(w); return esum; S10: if(*mu > 0) goto S20; w = (double)*mu+*x; if(w < 0.0e0) goto S20; esum = exp(w); return esum; S20: w = *mu; esum = exp(w)*exp(*x); return esum; } /* END */ /***=====================================================================***/ double exparg(const int *l) /* -------------------------------------------------------------------- IF L = 0 THEN EXPARG(L) = THE LARGEST POSITIVE W FOR WHICH EXP(W) CAN BE COMPUTED. IF L IS NONZERO THEN EXPARG(L) = THE LARGEST NEGATIVE W FOR WHICH THE COMPUTED VALUE OF EXP(W) IS NONZERO. NOTE... ONLY AN APPROXIMATE VALUE FOR EXPARG(L) IS NEEDED. -------------------------------------------------------------------- */ { static int K1 = 4; static int K2 = 9; static int K3 = 10; static double exparg,lnb; static int b,m; /* .. .. Executable Statements .. */ b = ipmpar(&K1); if(b != 2) goto S10; lnb = .69314718055995e0; goto S40; S10: if(b != 8) goto S20; lnb = 2.0794415416798e0; goto S40; S20: if(b != 16) goto S30; lnb = 2.7725887222398e0; goto S40; S30: lnb = log((double)b); S40: if(*l == 0) goto S50; m = ipmpar(&K2)-1; exparg = 0.99999e0*((double)m*lnb); return exparg; S50: m = ipmpar(&K3); exparg = 0.99999e0*((double)m*lnb); return exparg; } /* END */ /***=====================================================================***/ double fpser(const double *a,const double *b,const double *x,const double *eps) /* ----------------------------------------------------------------------- EVALUATION OF I (A,B) X FOR B .LT. MIN(EPS,EPS*A) AND X .LE. 0.5. ----------------------------------------------------------------------- SET FPSER = X**A */ { static int K1 = 1; static double fpser,an,c,s,t,tol; /* .. .. Executable Statements .. */ fpser = 1.0e0; if(*a <= 1.e-3**eps) goto S10; fpser = 0.0e0; t = *a*log(*x); if(t < exparg(&K1)) return fpser; fpser = exp(t); S10: /* NOTE THAT 1/B(A,B) = B */ fpser = *b/ *a*fpser; tol = *eps/ *a; an = *a+1.0e0; t = *x; s = t/an; S20: an += 1.0e0; t = *x*t; c = t/an; s += c; if(fabs(c) > tol) goto S20; fpser *= (1.0e0+*a*s); return fpser; } /* END */ /***=====================================================================***/ double gam1(const double *a) /* ------------------------------------------------------------------ COMPUTATION OF 1/GAMMA(A+1) - 1 FOR -0.5 .LE. A .LE. 1.5 ------------------------------------------------------------------ */ { static double s1 = .273076135303957e+00; static double s2 = .559398236957378e-01; static double p[7] = { .577215664901533e+00,-.409078193005776e+00,-.230975380857675e+00, .597275330452234e-01,.766968181649490e-02,-.514889771323592e-02, .589597428611429e-03 }; static double q[5] = { .100000000000000e+01,.427569613095214e+00,.158451672430138e+00, .261132021441447e-01,.423244297896961e-02 }; static double r[9] = { -.422784335098468e+00,-.771330383816272e+00,-.244757765222226e+00, .118378989872749e+00,.930357293360349e-03,-.118290993445146e-01, .223047661158249e-02,.266505979058923e-03,-.132674909766242e-03 }; static double gam1,bot,d,t,top,w,T1; /* .. .. Executable Statements .. */ t = *a; d = *a-0.5e0; if(d > 0.0e0) t = d-0.5e0; T1 = t; if(T1 < 0) goto S40; else if(T1 == 0) goto S10; else goto S20; S10: gam1 = 0.0e0; return gam1; S20: top = (((((p[6]*t+p[5])*t+p[4])*t+p[3])*t+p[2])*t+p[1])*t+p[0]; bot = (((q[4]*t+q[3])*t+q[2])*t+q[1])*t+1.0e0; w = top/bot; if(d > 0.0e0) goto S30; gam1 = *a*w; return gam1; S30: gam1 = t/ *a*(w-0.5e0-0.5e0); return gam1; S40: top = (((((((r[8]*t+r[7])*t+r[6])*t+r[5])*t+r[4])*t+r[3])*t+r[2])*t+r[1])*t+ r[0]; bot = (s2*t+s1)*t+1.0e0; w = top/bot; if(d > 0.0e0) goto S50; gam1 = *a*(w+0.5e0+0.5e0); return gam1; S50: gam1 = t*w/ *a; return gam1; } /* END */ /***=====================================================================***/ void gaminv(double *a,double *x,const double *x0,const double *p,const double *q, int *ierr) /* ---------------------------------------------------------------------- INVERSE INCOMPLETE GAMMA RATIO FUNCTION GIVEN POSITIVE A, AND NONEGATIVE P AND Q WHERE P + Q = 1. THEN X IS COMPUTED WHERE P(A,X) = P AND Q(A,X) = Q. SCHRODER ITERATION IS EMPLOYED. THE ROUTINE ATTEMPTS TO COMPUTE X TO 10 SIGNIFICANT DIGITS IF THIS IS POSSIBLE FOR THE PARTICULAR COMPUTER ARITHMETIC BEING USED. ------------ X IS A VARIABLE. IF P = 0 THEN X IS ASSIGNED THE VALUE 0, AND IF Q = 0 THEN X IS SET TO THE LARGEST FLOATING POINT NUMBER AVAILABLE. OTHERWISE, GAMINV ATTEMPTS TO OBTAIN A SOLUTION FOR P(A,X) = P AND Q(A,X) = Q. IF THE ROUTINE IS SUCCESSFUL THEN THE SOLUTION IS STORED IN X. X0 IS AN OPTIONAL INITIAL APPROXIMATION FOR X. IF THE USER DOES NOT WISH TO SUPPLY AN INITIAL APPROXIMATION, THEN SET X0 .LE. 0. IERR IS A VARIABLE THAT REPORTS THE STATUS OF THE RESULTS. WHEN THE ROUTINE TERMINATES, IERR HAS ONE OF THE FOLLOWING VALUES ... IERR = 0 THE SOLUTION WAS OBTAINED. ITERATION WAS NOT USED. IERR.GT.0 THE SOLUTION WAS OBTAINED. IERR ITERATIONS WERE PERFORMED. IERR = -2 (INPUT ERROR) A .LE. 0 IERR = -3 NO SOLUTION WAS OBTAINED. THE RATIO Q/A IS TOO LARGE. IERR = -4 (INPUT ERROR) P + Q .NE. 1 IERR = -6 20 ITERATIONS WERE PERFORMED. THE MOST RECENT VALUE OBTAINED FOR X IS GIVEN. THIS CANNOT OCCUR IF X0 .LE. 0. IERR = -7 ITERATION FAILED. NO VALUE IS GIVEN FOR X. THIS MAY OCCUR WHEN X IS APPROXIMATELY 0. IERR = -8 A VALUE FOR X HAS BEEN OBTAINED, BUT THE ROUTINE IS NOT CERTAIN OF ITS ACCURACY. ITERATION CANNOT BE PERFORMED IN THIS CASE. IF X0 .LE. 0, THIS CAN OCCUR ONLY WHEN P OR Q IS APPROXIMATELY 0. IF X0 IS POSITIVE THEN THIS CAN OCCUR WHEN A IS EXCEEDINGLY CLOSE TO X AND A IS EXTREMELY LARGE (SAY A .GE. 1.E20). ---------------------------------------------------------------------- WRITTEN BY ALFRED H. MORRIS, JR. NAVAL SURFACE WEAPONS CENTER DAHLGREN, VIRGINIA ------------------- */ { static double a0 = 3.31125922108741e0; static double a1 = 11.6616720288968e0; static double a2 = 4.28342155967104e0; static double a3 = .213623493715853e0; static double b1 = 6.61053765625462e0; static double b2 = 6.40691597760039e0; static double b3 = 1.27364489782223e0; static double b4 = .036117081018842e0; static double c = .577215664901533e0; static double ln10 = 2.302585e0; static double tol = 1.e-5; static double amin[2] = { 500.0e0,100.0e0 }; static double bmin[2] = { 1.e-28,1.e-13 }; static double dmin[2] = { 1.e-06,1.e-04 }; static double emin[2] = { 2.e-03,6.e-03 }; static double eps0[2] = { 1.e-10,1.e-08 }; static int K1 = 1; static int K2 = 2; static int K3 = 3; static int K8 = 0; static double am1,amax,ap1,ap2,ap3,apn,b,c1,c2,c3,c4,c5,d,e,e2,eps,g,h,pn,qg,qn, r,rta,s,s2,sum,t,u,w,xmax,xmin,xn,y,z; static int iop; static double T4,T5,T6,T7,T9; /* .. .. Executable Statements .. */ /* ****** E, XMIN, AND XMAX ARE MACHINE DEPENDENT CONSTANTS. E IS THE SMALLEST NUMBER FOR WHICH 1.0 + E .GT. 1.0. XMIN IS THE SMALLEST POSITIVE NUMBER AND XMAX IS THE LARGEST POSITIVE NUMBER. */ e = spmpar(&K1); xmin = spmpar(&K2); xmax = spmpar(&K3); *x = 0.0e0; if(*a <= 0.0e0) goto S300; t = *p+*q-1.e0; if(fabs(t) > e) goto S320; *ierr = 0; if(*p == 0.0e0) return; if(*q == 0.0e0) goto S270; if(*a == 1.0e0) goto S280; e2 = 2.0e0*e; amax = 0.4e-10/(e*e); iop = 1; if(e > 1.e-10) iop = 2; eps = eps0[iop-1]; xn = *x0; if(*x0 > 0.0e0) goto S160; /* SELECTION OF THE INITIAL APPROXIMATION XN OF X WHEN A .LT. 1 */ if(*a > 1.0e0) goto S80; T4 = *a+1.0e0; g = Xgamm(&T4); qg = *q*g; if(qg == 0.0e0) goto S360; b = qg/ *a; if(qg > 0.6e0**a) goto S40; if(*a >= 0.30e0 || b < 0.35e0) goto S10; t = exp(-(b+c)); u = t*exp(t); xn = t*exp(u); goto S160; S10: if(b >= 0.45e0) goto S40; if(b == 0.0e0) goto S360; y = -log(b); s = 0.5e0+(0.5e0-*a); z = log(y); t = y-s*z; if(b < 0.15e0) goto S20; xn = y-s*log(t)-log(1.0e0+s/(t+1.0e0)); goto S220; S20: if(b <= 0.01e0) goto S30; u = ((t+2.0e0*(3.0e0-*a))*t+(2.0e0-*a)*(3.0e0-*a))/((t+(5.0e0-*a))*t+2.0e0); xn = y-s*log(t)-log(u); goto S220; S30: c1 = -(s*z); c2 = -(s*(1.0e0+c1)); c3 = s*((0.5e0*c1+(2.0e0-*a))*c1+(2.5e0-1.5e0**a)); c4 = -(s*(((c1/3.0e0+(2.5e0-1.5e0**a))*c1+((*a-6.0e0)**a+7.0e0))*c1+( (11.0e0**a-46.0)**a+47.0e0)/6.0e0)); c5 = -(s*((((-(c1/4.0e0)+(11.0e0**a-17.0e0)/6.0e0)*c1+((-(3.0e0**a)+13.0e0)* *a-13.0e0))*c1+0.5e0*(((2.0e0**a-25.0e0)**a+72.0e0)**a-61.0e0))*c1+(( (25.0e0**a-195.0e0)**a+477.0e0)**a-379.0e0)/12.0e0)); xn = (((c5/y+c4)/y+c3)/y+c2)/y+c1+y; if(*a > 1.0e0) goto S220; if(b > bmin[iop-1]) goto S220; *x = xn; return; S40: if(b**q > 1.e-8) goto S50; xn = exp(-(*q/ *a+c)); goto S70; S50: if(*p <= 0.9e0) goto S60; T5 = -*q; xn = exp((alnrel(&T5)+gamln1(a))/ *a); goto S70; S60: xn = exp(log(*p*g)/ *a); S70: if(xn == 0.0e0) goto S310; t = 0.5e0+(0.5e0-xn/(*a+1.0e0)); xn /= t; goto S160; S80: /* SELECTION OF THE INITIAL APPROXIMATION XN OF X WHEN A .GT. 1 */ if(*q <= 0.5e0) goto S90; w = log(*p); goto S100; S90: w = log(*q); S100: t = sqrt(-(2.0e0*w)); s = t-(((a3*t+a2)*t+a1)*t+a0)/((((b4*t+b3)*t+b2)*t+b1)*t+1.0e0); if(*q > 0.5e0) s = -s; rta = sqrt(*a); s2 = s*s; xn = *a+s*rta+(s2-1.0e0)/3.0e0+s*(s2-7.0e0)/(36.0e0*rta)-((3.0e0*s2+7.0e0)* s2-16.0e0)/(810.0e0**a)+s*((9.0e0*s2+256.0e0)*s2-433.0e0)/(38880.0e0**a* rta); xn = fifdmax1(xn,0.0e0); if(*a < amin[iop-1]) goto S110; *x = xn; d = 0.5e0+(0.5e0-*x/ *a); if(fabs(d) <= dmin[iop-1]) return; S110: if(*p <= 0.5e0) goto S130; if(xn < 3.0e0**a) goto S220; y = -(w+gamln(a)); d = fifdmax1(2.0e0,*a*(*a-1.0e0)); if(y < ln10*d) goto S120; s = 1.0e0-*a; z = log(y); goto S30; S120: t = *a-1.0e0; T6 = -(t/(xn+1.0e0)); xn = y+t*log(xn)-alnrel(&T6); T7 = -(t/(xn+1.0e0)); xn = y+t*log(xn)-alnrel(&T7); goto S220; S130: ap1 = *a+1.0e0; if(xn > 0.70e0*ap1) goto S170; w += gamln(&ap1); if(xn > 0.15e0*ap1) goto S140; ap2 = *a+2.0e0; ap3 = *a+3.0e0; *x = exp((w+*x)/ *a); *x = exp((w+*x-log(1.0e0+*x/ap1*(1.0e0+*x/ap2)))/ *a); *x = exp((w+*x-log(1.0e0+*x/ap1*(1.0e0+*x/ap2)))/ *a); *x = exp((w+*x-log(1.0e0+*x/ap1*(1.0e0+*x/ap2*(1.0e0+*x/ap3))))/ *a); xn = *x; if(xn > 1.e-2*ap1) goto S140; if(xn <= emin[iop-1]*ap1) return; goto S170; S140: apn = ap1; t = xn/apn; sum = 1.0e0+t; S150: apn += 1.0e0; t *= (xn/apn); sum += t; if(t > 1.e-4) goto S150; t = w-log(sum); xn = exp((xn+t)/ *a); xn *= (1.0e0-(*a*log(xn)-xn-t)/(*a-xn)); goto S170; S160: /* SCHRODER ITERATION USING P */ if(*p > 0.5e0) goto S220; S170: if(*p <= 1.e10*xmin) goto S350; am1 = *a-0.5e0-0.5e0; S180: if(*a <= amax) goto S190; d = 0.5e0+(0.5e0-xn/ *a); if(fabs(d) <= e2) goto S350; S190: if(*ierr >= 20) goto S330; *ierr += 1; gratio(a,&xn,&pn,&qn,&K8); if(pn == 0.0e0 || qn == 0.0e0) goto S350; r = rcomp(a,&xn); if(r == 0.0e0) goto S350; t = (pn-*p)/r; w = 0.5e0*(am1-xn); if(fabs(t) <= 0.1e0 && fabs(w*t) <= 0.1e0) goto S200; *x = xn*(1.0e0-t); if(*x <= 0.0e0) goto S340; d = fabs(t); goto S210; S200: h = t*(1.0e0+w*t); *x = xn*(1.0e0-h); if(*x <= 0.0e0) goto S340; if(fabs(w) >= 1.0e0 && fabs(w)*t*t <= eps) return; d = fabs(h); S210: xn = *x; if(d > tol) goto S180; if(d <= eps) return; if(fabs(*p-pn) <= tol**p) return; goto S180; S220: /* SCHRODER ITERATION USING Q */ if(*q <= 1.e10*xmin) goto S350; am1 = *a-0.5e0-0.5e0; S230: if(*a <= amax) goto S240; d = 0.5e0+(0.5e0-xn/ *a); if(fabs(d) <= e2) goto S350; S240: if(*ierr >= 20) goto S330; *ierr += 1; gratio(a,&xn,&pn,&qn,&K8); if(pn == 0.0e0 || qn == 0.0e0) goto S350; r = rcomp(a,&xn); if(r == 0.0e0) goto S350; t = (*q-qn)/r; w = 0.5e0*(am1-xn); if(fabs(t) <= 0.1e0 && fabs(w*t) <= 0.1e0) goto S250; *x = xn*(1.0e0-t); if(*x <= 0.0e0) goto S340; d = fabs(t); goto S260; S250: h = t*(1.0e0+w*t); *x = xn*(1.0e0-h); if(*x <= 0.0e0) goto S340; if(fabs(w) >= 1.0e0 && fabs(w)*t*t <= eps) return; d = fabs(h); S260: xn = *x; if(d > tol) goto S230; if(d <= eps) return; if(fabs(*q-qn) <= tol**q) return; goto S230; S270: /* SPECIAL CASES */ *x = xmax; return; S280: if(*q < 0.9e0) goto S290; T9 = -*p; *x = -alnrel(&T9); return; S290: *x = -log(*q); return; S300: /* ERROR RETURN */ *ierr = -2; return; S310: *ierr = -3; return; S320: *ierr = -4; return; S330: *ierr = -6; return; S340: *ierr = -7; return; S350: *x = xn; *ierr = -8; return; S360: *x = xmax; *ierr = -8; } /* END */ /***=====================================================================***/ double gamln(double *a) /* ----------------------------------------------------------------------- EVALUATION OF LN(GAMMA(A)) FOR POSITIVE A ----------------------------------------------------------------------- WRITTEN BY ALFRED H. MORRIS NAVAL SURFACE WARFARE CENTER DAHLGREN, VIRGINIA -------------------------- D = 0.5*(LN(2*PI) - 1) -------------------------- */ { static double c0 = .833333333333333e-01; static double c1 = -.277777777760991e-02; static double c2 = .793650666825390e-03; static double c3 = -.595202931351870e-03; static double c4 = .837308034031215e-03; static double c5 = -.165322962780713e-02; static double d = .418938533204673e0; static double gamln,t,w; static int i,n; static double T1; /* .. .. Executable Statements .. */ if(*a > 0.8e0) goto S10; gamln = gamln1(a)-log(*a); return gamln; S10: if(*a > 2.25e0) goto S20; t = *a-0.5e0-0.5e0; gamln = gamln1(&t); return gamln; S20: if(*a >= 10.0e0) goto S40; n = *a-1.25e0; t = *a; w = 1.0e0; for(i=1; i<=n; i++) { t -= 1.0e0; w = t*w; } T1 = t-1.0e0; gamln = gamln1(&T1)+log(w); return gamln; S40: t = pow(1.0e0/ *a,2.0); w = (((((c5*t+c4)*t+c3)*t+c2)*t+c1)*t+c0)/ *a; gamln = d+w+(*a-0.5e0)*(log(*a)-1.0e0); return gamln; } /* END */ /***=====================================================================***/ double gamln1(const double *a) /* ----------------------------------------------------------------------- EVALUATION OF LN(GAMMA(1 + A)) FOR -0.2 .LE. A .LE. 1.25 ----------------------------------------------------------------------- */ { static double p0 = .577215664901533e+00; static double p1 = .844203922187225e+00; static double p2 = -.168860593646662e+00; static double p3 = -.780427615533591e+00; static double p4 = -.402055799310489e+00; static double p5 = -.673562214325671e-01; static double p6 = -.271935708322958e-02; static double q1 = .288743195473681e+01; static double q2 = .312755088914843e+01; static double q3 = .156875193295039e+01; static double q4 = .361951990101499e+00; static double q5 = .325038868253937e-01; static double q6 = .667465618796164e-03; static double r0 = .422784335098467e+00; static double r1 = .848044614534529e+00; static double r2 = .565221050691933e+00; static double r3 = .156513060486551e+00; static double r4 = .170502484022650e-01; static double r5 = .497958207639485e-03; static double s1 = .124313399877507e+01; static double s2 = .548042109832463e+00; static double s3 = .101552187439830e+00; static double s4 = .713309612391000e-02; static double s5 = .116165475989616e-03; static double gamln1,w,x; /* .. .. Executable Statements .. */ if(*a >= 0.6e0) goto S10; w = ((((((p6**a+p5)**a+p4)**a+p3)**a+p2)**a+p1)**a+p0)/((((((q6**a+q5)**a+ q4)**a+q3)**a+q2)**a+q1)**a+1.0e0); gamln1 = -(*a*w); return gamln1; S10: x = *a-0.5e0-0.5e0; w = (((((r5*x+r4)*x+r3)*x+r2)*x+r1)*x+r0)/(((((s5*x+s4)*x+s3)*x+s2)*x+s1)*x +1.0e0); gamln1 = x*w; return gamln1; } /* END */ /***=====================================================================***/ double Xgamm(const double *a) /* ----------------------------------------------------------------------- EVALUATION OF THE GAMMA FUNCTION FOR REAL ARGUMENTS ----------- GAMMA(A) IS ASSIGNED THE VALUE 0 WHEN THE GAMMA FUNCTION CANNOT BE COMPUTED. ----------------------------------------------------------------------- WRITTEN BY ALFRED H. MORRIS, JR. NAVAL SURFACE WEAPONS CENTER DAHLGREN, VIRGINIA ----------------------------------------------------------------------- */ { static double d = .41893853320467274178e0; static double pi = 3.1415926535898e0; static double r1 = .820756370353826e-03; static double r2 = -.595156336428591e-03; static double r3 = .793650663183693e-03; static double r4 = -.277777777770481e-02; static double r5 = .833333333333333e-01; static double p[7] = { .539637273585445e-03,.261939260042690e-02,.204493667594920e-01, .730981088720487e-01,.279648642639792e+00,.553413866010467e+00,1.0e0 }; static double q[7] = { -.832979206704073e-03,.470059485860584e-02,.225211131035340e-01, -.170458969313360e+00,-.567902761974940e-01,.113062953091122e+01,1.0e0 }; static int K2 = 3; static int K3 = 0; static double Xgamm,bot,g,lnx,s,t,top,w,x,z; static int i,j,m,n,T1; /* .. .. Executable Statements .. */ Xgamm = 0.0e0; x = *a; if(fabs(*a) >= 15.0e0) goto S110; /* ----------------------------------------------------------------------- EVALUATION OF GAMMA(A) FOR ABS(A) .LT. 15 ----------------------------------------------------------------------- */ t = 1.0e0; m = fifidint(*a)-1; /* LET T BE THE PRODUCT OF A-J WHEN A .GE. 2 */ T1 = m; if(T1 < 0) goto S40; else if(T1 == 0) goto S30; else goto S10; S10: for(j=1; j<=m; j++) { x -= 1.0e0; t = x*t; } S30: x -= 1.0e0; goto S80; S40: /* LET T BE THE PRODUCT OF A+J WHEN A .LT. 1 */ t = *a; if(*a > 0.0e0) goto S70; m = -m-1; if(m == 0) goto S60; for(j=1; j<=m; j++) { x += 1.0e0; t = x*t; } S60: x += (0.5e0+0.5e0); t = x*t; if(t == 0.0e0) return Xgamm; S70: /* THE FOLLOWING CODE CHECKS IF 1/T CAN OVERFLOW. THIS CODE MAY BE OMITTED IF DESIRED. */ if(fabs(t) >= 1.e-30) goto S80; if(fabs(t)*spmpar(&K2) <= 1.0001e0) return Xgamm; Xgamm = 1.0e0/t; return Xgamm; S80: /* COMPUTE GAMMA(1 + X) FOR 0 .LE. X .LT. 1 */ top = p[0]; bot = q[0]; for(i=1; i<7; i++) { top = p[i]+x*top; bot = q[i]+x*bot; } Xgamm = top/bot; /* TERMINATION */ if(*a < 1.0e0) goto S100; Xgamm *= t; return Xgamm; S100: Xgamm /= t; return Xgamm; S110: /* ----------------------------------------------------------------------- EVALUATION OF GAMMA(A) FOR ABS(A) .GE. 15 ----------------------------------------------------------------------- */ if(fabs(*a) >= 1.e3) return Xgamm; if(*a > 0.0e0) goto S120; x = -*a; n = x; t = x-(double)n; if(t > 0.9e0) t = 1.0e0-t; s = sin(pi*t)/pi; if(fifmod(n,2) == 0) s = -s; if(s == 0.0e0) return Xgamm; S120: /* COMPUTE THE MODIFIED ASYMPTOTIC SUM */ t = 1.0e0/(x*x); g = ((((r1*t+r2)*t+r3)*t+r4)*t+r5)/x; /* ONE MAY REPLACE THE NEXT STATEMENT WITH LNX = ALOG(X) BUT LESS ACCURACY WILL NORMALLY BE OBTAINED. */ lnx = log(x); /* FINAL ASSEMBLY */ z = x; g = d+g+(z-0.5e0)*(lnx-1.e0); w = g; t = g-w; if(w > 0.99999e0*exparg(&K3)) return Xgamm; Xgamm = exp(w)*(1.0e0+t); if(*a < 0.0e0) Xgamm = 1.0e0/(Xgamm*s)/x; return Xgamm; } /* END */ /***=====================================================================***/ void grat1(double *a,const double *x,const double *r,double *p,double *q, const double *eps) { static int K2 = 0; static double a2n,a2nm1,am0,an,an0,b2n,b2nm1,c,cma,g,h,j,l,sum,t,tol,w,z,T1,T3; /* .. .. Executable Statements .. */ /* ----------------------------------------------------------------------- EVALUATION OF THE INCOMPLETE GAMMA RATIO FUNCTIONS P(A,X) AND Q(A,X) IT IS ASSUMED THAT A .LE. 1. EPS IS THE TOLERANCE TO BE USED. THE INPUT ARGUMENT R HAS THE VALUE E**(-X)*X**A/GAMMA(A). ----------------------------------------------------------------------- */ if(*a**x == 0.0e0) goto S120; if(*a == 0.5e0) goto S100; if(*x < 1.1e0) goto S10; goto S60; S10: /* TAYLOR SERIES FOR P(A,X)/X**A */ an = 3.0e0; c = *x; sum = *x/(*a+3.0e0); tol = 0.1e0**eps/(*a+1.0e0); S20: an += 1.0e0; c = -(c*(*x/an)); t = c/(*a+an); sum += t; if(fabs(t) > tol) goto S20; j = *a**x*((sum/6.0e0-0.5e0/(*a+2.0e0))**x+1.0e0/(*a+1.0e0)); z = *a*log(*x); h = gam1(a); g = 1.0e0+h; if(*x < 0.25e0) goto S30; if(*a < *x/2.59e0) goto S50; goto S40; S30: if(z > -.13394e0) goto S50; S40: w = exp(z); *p = w*g*(0.5e0+(0.5e0-j)); *q = 0.5e0+(0.5e0-*p); return; S50: l = rexp(&z); w = 0.5e0+(0.5e0+l); *q = (w*j-l)*g-h; if(*q < 0.0e0) goto S90; *p = 0.5e0+(0.5e0-*q); return; S60: /* CONTINUED FRACTION EXPANSION */ a2nm1 = a2n = 1.0e0; b2nm1 = *x; b2n = *x+(1.0e0-*a); c = 1.0e0; S70: a2nm1 = *x*a2n+c*a2nm1; b2nm1 = *x*b2n+c*b2nm1; am0 = a2nm1/b2nm1; c += 1.0e0; cma = c-*a; a2n = a2nm1+cma*a2n; b2n = b2nm1+cma*b2n; an0 = a2n/b2n; if(fabs(an0-am0) >= *eps*an0) goto S70; *q = *r*an0; *p = 0.5e0+(0.5e0-*q); return; S80: /* SPECIAL CASES */ *p = 0.0e0; *q = 1.0e0; return; S90: *p = 1.0e0; *q = 0.0e0; return; S100: if(*x >= 0.25e0) goto S110; T1 = sqrt(*x); *p = erf1(&T1); *q = 0.5e0+(0.5e0-*p); return; S110: T3 = sqrt(*x); *q = erfc1(&K2,&T3); *p = 0.5e0+(0.5e0-*q); return; S120: if(*x <= *a) goto S80; goto S90; } /* END */ /***=====================================================================***/ void gratio(double *a,const double *x,double *ans,double *qans,const int *ind) /* ---------------------------------------------------------------------- EVALUATION OF THE INCOMPLETE GAMMA RATIO FUNCTIONS P(A,X) AND Q(A,X) ---------- IT IS ASSUMED THAT A AND X ARE NONNEGATIVE, WHERE A AND X ARE NOT BOTH 0. ANS AND QANS ARE VARIABLES. GRATIO ASSIGNS ANS THE VALUE P(A,X) AND QANS THE VALUE Q(A,X). IND MAY BE ANY INTEGER. IF IND = 0 THEN THE USER IS REQUESTING AS MUCH ACCURACY AS POSSIBLE (UP TO 14 SIGNIFICANT DIGITS). OTHERWISE, IF IND = 1 THEN ACCURACY IS REQUESTED TO WITHIN 1 UNIT OF THE 6-TH SIGNIFICANT DIGIT, AND IF IND .NE. 0,1 THEN ACCURACY IS REQUESTED TO WITHIN 1 UNIT OF THE 3RD SIGNIFICANT DIGIT. ERROR RETURN ... ANS IS ASSIGNED THE VALUE 2 WHEN A OR X IS NEGATIVE, WHEN A*X = 0, OR WHEN P(A,X) AND Q(A,X) ARE INDETERMINANT. P(A,X) AND Q(A,X) ARE COMPUTATIONALLY INDETERMINANT WHEN X IS EXCEEDINGLY CLOSE TO A AND A IS EXTREMELY LARGE. ---------------------------------------------------------------------- WRITTEN BY ALFRED H. MORRIS, JR. NAVAL SURFACE WEAPONS CENTER DAHLGREN, VIRGINIA -------------------- */ { static double alog10 = 2.30258509299405e0; static double d10 = -.185185185185185e-02; static double d20 = .413359788359788e-02; static double d30 = .649434156378601e-03; static double d40 = -.861888290916712e-03; static double d50 = -.336798553366358e-03; static double d60 = .531307936463992e-03; static double d70 = .344367606892378e-03; static double rt2pin = .398942280401433e0; static double rtpi = 1.77245385090552e0; static double third = .333333333333333e0; static double acc0[3] = { 5.e-15,5.e-7,5.e-4 }; static double big[3] = { 20.0e0,14.0e0,10.0e0 }; static double d0[13] = { .833333333333333e-01,-.148148148148148e-01,.115740740740741e-02, .352733686067019e-03,-.178755144032922e-03,.391926317852244e-04, -.218544851067999e-05,-.185406221071516e-05,.829671134095309e-06, -.176659527368261e-06,.670785354340150e-08,.102618097842403e-07, -.438203601845335e-08 }; static double d1[12] = { -.347222222222222e-02,.264550264550265e-02,-.990226337448560e-03, .205761316872428e-03,-.401877572016461e-06,-.180985503344900e-04, .764916091608111e-05,-.161209008945634e-05,.464712780280743e-08, .137863344691572e-06,-.575254560351770e-07,.119516285997781e-07 }; static double d2[10] = { -.268132716049383e-02,.771604938271605e-03,.200938786008230e-05, -.107366532263652e-03,.529234488291201e-04,-.127606351886187e-04, .342357873409614e-07,.137219573090629e-05,-.629899213838006e-06, .142806142060642e-06 }; static double d3[8] = { .229472093621399e-03,-.469189494395256e-03,.267720632062839e-03, -.756180167188398e-04,-.239650511386730e-06,.110826541153473e-04, -.567495282699160e-05,.142309007324359e-05 }; static double d4[6] = { .784039221720067e-03,-.299072480303190e-03,-.146384525788434e-05, .664149821546512e-04,-.396836504717943e-04,.113757269706784e-04 }; static double d5[4] = { -.697281375836586e-04,.277275324495939e-03,-.199325705161888e-03, .679778047793721e-04 }; static double d6[2] = { -.592166437353694e-03,.270878209671804e-03 }; static double e00[3] = { .25e-3,.25e-1,.14e0 }; static double x00[3] = { 31.0e0,17.0e0,9.7e0 }; static int K1 = 1; static int K2 = 0; static double a2n,a2nm1,acc,am0,amn,an,an0,apn,b2n,b2nm1,c,c0,c1,c2,c3,c4,c5,c6, cma,e,e0,g,h,j,l,r,rta,rtx,s,sum,t,t1,tol,twoa,u,w,x0,y,z; static int i,iop,m,max,n; static double wk[20],T3; static int T4,T5; static double T6,T7; /* .. .. Executable Statements .. */ /* -------------------- ****** E IS A MACHINE DEPENDENT CONSTANT. E IS THE SMALLEST FLOATING POINT NUMBER FOR WHICH 1.0 + E .GT. 1.0 . */ e = spmpar(&K1); if(*a < 0.0e0 || *x < 0.0e0) goto S430; if(*a == 0.0e0 && *x == 0.0e0) goto S430; if(*a**x == 0.0e0) goto S420; iop = *ind+1; if(iop != 1 && iop != 2) iop = 3; acc = fifdmax1(acc0[iop-1],e); e0 = e00[iop-1]; x0 = x00[iop-1]; /* SELECT THE APPROPRIATE ALGORITHM */ if(*a >= 1.0e0) goto S10; if(*a == 0.5e0) goto S390; if(*x < 1.1e0) goto S160; t1 = *a*log(*x)-*x; u = *a*exp(t1); if(u == 0.0e0) goto S380; r = u*(1.0e0+gam1(a)); goto S250; S10: if(*a >= big[iop-1]) goto S30; if(*a > *x || *x >= x0) goto S20; twoa = *a+*a; m = fifidint(twoa); if(twoa != (double)m) goto S20; i = m/2; if(*a == (double)i) goto S210; goto S220; S20: t1 = *a*log(*x)-*x; r = exp(t1)/Xgamm(a); goto S40; S30: l = *x/ *a; if(l == 0.0e0) goto S370; s = 0.5e0+(0.5e0-l); z = rlog(&l); if(z >= 700.0e0/ *a) goto S410; y = *a*z; rta = sqrt(*a); if(fabs(s) <= e0/rta) goto S330; if(fabs(s) <= 0.4e0) goto S270; t = pow(1.0e0/ *a,2.0); t1 = (((0.75e0*t-1.0e0)*t+3.5e0)*t-105.0e0)/(*a*1260.0e0); t1 -= y; r = rt2pin*rta*exp(t1); S40: if(r == 0.0e0) goto S420; if(*x <= fifdmax1(*a,alog10)) goto S50; if(*x < x0) goto S250; goto S100; S50: /* TAYLOR SERIES FOR P/R */ apn = *a+1.0e0; t = *x/apn; wk[0] = t; for(n=2; n<=20; n++) { apn += 1.0e0; t *= (*x/apn); if(t <= 1.e-3) goto S70; wk[n-1] = t; } n = 20; S70: sum = t; tol = 0.5e0*acc; S80: apn += 1.0e0; t *= (*x/apn); sum += t; if(t > tol) goto S80; max = n-1; for(m=1; m<=max; m++) { n -= 1; sum += wk[n-1]; } *ans = r/ *a*(1.0e0+sum); *qans = 0.5e0+(0.5e0-*ans); return; S100: /* ASYMPTOTIC EXPANSION */ amn = *a-1.0e0; t = amn/ *x; wk[0] = t; for(n=2; n<=20; n++) { amn -= 1.0e0; t *= (amn/ *x); if(fabs(t) <= 1.e-3) goto S120; wk[n-1] = t; } n = 20; S120: sum = t; S130: if(fabs(t) <= acc) goto S140; amn -= 1.0e0; t *= (amn/ *x); sum += t; goto S130; S140: max = n-1; for(m=1; m<=max; m++) { n -= 1; sum += wk[n-1]; } *qans = r/ *x*(1.0e0+sum); *ans = 0.5e0+(0.5e0-*qans); return; S160: /* TAYLOR SERIES FOR P(A,X)/X**A */ an = 3.0e0; c = *x; sum = *x/(*a+3.0e0); tol = 3.0e0*acc/(*a+1.0e0); S170: an += 1.0e0; c = -(c*(*x/an)); t = c/(*a+an); sum += t; if(fabs(t) > tol) goto S170; j = *a**x*((sum/6.0e0-0.5e0/(*a+2.0e0))**x+1.0e0/(*a+1.0e0)); z = *a*log(*x); h = gam1(a); g = 1.0e0+h; if(*x < 0.25e0) goto S180; if(*a < *x/2.59e0) goto S200; goto S190; S180: if(z > -.13394e0) goto S200; S190: w = exp(z); *ans = w*g*(0.5e0+(0.5e0-j)); *qans = 0.5e0+(0.5e0-*ans); return; S200: l = rexp(&z); w = 0.5e0+(0.5e0+l); *qans = (w*j-l)*g-h; if(*qans < 0.0e0) goto S380; *ans = 0.5e0+(0.5e0-*qans); return; S210: /* FINITE SUMS FOR Q WHEN A .GE. 1 AND 2*A IS AN INTEGER */ sum = exp(-*x); t = sum; n = 1; c = 0.0e0; goto S230; S220: rtx = sqrt(*x); sum = erfc1(&K2,&rtx); t = exp(-*x)/(rtpi*rtx); n = 0; c = -0.5e0; S230: if(n == i) goto S240; n += 1; c += 1.0e0; t = *x*t/c; sum += t; goto S230; S240: *qans = sum; *ans = 0.5e0+(0.5e0-*qans); return; S250: /* CONTINUED FRACTION EXPANSION */ tol = fifdmax1(5.0e0*e,acc); a2nm1 = a2n = 1.0e0; b2nm1 = *x; b2n = *x+(1.0e0-*a); c = 1.0e0; S260: a2nm1 = *x*a2n+c*a2nm1; b2nm1 = *x*b2n+c*b2nm1; am0 = a2nm1/b2nm1; c += 1.0e0; cma = c-*a; a2n = a2nm1+cma*a2n; b2n = b2nm1+cma*b2n; an0 = a2n/b2n; if(fabs(an0-am0) >= tol*an0) goto S260; *qans = r*an0; *ans = 0.5e0+(0.5e0-*qans); return; S270: /* GENERAL TEMME EXPANSION */ if(fabs(s) <= 2.0e0*e && *a*e*e > 3.28e-3) goto S430; c = exp(-y); T3 = sqrt(y); w = 0.5e0*erfc1(&K1,&T3); u = 1.0e0/ *a; z = sqrt(z+z); if(l < 1.0e0) z = -z; T4 = iop-2; if(T4 < 0) goto S280; else if(T4 == 0) goto S290; else goto S300; S280: if(fabs(s) <= 1.e-3) goto S340; c0 = ((((((((((((d0[12]*z+d0[11])*z+d0[10])*z+d0[9])*z+d0[8])*z+d0[7])*z+d0[ 6])*z+d0[5])*z+d0[4])*z+d0[3])*z+d0[2])*z+d0[1])*z+d0[0])*z-third; c1 = (((((((((((d1[11]*z+d1[10])*z+d1[9])*z+d1[8])*z+d1[7])*z+d1[6])*z+d1[5] )*z+d1[4])*z+d1[3])*z+d1[2])*z+d1[1])*z+d1[0])*z+d10; c2 = (((((((((d2[9]*z+d2[8])*z+d2[7])*z+d2[6])*z+d2[5])*z+d2[4])*z+d2[3])*z+ d2[2])*z+d2[1])*z+d2[0])*z+d20; c3 = (((((((d3[7]*z+d3[6])*z+d3[5])*z+d3[4])*z+d3[3])*z+d3[2])*z+d3[1])*z+ d3[0])*z+d30; c4 = (((((d4[5]*z+d4[4])*z+d4[3])*z+d4[2])*z+d4[1])*z+d4[0])*z+d40; c5 = (((d5[3]*z+d5[2])*z+d5[1])*z+d5[0])*z+d50; c6 = (d6[1]*z+d6[0])*z+d60; t = ((((((d70*u+c6)*u+c5)*u+c4)*u+c3)*u+c2)*u+c1)*u+c0; goto S310; S290: c0 = (((((d0[5]*z+d0[4])*z+d0[3])*z+d0[2])*z+d0[1])*z+d0[0])*z-third; c1 = (((d1[3]*z+d1[2])*z+d1[1])*z+d1[0])*z+d10; c2 = d2[0]*z+d20; t = (c2*u+c1)*u+c0; goto S310; S300: t = ((d0[2]*z+d0[1])*z+d0[0])*z-third; S310: if(l < 1.0e0) goto S320; *qans = c*(w+rt2pin*t/rta); *ans = 0.5e0+(0.5e0-*qans); return; S320: *ans = c*(w-rt2pin*t/rta); *qans = 0.5e0+(0.5e0-*ans); return; S330: /* TEMME EXPANSION FOR L = 1 */ if(*a*e*e > 3.28e-3) goto S430; c = 0.5e0+(0.5e0-y); w = (0.5e0-sqrt(y)*(0.5e0+(0.5e0-y/3.0e0))/rtpi)/c; u = 1.0e0/ *a; z = sqrt(z+z); if(l < 1.0e0) z = -z; T5 = iop-2; if(T5 < 0) goto S340; else if(T5 == 0) goto S350; else goto S360; S340: c0 = ((((((d0[6]*z+d0[5])*z+d0[4])*z+d0[3])*z+d0[2])*z+d0[1])*z+d0[0])*z- third; c1 = (((((d1[5]*z+d1[4])*z+d1[3])*z+d1[2])*z+d1[1])*z+d1[0])*z+d10; c2 = ((((d2[4]*z+d2[3])*z+d2[2])*z+d2[1])*z+d2[0])*z+d20; c3 = (((d3[3]*z+d3[2])*z+d3[1])*z+d3[0])*z+d30; c4 = (d4[1]*z+d4[0])*z+d40; c5 = (d5[1]*z+d5[0])*z+d50; c6 = d6[0]*z+d60; t = ((((((d70*u+c6)*u+c5)*u+c4)*u+c3)*u+c2)*u+c1)*u+c0; goto S310; S350: c0 = (d0[1]*z+d0[0])*z-third; c1 = d1[0]*z+d10; t = (d20*u+c1)*u+c0; goto S310; S360: t = d0[0]*z-third; goto S310; S370: /* SPECIAL CASES */ *ans = 0.0e0; *qans = 1.0e0; return; S380: *ans = 1.0e0; *qans = 0.0e0; return; S390: if(*x >= 0.25e0) goto S400; T6 = sqrt(*x); *ans = erf1(&T6); *qans = 0.5e0+(0.5e0-*ans); return; S400: T7 = sqrt(*x); *qans = erfc1(&K2,&T7); *ans = 0.5e0+(0.5e0-*qans); return; S410: if(fabs(s) <= 2.0e0*e) goto S430; S420: if(*x <= *a) goto S370; goto S380; S430: /* ERROR RETURN */ *ans = 2.0e0; } /* END */ /***=====================================================================***/ double gsumln(const double *a,const double *b) /* ----------------------------------------------------------------------- EVALUATION OF THE FUNCTION LN(GAMMA(A + B)) FOR 1 .LE. A .LE. 2 AND 1 .LE. B .LE. 2 ----------------------------------------------------------------------- */ { static double gsumln,x,T1,T2; /* .. .. Executable Statements .. */ x = *a+*b-2.e0; if(x > 0.25e0) goto S10; T1 = 1.0e0+x; gsumln = gamln1(&T1); return gsumln; S10: if(x > 1.25e0) goto S20; gsumln = gamln1(&x)+alnrel(&x); return gsumln; S20: T2 = x-1.0e0; gsumln = gamln1(&T2)+log(x*(1.0e0+x)); return gsumln; } /* END */ /***=====================================================================***/ double psi(const double *xx) /* --------------------------------------------------------------------- EVALUATION OF THE DIGAMMA FUNCTION ----------- PSI(XX) IS ASSIGNED THE VALUE 0 WHEN THE DIGAMMA FUNCTION CANNOT BE COMPUTED. THE MAIN COMPUTATION INVOLVES EVALUATION OF RATIONAL CHEBYSHEV APPROXIMATIONS PUBLISHED IN MATH. COMP. 27, 123-127(1973) BY CODY, STRECOK AND THACHER. --------------------------------------------------------------------- PSI WAS WRITTEN AT ARGONNE NATIONAL LABORATORY FOR THE FUNPACK PACKAGE OF SPECIAL FUNCTION SUBROUTINES. PSI WAS MODIFIED BY A.H. MORRIS (NSWC). --------------------------------------------------------------------- */ { static double dx0 = 1.461632144968362341262659542325721325e0; static double piov4 = .785398163397448e0; static double p1[7] = { .895385022981970e-02,.477762828042627e+01,.142441585084029e+03, .118645200713425e+04,.363351846806499e+04,.413810161269013e+04, .130560269827897e+04 }; static double p2[4] = { -.212940445131011e+01,-.701677227766759e+01,-.448616543918019e+01, -.648157123766197e+00 }; static double q1[6] = { .448452573429826e+02,.520752771467162e+03,.221000799247830e+04, .364127349079381e+04,.190831076596300e+04,.691091682714533e-05 }; static double q2[4] = { .322703493791143e+02,.892920700481861e+02,.546117738103215e+02, .777788548522962e+01 }; static int K1 = 3; static int K2 = 1; static double psi,aug,den,sgn,upper,w,x,xmax1,xmx0,xsmall,z; static int i,m,n,nq; /* .. .. Executable Statements .. */ /* --------------------------------------------------------------------- MACHINE DEPENDENT CONSTANTS ... XMAX1 = THE SMALLEST POSITIVE FLOATING POINT CONSTANT WITH ENTIRELY INTEGER REPRESENTATION. ALSO USED AS NEGATIVE OF LOWER BOUND ON ACCEPTABLE NEGATIVE ARGUMENTS AND AS THE POSITIVE ARGUMENT BEYOND WHICH PSI MAY BE REPRESENTED AS ALOG(X). XSMALL = ABSOLUTE ARGUMENT BELOW WHICH PI*COTAN(PI*X) MAY BE REPRESENTED BY 1/X. --------------------------------------------------------------------- */ xmax1 = ipmpar(&K1); xmax1 = fifdmin1(xmax1,1.0e0/spmpar(&K2)); xsmall = 1.e-9; x = *xx; aug = 0.0e0; if(x >= 0.5e0) goto S50; /* --------------------------------------------------------------------- X .LT. 0.5, USE REFLECTION FORMULA PSI(1-X) = PSI(X) + PI * COTAN(PI*X) --------------------------------------------------------------------- */ if(fabs(x) > xsmall) goto S10; if(x == 0.0e0) goto S100; /* --------------------------------------------------------------------- 0 .LT. ABS(X) .LE. XSMALL. USE 1/X AS A SUBSTITUTE FOR PI*COTAN(PI*X) --------------------------------------------------------------------- */ aug = -(1.0e0/x); goto S40; S10: /* --------------------------------------------------------------------- REDUCTION OF ARGUMENT FOR COTAN --------------------------------------------------------------------- */ w = -x; sgn = piov4; if(w > 0.0e0) goto S20; w = -w; sgn = -sgn; S20: /* --------------------------------------------------------------------- MAKE AN ERROR EXIT IF X .LE. -XMAX1 --------------------------------------------------------------------- */ if(w >= xmax1) goto S100; nq = fifidint(w); w -= (double)nq; nq = fifidint(w*4.0e0); w = 4.0e0*(w-(double)nq*.25e0); /* --------------------------------------------------------------------- W IS NOW RELATED TO THE FRACTIONAL PART OF 4.0 * X. ADJUST ARGUMENT TO CORRESPOND TO VALUES IN FIRST QUADRANT AND DETERMINE SIGN --------------------------------------------------------------------- */ n = nq/2; if(n+n != nq) w = 1.0e0-w; z = piov4*w; m = n/2; if(m+m != n) sgn = -sgn; /* --------------------------------------------------------------------- DETERMINE FINAL VALUE FOR -PI*COTAN(PI*X) --------------------------------------------------------------------- */ n = (nq+1)/2; m = n/2; m += m; if(m != n) goto S30; /* --------------------------------------------------------------------- CHECK FOR SINGULARITY --------------------------------------------------------------------- */ if(z == 0.0e0) goto S100; /* --------------------------------------------------------------------- USE COS/SIN AS A SUBSTITUTE FOR COTAN, AND SIN/COS AS A SUBSTITUTE FOR TAN --------------------------------------------------------------------- */ aug = sgn*(cos(z)/sin(z)*4.0e0); goto S40; S30: aug = sgn*(sin(z)/cos(z)*4.0e0); S40: x = 1.0e0-x; S50: if(x > 3.0e0) goto S70; /* --------------------------------------------------------------------- 0.5 .LE. X .LE. 3.0 --------------------------------------------------------------------- */ den = x; upper = p1[0]*x; for(i=1; i<=5; i++) { den = (den+q1[i-1])*x; upper = (upper+p1[i+1-1])*x; } den = (upper+p1[6])/(den+q1[5]); xmx0 = x-dx0; psi = den*xmx0+aug; return psi; S70: /* --------------------------------------------------------------------- IF X .GE. XMAX1, PSI = LN(X) --------------------------------------------------------------------- */ if(x >= xmax1) goto S90; /* --------------------------------------------------------------------- 3.0 .LT. X .LT. XMAX1 --------------------------------------------------------------------- */ w = 1.0e0/(x*x); den = w; upper = p2[0]*w; for(i=1; i<=3; i++) { den = (den+q2[i-1])*w; upper = (upper+p2[i+1-1])*w; } aug = upper/(den+q2[3])-0.5e0/x+aug; S90: psi = aug+log(x); return psi; S100: /* --------------------------------------------------------------------- ERROR RETURN --------------------------------------------------------------------- */ psi = 0.0e0; return psi; } /* END */ /***=====================================================================***/ double rcomp(double *a,const double *x) /* ------------------- EVALUATION OF EXP(-X)*X**A/GAMMA(A) ------------------- RT2PIN = 1/SQRT(2*PI) ------------------- */ { static double rt2pin = .398942280401433e0; static double rcomp,t,t1,u; /* .. .. Executable Statements .. */ rcomp = 0.0e0; if(*a >= 20.0e0) goto S20; t = *a*log(*x)-*x; if(*a >= 1.0e0) goto S10; rcomp = *a*exp(t)*(1.0e0+gam1(a)); return rcomp; S10: rcomp = exp(t)/Xgamm(a); return rcomp; S20: u = *x/ *a; if(u == 0.0e0) return rcomp; t = pow(1.0e0/ *a,2.0); t1 = (((0.75e0*t-1.0e0)*t+3.5e0)*t-105.0e0)/(*a*1260.0e0); t1 -= (*a*rlog(&u)); rcomp = rt2pin*sqrt(*a)*exp(t1); return rcomp; } /* END */ /***=====================================================================***/ double rexp(const double *x) /* ----------------------------------------------------------------------- EVALUATION OF THE FUNCTION EXP(X) - 1 ----------------------------------------------------------------------- */ { static double p1 = .914041914819518e-09; static double p2 = .238082361044469e-01; static double q1 = -.499999999085958e+00; static double q2 = .107141568980644e+00; static double q3 = -.119041179760821e-01; static double q4 = .595130811860248e-03; static double rexp,w; /* .. .. Executable Statements .. */ if(fabs(*x) > 0.15e0) goto S10; rexp = *x*(((p2**x+p1)**x+1.0e0)/((((q4**x+q3)**x+q2)**x+q1)**x+1.0e0)); return rexp; S10: w = exp(*x); if(*x > 0.0e0) goto S20; rexp = w-0.5e0-0.5e0; return rexp; S20: rexp = w*(0.5e0+(0.5e0-1.0e0/w)); return rexp; } /* END */ /***=====================================================================***/ double rlog(const double *x) /* ------------------- COMPUTATION OF X - 1 - LN(X) ------------------- */ { static double a = .566749439387324e-01; static double b = .456512608815524e-01; static double p0 = .333333333333333e+00; static double p1 = -.224696413112536e+00; static double p2 = .620886815375787e-02; static double q1 = -.127408923933623e+01; static double q2 = .354508718369557e+00; static double rlog,r,t,u,w,w1; /* .. .. Executable Statements .. */ if(*x < 0.61e0 || *x > 1.57e0) goto S40; if(*x < 0.82e0) goto S10; if(*x > 1.18e0) goto S20; /* ARGUMENT REDUCTION */ u = *x-0.5e0-0.5e0; w1 = 0.0e0; goto S30; S10: u = *x-0.7e0; u /= 0.7e0; w1 = a-u*0.3e0; goto S30; S20: u = 0.75e0**x-1.e0; w1 = b+u/3.0e0; S30: /* SERIES EXPANSION */ r = u/(u+2.0e0); t = r*r; w = ((p2*t+p1)*t+p0)/((q2*t+q1)*t+1.0e0); rlog = 2.0e0*t*(1.0e0/(1.0e0-r)-r*w)+w1; return rlog; S40: r = *x-0.5e0-0.5e0; rlog = r-log(*x); return rlog; } /* END */ /***=====================================================================***/ double rlog1(const double *x) /* ----------------------------------------------------------------------- EVALUATION OF THE FUNCTION X - LN(1 + X) ----------------------------------------------------------------------- */ { static double a = .566749439387324e-01; static double b = .456512608815524e-01; static double p0 = .333333333333333e+00; static double p1 = -.224696413112536e+00; static double p2 = .620886815375787e-02; static double q1 = -.127408923933623e+01; static double q2 = .354508718369557e+00; static double rlog1,h,r,t,w,w1; /* .. .. Executable Statements .. */ if(*x < -0.39e0 || *x > 0.57e0) goto S40; if(*x < -0.18e0) goto S10; if(*x > 0.18e0) goto S20; /* ARGUMENT REDUCTION */ h = *x; w1 = 0.0e0; goto S30; S10: h = *x+0.3e0; h /= 0.7e0; w1 = a-h*0.3e0; goto S30; S20: h = 0.75e0**x-0.25e0; w1 = b+h/3.0e0; S30: /* SERIES EXPANSION */ r = h/(h+2.0e0); t = r*r; w = ((p2*t+p1)*t+p0)/((q2*t+q1)*t+1.0e0); rlog1 = 2.0e0*t*(1.0e0/(1.0e0-r)-r*w)+w1; return rlog1; S40: w = *x+0.5e0+0.5e0; rlog1 = *x-log(w); return rlog1; } /* END */ /***=====================================================================***/ double spmpar(const int *i) /* ----------------------------------------------------------------------- SPMPAR PROVIDES THE SINGLE PRECISION MACHINE CONSTANTS FOR THE COMPUTER BEING USED. IT IS ASSUMED THAT THE ARGUMENT I IS AN INTEGER HAVING ONE OF THE VALUES 1, 2, OR 3. IF THE SINGLE PRECISION ARITHMETIC BEING USED HAS M BASE B DIGITS AND ITS SMALLEST AND LARGEST EXPONENTS ARE EMIN AND EMAX, THEN SPMPAR(1) = B**(1 - M), THE MACHINE PRECISION, SPMPAR(2) = B**(EMIN - 1), THE SMALLEST MAGNITUDE, SPMPAR(3) = B**EMAX*(1 - B**(-M)), THE LARGEST MAGNITUDE. ----------------------------------------------------------------------- WRITTEN BY ALFRED H. MORRIS, JR. NAVAL SURFACE WARFARE CENTER DAHLGREN VIRGINIA ----------------------------------------------------------------------- ----------------------------------------------------------------------- MODIFIED BY BARRY W. BROWN TO RETURN DOUBLE PRECISION MACHINE CONSTANTS FOR THE COMPUTER BEING USED. THIS MODIFICATION WAS MADE AS PART OF CONVERTING BRATIO TO DOUBLE PRECISION ----------------------------------------------------------------------- */ { static int K1 = 4; static int K2 = 8; static int K3 = 9; static int K4 = 10; static double spmpar,b,binv,bm1,one,w,z; static int emax,emin,ibeta,m; /* .. .. Executable Statements .. */ if(*i > 1) goto S10; b = ipmpar(&K1); m = ipmpar(&K2); spmpar = pow(b,(double)(1-m)); return spmpar; S10: if(*i > 2) goto S20; b = ipmpar(&K1); emin = ipmpar(&K3); one = 1.0; binv = one/b; w = pow(b,(double)(emin+2)); spmpar = w*binv*binv*binv; return spmpar; S20: ibeta = ipmpar(&K1); m = ipmpar(&K2); emax = ipmpar(&K4); b = ibeta; bm1 = ibeta-1; one = 1.0; z = pow(b,(double)(m-1)); w = ((z-one)*b+bm1)/(b*z); z = pow(b,(double)(emax-2)); spmpar = w*z*b*b; return spmpar; } /* END */ /***=====================================================================***/ double stvaln(const double *p) /* ********************************************************************** double stvaln(double *p) STarting VALue for Neton-Raphon calculation of Normal distribution Inverse Function Returns X such that CUMNOR(X) = P, i.e., the integral from - infinity to X of (1/SQRT(2*PI)) EXP(-U*U/2) dU is P Arguments P --> The probability whose normal deviate is sought. P is DOUBLE PRECISION Method The rational function on page 95 of Kennedy and Gentle, Statistical Computing, Marcel Dekker, NY , 1980. ********************************************************************** */ { static double xden[5] = { 0.993484626060e-1,0.588581570495e0,0.531103462366e0,0.103537752850e0, 0.38560700634e-2 }; static double xnum[5] = { -0.322232431088e0,-1.000000000000e0,-0.342242088547e0,-0.204231210245e-1, -0.453642210148e-4 }; static int K1 = 5; static double stvaln,sign,y,z; /* .. .. Executable Statements .. */ if(!(*p <= 0.5e0)) goto S10; sign = -1.0e0; z = *p; goto S20; S10: sign = 1.0e0; z = 1.0e0-*p; S20: y = sqrt(-(2.0e0*log(z))); stvaln = y+devlpl(xnum,&K1,&y)/devlpl(xden,&K1,&y); stvaln = sign*stvaln; return stvaln; } /* END */ /***=====================================================================***/ double fifdint(double a) /************************************************************************ FIFDINT: Truncates a double precision number to an integer and returns the value in a double. ************************************************************************/ /* a - number to be truncated */ { return (double) ((int) a); } /* END */ /***=====================================================================***/ double fifdmax1(double a,double b) /************************************************************************ FIFDMAX1: returns the maximum of two numbers a and b ************************************************************************/ /* a - first number */ /* b - second number */ { if (a < b) return b; else return a; } /* END */ /***=====================================================================***/ double fifdmin1(double a,double b) /************************************************************************ FIFDMIN1: returns the minimum of two numbers a and b ************************************************************************/ /* a - first number */ /* b - second number */ { if (a < b) return a; else return b; } /* END */ /***=====================================================================***/ double fifdsign(double mag,double sign) /************************************************************************ FIFDSIGN: transfers the sign of the variable "sign" to the variable "mag" ************************************************************************/ /* mag - magnitude */ /* sign - sign to be transfered */ { if (mag < 0) mag = -mag; if (sign < 0) mag = -mag; return mag; } /* END */ /***=====================================================================***/ long fifidint(double a) /************************************************************************ FIFIDINT: Truncates a double precision number to a long integer ************************************************************************/ /* a - number to be truncated */ { if (a < 1.0) return (long) 0; else return (long) a; } /* END */ /***=====================================================================***/ long fifmod(long a,long b) /************************************************************************ FIFMOD: returns the modulo of a and b ************************************************************************/ /* a - numerator */ /* b - denominator */ { return a % b; } /* END */ /***=====================================================================***/ void ftnstop(const char* msg) /************************************************************************ FTNSTOP: Prints msg to standard error and then exits ************************************************************************/ /* msg - error message */ { if (msg != NULL) fprintf(stderr,"*** CDFLIB ERROR: %s\n",msg); /** exit(1); **/ /** RWCox - DON'T EXIT */ } /* END */ /***=====================================================================***/ int ipmpar(const int *i) /* ----------------------------------------------------------------------- IPMPAR PROVIDES THE INTEGER MACHINE CONSTANTS FOR THE COMPUTER THAT IS USED. IT IS ASSUMED THAT THE ARGUMENT I IS AN INTEGER HAVING ONE OF THE VALUES 1-10. IPMPAR(I) HAS THE VALUE ... INTEGERS. ASSUME INTEGERS ARE REPRESENTED IN THE N-DIGIT, BASE-A FORM SIGN ( X(N-1)*A**(N-1) + ... + X(1)*A + X(0) ) WHERE 0 .LE. X(I) .LT. A FOR I=0,...,N-1. IPMPAR(1) = A, THE BASE. IPMPAR(2) = N, THE NUMBER OF BASE-A DIGITS. IPMPAR(3) = A**N - 1, THE LARGEST MAGNITUDE. FLOATING-POINT NUMBERS. IT IS ASSUMED THAT THE SINGLE AND DOUBLE PRECISION FLOATING POINT ARITHMETICS HAVE THE SAME BASE, SAY B, AND THAT THE NONZERO NUMBERS ARE REPRESENTED IN THE FORM SIGN (B**E) * (X(1)/B + ... + X(M)/B**M) WHERE X(I) = 0,1,...,B-1 FOR I=1,...,M, X(1) .GE. 1, AND EMIN .LE. E .LE. EMAX. IPMPAR(4) = B, THE BASE. SINGLE-PRECISION IPMPAR(5) = M, THE NUMBER OF BASE-B DIGITS. IPMPAR(6) = EMIN, THE SMALLEST EXPONENT E. IPMPAR(7) = EMAX, THE LARGEST EXPONENT E. DOUBLE-PRECISION IPMPAR(8) = M, THE NUMBER OF BASE-B DIGITS. IPMPAR(9) = EMIN, THE SMALLEST EXPONENT E. IPMPAR(10) = EMAX, THE LARGEST EXPONENT E. ----------------------------------------------------------------------- TO DEFINE THIS FUNCTION FOR THE COMPUTER BEING USED REMOVE THE COMMENT DELIMITORS FROM THE DEFINITIONS DIRECTLY BELOW THE NAME OF THE MACHINE *** RWCox: at this time, the IEEE parameters are enabled. ----------------------------------------------------------------------- IPMPAR IS AN ADAPTATION OF THE FUNCTION I1MACH, WRITTEN BY P.A. FOX, A.D. HALL, AND N.L. SCHRYER (BELL LABORATORIES). IPMPAR WAS FORMED BY A.H. MORRIS (NSWC). THE CONSTANTS ARE FROM BELL LABORATORIES, NSWC, AND OTHER SOURCES. ----------------------------------------------------------------------- .. Scalar Arguments .. */ { static int imach[11]; static int outval ; /* MACHINE CONSTANTS FOR AMDAHL MACHINES. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 16; imach[5] = 6; imach[6] = -64; imach[7] = 63; imach[8] = 14; imach[9] = -64; imach[10] = 63; */ /* MACHINE CONSTANTS FOR THE AT&T 3B SERIES, AT&T PC 7300, AND AT&T 6300. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -125; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; */ /* MACHINE CONSTANTS FOR THE BURROUGHS 1700 SYSTEM. */ /* imach[1] = 2; imach[2] = 33; imach[3] = 8589934591; imach[4] = 2; imach[5] = 24; imach[6] = -256; imach[7] = 255; imach[8] = 60; imach[9] = -256; imach[10] = 255; */ /* MACHINE CONSTANTS FOR THE BURROUGHS 5700 SYSTEM. */ /* imach[1] = 2; imach[2] = 39; imach[3] = 549755813887; imach[4] = 8; imach[5] = 13; imach[6] = -50; imach[7] = 76; imach[8] = 26; imach[9] = -50; imach[10] = 76; */ /* MACHINE CONSTANTS FOR THE BURROUGHS 6700/7700 SYSTEMS. */ /* imach[1] = 2; imach[2] = 39; imach[3] = 549755813887; imach[4] = 8; imach[5] = 13; imach[6] = -50; imach[7] = 76; imach[8] = 26; imach[9] = -32754; imach[10] = 32780; */ /* MACHINE CONSTANTS FOR THE CDC 6000/7000 SERIES 60 BIT ARITHMETIC, AND THE CDC CYBER 995 64 BIT ARITHMETIC (NOS OPERATING SYSTEM). */ /* imach[1] = 2; imach[2] = 48; imach[3] = 281474976710655; imach[4] = 2; imach[5] = 48; imach[6] = -974; imach[7] = 1070; imach[8] = 95; imach[9] = -926; imach[10] = 1070; */ /* MACHINE CONSTANTS FOR THE CDC CYBER 995 64 BIT ARITHMETIC (NOS/VE OPERATING SYSTEM). */ /* imach[1] = 2; imach[2] = 63; imach[3] = 9223372036854775807; imach[4] = 2; imach[5] = 48; imach[6] = -4096; imach[7] = 4095; imach[8] = 96; imach[9] = -4096; imach[10] = 4095; */ /* MACHINE CONSTANTS FOR THE CRAY 1, XMP, 2, AND 3. */ /* imach[1] = 2; imach[2] = 63; imach[3] = 9223372036854775807; imach[4] = 2; imach[5] = 47; imach[6] = -8189; imach[7] = 8190; imach[8] = 94; imach[9] = -8099; imach[10] = 8190; */ /* MACHINE CONSTANTS FOR THE DATA GENERAL ECLIPSE S/200. */ /* imach[1] = 2; imach[2] = 15; imach[3] = 32767; imach[4] = 16; imach[5] = 6; imach[6] = -64; imach[7] = 63; imach[8] = 14; imach[9] = -64; imach[10] = 63; */ /* MACHINE CONSTANTS FOR THE HARRIS 220. */ /* imach[1] = 2; imach[2] = 23; imach[3] = 8388607; imach[4] = 2; imach[5] = 23; imach[6] = -127; imach[7] = 127; imach[8] = 38; imach[9] = -127; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE HONEYWELL 600/6000 AND DPS 8/70 SERIES. */ /* imach[1] = 2; imach[2] = 35; imach[3] = 34359738367; imach[4] = 2; imach[5] = 27; imach[6] = -127; imach[7] = 127; imach[8] = 63; imach[9] = -127; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE HP 2100 3 WORD DOUBLE PRECISION OPTION WITH FTN4 */ /* imach[1] = 2; imach[2] = 15; imach[3] = 32767; imach[4] = 2; imach[5] = 23; imach[6] = -128; imach[7] = 127; imach[8] = 39; imach[9] = -128; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE HP 2100 4 WORD DOUBLE PRECISION OPTION WITH FTN4 */ /* imach[1] = 2; imach[2] = 15; imach[3] = 32767; imach[4] = 2; imach[5] = 23; imach[6] = -128; imach[7] = 127; imach[8] = 55; imach[9] = -128; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE HP 9000. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -126; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; */ /* MACHINE CONSTANTS FOR THE IBM 360/370 SERIES, THE ICL 2900, THE ITEL AS/6, THE XEROX SIGMA 5/7/9 AND THE SEL SYSTEMS 85/86. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 16; imach[5] = 6; imach[6] = -64; imach[7] = 63; imach[8] = 14; imach[9] = -64; imach[10] = 63; */ /* MACHINE CONSTANTS FOR THE IBM PC. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -125; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; */ /* MACHINE CONSTANTS FOR THE MACINTOSH II - ABSOFT MACFORTRAN II. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -125; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; */ /* MACHINE CONSTANTS FOR THE MICROVAX - VMS FORTRAN. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -127; imach[7] = 127; imach[8] = 56; imach[9] = -127; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE PDP-10 (KA PROCESSOR). */ /* imach[1] = 2; imach[2] = 35; imach[3] = 34359738367; imach[4] = 2; imach[5] = 27; imach[6] = -128; imach[7] = 127; imach[8] = 54; imach[9] = -101; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE PDP-10 (KI PROCESSOR). */ /* imach[1] = 2; imach[2] = 35; imach[3] = 34359738367; imach[4] = 2; imach[5] = 27; imach[6] = -128; imach[7] = 127; imach[8] = 62; imach[9] = -128; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE PDP-11 FORTRAN SUPPORTING 32-BIT INTEGER ARITHMETIC. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -127; imach[7] = 127; imach[8] = 56; imach[9] = -127; imach[10] = 127; */ /* MACHINE CONSTANTS FOR THE SEQUENT BALANCE 8000. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -125; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; */ /* MACHINE CONSTANTS FOR THE SILICON GRAPHICS IRIS-4D SERIES (MIPS R3000 PROCESSOR). */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -125; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; */ /* MACHINE CONSTANTS FOR IEEE ARITHMETIC MACHINES, SUCH AS THE AT&T 3B SERIES, MOTOROLA 68000 BASED MACHINES (E.G. SUN 3 AND AT&T PC 7300), AND 8087 BASED MICROS (E.G. IBM PC AND AT&T 6300). */ imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -125; imach[7] = 128; imach[8] = 53; imach[9] = -1021; imach[10] = 1024; /* MACHINE CONSTANTS FOR THE UNIVAC 1100 SERIES. */ /* imach[1] = 2; imach[2] = 35; imach[3] = 34359738367; imach[4] = 2; imach[5] = 27; imach[6] = -128; imach[7] = 127; imach[8] = 60; imach[9] = -1024; imach[10] = 1023; */ /* MACHINE CONSTANTS FOR THE VAX 11/780. */ /* imach[1] = 2; imach[2] = 31; imach[3] = 2147483647; imach[4] = 2; imach[5] = 24; imach[6] = -127; imach[7] = 127; imach[8] = 56; imach[9] = -127; imach[10] = 127; */ outval = imach[*i]; return outval ; } /*************************************************************************/ /*************************************************************************/ /************************ End of cdflib inclusion ************************/ /*************************************************************************/ /*************************************************************************/ /*-----------------------------------------------------------------------*/ typedef struct { double p,q ; } pqpair ; /* for returning p=cdf q=1-cdf */ /*-----------------------------------------------------------------------*/ #undef BIGG #define BIGG 9.99e+37 /* a really big number (duh) */ /*-----------------------------------------------------------------------*/ /*************************************************************************/ /******** Internal functions for various statistical computations ********/ /*************************************************************************/ /*--------------------------------------------------------------- F statistic -----------------------------------------------------------------*/ static double fstat_pq2s( pqpair pq , double dofnum , double dofden ) { int which , status ; double p , q , f , dfn , dfd , bound ; which = 2 ; p = pq.p ; if( p <= 0.0 ) return 0.0 ; q = pq.q ; if( q <= 0.0 ) return BIGG ; f = 0.0 ; dfn = dofnum ; dfd = dofden ; cdff( &which , &p , &q , &f , &dfn , &dfd , &status , &bound ) ; return f ; } /*------------------------------*/ static pqpair fstat_s2pq( double ff , double dofnum , double dofden ) { int which , status ; double p , q , f , dfn , dfd , bound ; pqpair pq={0.0,1.0} ; which = 1 ; p = 0.0 ; q = 1.0 ; f = ff ; if( f <= 0.0 ) return pq; dfn = dofnum ; if( dfn <= 0.0 ) return pq ; dfd = dofden ; if( dfd <= 0.0 ) return pq ; cdff( &which , &p , &q , &f , &dfn , &dfd , &status , &bound ) ; pq.p = p ; pq.q = q ; return pq ; } /*--------------------------------------------------------------- noncentral F statistic -----------------------------------------------------------------*/ static double fnonc_pq2s( pqpair pq , double dofnum , double dofden , double nonc ) { int which , status ; double p , q , f , dfn , dfd , bound , pnonc ; which = 2 ; p = pq.p ; if( p <= 0.0 ) return 0.0 ; q = pq.q ; if( q <= 0.0 ) return BIGG ; f = 0.0 ; dfn = dofnum ; dfd = dofden ; pnonc = nonc ; cdffnc( &which , &p , &q , &f , &dfn , &dfd , &pnonc , &status , &bound ) ; return f ; } /*------------------------------*/ static pqpair fnonc_s2pq( double ff , double dofnum , double dofden , double nonc ) { int which , status ; double p , q , f , dfn , dfd , bound , pnonc ; pqpair pq={0.0,1.0} ; which = 1 ; p = 0.0 ; q = 1.0 ; f = ff ; if( f <= 0.0 ) return pq ; dfn = dofnum ; if( dfn <= 0.0 ) return pq ; dfd = dofden ; if( dfd <= 0.0 ) return pq ; pnonc = nonc ; if( pnonc < 0.0 ) return pq ; cdffnc( &which , &p , &q , &f , &dfn , &dfd , &pnonc , &status , &bound ) ; pq.p = p ; pq.q = q ; return pq ; } /*--------------------------------------------------------------- Standard Normal distribution -----------------------------------------------------------------*/ static pqpair normal_s2pq( double zz ) { double p , q , x=zz ; pqpair pq ; cumnor( &x, &p, &q ) ; pq.p = p ; pq.q = q ; return pq ; } /*------------------------------*/ static double normal_pq2s( pqpair pq ) { double p=pq.p , q=pq.q ; if( p <= 0.0 ) return -BIGG ; if( q <= 0.0 ) return BIGG ; return dinvnr( &p,&q ) ; } /*---------------------------------------------------------------- Chi-square ------------------------------------------------------------------*/ static pqpair chisq_s2pq( double xx , double dof ) { int which , status ; double p,q,x,df,bound ; pqpair pq={0.0,1.0} ; which = 1 ; p = 0.0 ; q = 1.0 ; x = xx ; if( x <= 0.0 ) return pq ; df = dof ; if( dof <= 0.0 ) return pq ; cdfchi( &which , &p , &q , &x , &df , &status , &bound ) ; pq.p = p ; pq.q = q ; return pq ; } /*------------------------------*/ static double chisq_pq2s( pqpair pq , double dof ) { int which , status ; double p,q,x,df,bound ; which = 2 ; p = pq.p ; if( p <= 0.0 ) return 0.0 ; q = pq.q ; if( q <= 0.0 ) return BIGG ; x = 0.0 ; df = dof ; cdfchi( &which , &p , &q , &x , &df , &status , &bound ) ; return x ; } /*---------------------------------------------------------------- noncentral Chi-square ------------------------------------------------------------------*/ static pqpair chsqnonc_s2pq( double xx , double dof , double nonc ) { int which , status ; double p,q,x,df,bound , pnonc ; pqpair pq={0.0,1.0} ; which = 1 ; p = 0.0 ; q = 1.0 ; x = xx ; if( x <= 0.0 ) return pq ; df = dof ; if( df <= 0.0 ) return pq ; pnonc = nonc ; if( pnonc < 0.0 ) return pq ; cdfchn( &which , &p , &q , &x , &df , &pnonc , &status , &bound ) ; pq.p = p ; pq.q = q ; return pq ; } /*------------------------------*/ static double chsqnonc_pq2s( pqpair pq , double dof , double nonc ) { int which , status ; double p,q,x,df,bound , pnonc ; which = 2 ; p = pq.p ; if( p <= 0.0 ) return 0.0 ; q = pq.q ; if( q <= 0.0 ) return BIGG ; x = 0.0 ; df = dof ; pnonc = nonc ; cdfchn( &which , &p , &q , &x , &df , &pnonc , &status , &bound ) ; return x ; } /*---------------------------------------------------------------- Beta distribution ------------------------------------------------------------------*/ static pqpair beta_s2pq( double xx , double aa , double bb ) { int which , status ; double p,q,x,y,a,b,bound ; pqpair pq={0.0,1.0} ; which = 1 ; p = 0.0 ; q = 1.0 ; x = xx ; if( x <= 0.0 ) return pq ; y = 1.0 - xx ; if( y <= 0.0 ){ pq.p=1.0; pq.q=0.0; return pq; } a = aa ; if( a < 0.0 ) return pq ; b = bb ; if( b < 0.0 ) return pq ; cdfbet( &which , &p , &q , &x , &y , &a , &b , &status , &bound ) ; pq.p = p ; pq.q = q ; return pq ; } /*------------------------------*/ static double beta_pq2s( pqpair pq , double aa , double bb ) { int which , status ; double p,q,x,y,a,b,bound ; which = 2 ; p = pq.p ; if( p <= 0.0 ) return 0.0 ; q = pq.q ; if( q <= 0.0 ) return 1.0 ; x = 0.0 ; y = 1.0 ; a = aa ; b = bb ; cdfbet( &which , &p , &q , &x , &y , &a , &b , &status , &bound ) ; return x ; } /*---------------------------------------------------------------- Binomial distribution (that is, the probability that more than ss out of ntrial trials were successful). ------------------------------------------------------------------*/ static pqpair binomial_s2pq( double ss , double ntrial , double ptrial ) { int which , status ; double p,q, s,xn,pr,ompr,bound ; pqpair pq={0.0,1.0} ; which = 1 ; p = 0.0 ; q = 1.0 ; s = ss ; if( s < 0.0 ) return pq ; xn = ntrial ; if( xn <= 0.0 ) return pq ; pr = ptrial ; if( pr < 0.0 ) return pq ; ompr = 1.0 - ptrial ; cdfbin( &which , &p , &q , &s , &xn , &pr , &ompr , &status , &bound ) ; pq.p = p ; pq.q = q ; return pq ; } /*------------------------------*/ static double binomial_pq2s( pqpair pq , double ntrial , double ptrial ) { int which , status ; double p,q, s,xn,pr,ompr,bound ; which = 2 ; p = pq.p ; q = pq.q ; s = 0.0 ; xn = ntrial ; pr = ptrial ; ompr = 1.0 - ptrial ; cdfbin( &which , &p , &q , &s , &xn , &pr , &ompr , &status , &bound ) ; return s ; } /*---------------------------------------------------------------- Gamma distribution. ------------------------------------------------------------------*/ static pqpair gamma_s2pq( double xx , double sh , double sc ) { int which , status ; double p,q, x,shape,scale,bound ; pqpair pq={0.0,1.0} ; which = 1 ; p = 0.0 ; q = 1.0 ; x = xx ; if( x <= 0.0 ) return pq ; shape = sh ; if( shape <= 0.0 ) return pq ; scale = sc ; if( scale <= 0.0 ) return pq ; cdfgam( &which , &p , &q , &x , &shape , &scale , &status , &bound ) ; pq.p = p ; pq.q = q ; return pq ; } /*------------------------------*/ static double gamma_pq2s( pqpair pq , double sh , double sc ) { int which , status ; double p,q, x,shape,scale,bound ; which = 2 ; p = pq.p ; if( p <= 0.0 ) return 0.0 ; q = pq.q ; if( q <= 0.0 ) return BIGG ; x = 0.0 ; shape = sh ; scale = sc ; cdfgam( &which , &p , &q , &x , &shape , &scale , &status , &bound ) ; return x ; } /*---------------------------------------------------------------- Poisson distribution ------------------------------------------------------------------*/ static pqpair poisson_s2pq( double xx , double lambda ) { int which , status ; double p,q, s,xlam,bound ; pqpair pq={0.0,1.0} ; which = 1 ; p = 0.0 ; q = 1.0 ; s = xx ; if( s < 0.0 ) return pq ; xlam = lambda ; if( xlam < 0.0 ) return pq ; cdfpoi( &which , &p , &q , &s , &xlam , &status , &bound ) ; pq.p = p ; pq.q = q ; return pq ; } /*------------------------------*/ static double poisson_pq2s( pqpair pq , double lambda ) { int which , status ; double p,q, s,xlam,bound ; which = 2 ; p = pq.p ; q = pq.q ; s = 0.0 ; xlam = lambda ; cdfpoi( &which , &p , &q , &s , &xlam , &status , &bound ) ; return s ; } /*---------------------------------------------------------------- T distribution. ------------------------------------------------------------------*/ static pqpair student_s2pq( double xx , double dof ) { int which , status ; double p,q, s,xlam,bound ; pqpair pq={0.0,1.0} ; which = 1 ; p = 0.0 ; q = 1.0 ; s = xx ; xlam = dof ; if( xlam <= 0.0 ) return pq ; cdft( &which , &p , &q , &s , &xlam , &status , &bound ) ; pq.p = p ; pq.q = q ; return pq ; } /*------------------------------*/ double student_pq2s( pqpair pq , double dof ) { int which , status ; double p,q, s,xlam,bound ; which = 2 ; p = pq.p ; q = pq.q ; s = 0.0 ; xlam = dof ; cdft( &which , &p , &q , &s , &xlam , &status , &bound ) ; return s ; } /****************************************************************************/ /* For the distributions below here, cdflib can't do what we want directly. */ /****************************************************************************/ /*---------------------------------------------------------------- Null correlation distribution. Let x = (rr+1)/2; then x is Beta(dof/2,dof/2). ------------------------------------------------------------------*/ static pqpair correl_s2pq( double rr , double dof ) /* fake it with cdflib */ { return beta_s2pq( 0.5*(rr+1.0) , 0.5*dof , 0.5*dof ) ; } /*------------------------------*/ static double correl_pq2s( pqpair pq , double dof ) { double xx = beta_pq2s( pq , 0.5*dof , 0.5*dof ) ; return (2.0*xx-1.0) ; } /*---------------------------------------------------------------- Uniform U(0,1) distribution. ------------------------------------------------------------------*/ static pqpair uniform_s2pq( double xx ) /* this isn't too hard */ { pqpair pq ; if( xx <= 0.0 ) pq.p = 0.0 ; else if( xx >= 1.0 ) pq.p = 1.0 ; else pq.p = xx ; pq.q = 1.0-xx ; return pq ; } /*------------------------------*/ static double uniform_pq2s( pqpair pq ) { return pq.p ; /* that was easy */ } /*---------------------------------------------------------------- standard Logistic distribution. ------------------------------------------------------------------*/ static pqpair logistic_s2pq( double xx ) /* this isn't hard, either */ { pqpair pq ; if( xx >= 0.0 ){ pq.q = 1.0/(1.0+exp( xx)); pq.p = 1.0-pq.q; } else { pq.p = 1.0/(1.0+exp(-xx)); pq.q = 1.0-pq.p; } return pq ; } /*------------------------------*/ static double logistic_pq2s( pqpair pq ) { if( pq.p <= 0.0 ) return -BIGG ; else if( pq.q <= 0.0 ) return BIGG ; if( pq.p < pq.q ) return -log(1.0/pq.p-1.0) ; else return log(1.0/pq.q-1.0) ; } /*---------------------------------------------------------------- standard Laplace distribution. ------------------------------------------------------------------*/ static pqpair laplace_s2pq( double xx ) /* easy */ { pqpair pq ; if( xx >= 0.0 ){ pq.q = 0.5*exp(-xx) ; pq.p = 1.0-pq.q ; } else { pq.p = 0.5*exp( xx) ; pq.q = 1.0-pq.p ; } return pq ; } /*------------------------------*/ static double laplace_pq2s( pqpair pq ) { if( pq.p <= 0.0 ) return -BIGG ; else if( pq.q <= 0.0 ) return BIGG ; if( pq.p < pq.q ) return log(2.0*pq.p) ; else return -log(2.0*pq.q) ; } /*---------------------------------------------------------------- noncentral T distribution = hard calculation ------------------------------------------------------------------*/ /**************************************************************************** Noncentral t distribution function by Professor K. Krishnamoorthy Department of Mathematics University of Louisiana at Lafayette Manually translated from Fortran by RWC. *****************************************************************************/ #if 0 static double alng( double x ) /* log(Gamma(x)) from K */ { int indx ; double xx,fterm,sum,valg ; double b[9] = { 0.0 , 8.33333333333333e-2, 3.33333333333333e-2, 2.52380952380952e-1, 5.25606469002695e-1, 1.01152306812684e0, 1.51747364915329e0, 2.26948897420496e0, 3.00991738325940e0 } ; if( x < 8.0 ){ xx = x + 8.0 ; indx = 1 ; } else { xx = x ; indx = 0 ; } fterm = (xx-0.5)*log(xx) - xx + 9.1893853320467e-1 ; sum = b[1]/(xx+b[2]/(xx+b[3]/(xx+b[4]/(xx+b[5]/(xx+b[6]/ (xx+b[7]/(xx+b[8]))))))) ; valg = sum + fterm ; if(indx) valg = valg-log(x+7.0)-log(x+6.0)-log(x+5.0) -log(x+4.0)-log(x+3.0)-log(x+2.0)-log(x+1.0)-log(x) ; return valg ; } #else static double alng( double x ) /*-- replace with cdflib function --*/ { double xx=x ; return alngam( &xx ) ; } #endif /*---------------------------------------------------------------------------*/ #if 0 static double gaudf( double x ) /* N(0,1) cdf from K */ { static double p0=913.16744211475570 , p1=1024.60809538333800, p2=580.109897562908800, p3=202.102090717023000, p4=46.0649519338751400, p5=6.81311678753268400, p6=6.047379926867041e-1,p7=2.493381293151434e-2 ; static double q0=1826.33488422951125, q1=3506.420597749092, q2=3044.77121163622200, q3=1566.104625828454, q4=523.596091947383490, q5=116.9795245776655, q6=17.1406995062577800, q7=1.515843318555982, q8=6.25e-2 ; static double sqr2pi=2.506628274631001 ; int check ; double reslt,z , first,phi ; if(x > 0.0){ z = x ; check = 1 ; } else { z =-x ; check = 0 ; } if( z > 32.0 ) return (x > 0.0) ? 1.0 : 0.0 ; first = exp(-0.5*z*z) ; phi = first/sqr2pi ; if (z < 7.0) reslt = first* (((((((p7*z+p6)*z+p5)*z+p4)*z+p3)*z+p2)*z+p1)*z+p0) /((((((((q8*z+q7)*z+q6)*z+q5)*z+q4)*z+q3)*z+q2)*z+q1)*z+q0); else reslt = phi/(z+1.0/(z+2.0/(z+3.0/(z+4.0/(z+6.0/(z+7.0)))))) ; if(check) reslt = 1.0 - reslt ; return reslt ; } #else static double gaudf( double x ) /*-- replace with cdflib func --*/ { double xx=x , p,q ; cumnor( &xx, &p, &q ); return p; } #endif /*---------------------------------------------------------------------------*/ #if 0 static double betadf( double x , double p , double q ) /* Beta cdf from K */ { int check , ns ; double result,betf,psq,xx,cx,pp,qq ; double term,ai,rx,temp ; if( x >= 1.0 ) return 1.0 ; if( x <= 0.0 ) return 0.0 ; betf = alng(p)+alng(q)-alng(p+q) ; result=x ; psq=p+q ; cx=1.0-x ; if(p < psq*x){ xx=cx ; cx=x ; pp=q ; qq=p ; check=1 ; } else { xx=x ; pp=p ; qq=q ; check=0 ; } term=1.0 ; ai=1.0 ; result=1.0 ; ns=(int)(qq+cx*psq) ; rx=xx/cx ; L3: temp=qq-ai ; if(ns == 0) rx=xx ; L4: term=term*temp*rx/(pp+ai) ; result=result+term ; temp=fabs(term) ; if(temp <= 1.e-14 && temp <= 1.e-14*result) goto L5 ; ai=ai+1.0 ; ns=ns-1 ; if(ns >= 0) goto L3 ; temp=psq ; psq=psq+1.0 ; goto L4 ; L5: result=result*exp(pp*log(xx)+(qq-1.0)*log(cx)-betf)/pp ; if(check) result=1.0-result ; return result ; } #else static double betadf( double x , double p , double q ) /*-- cdflib func --*/ { double xx=x,yy=1.0-x , aa=p,bb=q , pp,qq ; cumbet( &xx,&yy , &aa,&bb , &pp,&qq ) ; return pp ; } #endif /*---------------------------------------------------------------------------*/ /* Krishnamoorthy's function for cdf of noncentral t, for df > 0, translated into C by RW Cox [Mar 2004]. Note the original fails for delta=0, so we call the cdflib func for this. A couple of other minor fixes are also included. -----------------------------------------------------------------------------*/ static pqpair tnonc_s2pq( double t , double df , double delta ) { int indx , k , i ; double x,del,tnd,ans,y,dels,a,b,c ; double pkf,pkb,qkf,qkb , pgamf,pgamb,qgamf,qgamb ; double pbetaf,pbetab,qbetaf,qbetab ; double ptermf,qtermf,ptermb,qtermb,term ; double rempois,delosq2,sum,cons,error ; pqpair pq={0.0,1.0} ; /* will be return value */ double ab1 ; /*-- stupid user? --*/ if( df <= 0.0 ) return pq ; /*-- non-centrality = 0? --*/ if( fabs(delta) < 1.e-8 ) return student_s2pq(t,df) ; /*-- start K's code here --*/ if( t < 0.0 ){ x = -t ; del = -delta ; indx = 1 ; } /* x will be */ else { x = t ; del = delta ; indx = 0 ; } /* positive */ ans = gaudf(-del) ; /* prob that x <= 0 = Normal cdf */ /*-- the nearly trivial case of x=0 --*/ if( x == 0.0 ){ pq.p = ans; pq.q = 1.0-ans; return pq; } if( df == 1.0 ) df = 1.0000001 ; /** df=1 is BAD **/ y = x*x/(df+x*x) ; /* between 0 and 1 */ dels = 0.5*del*del ; /* will be positive */ k = (int)dels ; /* 0, 1, 2, ... */ a = k+0.5 ; /* might be as small as 0.5 */ c = k+1.0 ; b = 0.5*df ; /* might be as small as 0.0 */ pkf = exp(-dels+k*log(dels)-alng(k+1.0)) ; pkb = pkf ; qkf = exp(-dels+k*log(dels)-alng(k+1.0+0.5)) ; qkb = qkf ; pbetaf = betadf(y, a, b) ; pbetab = pbetaf ; qbetaf = betadf(y, c, b) ; qbetab = qbetaf ; ab1 = a+b-1.0 ; /* might be as small as -0.5 */ /*-- RWCox: if a+b-1 < 0, log(Gamma(a+b-1)) won't work; instead, use Gamma(a+b-1)=Gamma(a+b)/(a+b-1) --*/ if( ab1 > 0.0 ) pgamf = exp(alng(ab1)-alng(a)-alng(b)+(a-1.0)*log(y)+b*log(1.0-y)) ; else pgamf = exp(alng(a+b)-alng(a)-alng(b)+(a-1.0)*log(y)+b*log(1.0-y))/ab1 ; pgamb = pgamf*y*(ab1)/a ; /*-- we can't have c+b-1 < 0, so the above patchup isn't needed --*/ qgamf = exp(alng(c+b-1.0)-alng(c)-alng(b)+(c-1.0)*log(y) + b*log(1.0-y)) ; qgamb = qgamf*y*(c+b-1.0)/c ; rempois = 1.0 - pkf ; delosq2 = del/1.4142135623731 ; sum = pkf*pbetaf+delosq2*qkf*qbetaf ; cons = 0.5*(1.0 + 0.5*fabs(delta)) ; i = 0 ; L1: i = i + 1 ; pgamf = pgamf*y*(a+b+i-2.0)/(a+i-1.0) ; pbetaf = pbetaf - pgamf ; pkf = pkf*dels/(k+i) ; ptermf = pkf*pbetaf ; qgamf = qgamf*y*(c+b+i-2.0)/(c+i-1.0) ; qbetaf = qbetaf - qgamf ; qkf = qkf*dels/(k+i-1.0+1.5) ; qtermf = qkf*qbetaf ; term = ptermf + delosq2*qtermf ; sum = sum + term ; error = rempois*cons*pbetaf ; rempois = rempois - pkf ; if( i > k ){ if( error <= 1.e-12 || i >= 9999 ) goto L2 ; goto L1 ; } else { pgamb = pgamb*(a-i+1.0)/(y*(a+b-i)) ; pbetab = pbetab + pgamb ; pkb = (k-i+1.0)*pkb/dels ; ptermb = pkb*pbetab ; qgamb = qgamb*(c-i+1.0)/(y*(c+b-i)) ; qbetab = qbetab + qgamb ; qkb = (k-i+1.0+0.5)*qkb/dels ; qtermb = qkb*qbetab ; term = ptermb + delosq2*qtermb ; sum = sum + term ; rempois = rempois - pkb ; if (rempois <= 1.e-12 || i >= 9999) goto L2 ; goto L1 ; } L2: tnd = 0.5*sum + ans ; /*-- return a pqpair, not just the cdf --*/ if( indx ){ pq.p = 1.0-tnd; pq.q = tnd ; } else { pq.p = tnd ; pq.q = 1.0-tnd; } return pq ; } /*------------------------------*/ /* Inverse to above function; uses cdflib dstinv()/dinvr() to solve the equation. --------------------------------*/ static double tnonc_pq2s( pqpair pq , double dof , double nonc ) { double t ; /* will be result */ double tbot,ttop , dt ; double T6=1.e-50,T7=1.e-8 ; double K4=0.5,K5=5.0 ; double fx ; unsigned long qhi,qleft ; int status , qporq , ite ; pqpair tpq ; if( dof <= 0.0 ) return BIGG ; /* bad user */ if( pq.p <= 0.0 ) return -BIGG ; if( pq.q <= 0.0 ) return BIGG ; t = student_pq2s(pq,dof) ; /* initial guess */ if( fabs(nonc) < 1.e-8 ) return t ; t += 0.5*nonc ; /* adjust up or down */ dt = 0.1 * fabs(t) ; if( dt < 1.0 ) dt = 1.0 ; /* stepsize */ /* scan down for lower bound, below which cdf is < p */ tbot = t ; for( ite=0 ; ite < 1000 ; ite++ ){ tpq = tnonc_s2pq( tbot , dof , nonc ) ; if( tpq.p <= pq.p ) break ; tbot -= dt ; } if( ite >= 1000 ) return -BIGG ; /* scan up for upper bound, above which cdf is > p */ ttop = tbot+0.5*dt ; for( ite=0 ; ite < 1000 ; ite++ ){ tpq = tnonc_s2pq( ttop , dof , nonc ) ; if( tpq.p >= pq.p ) break ; ttop += dt ; } if( ite >= 1000 ) return BIGG ; t = 0.5*(tbot+ttop) ; /* initial guess in middle */ /* initialize searching parameters */ dstinv(&tbot,&ttop,&K4,&K4,&K5,&T6,&T7); status = 0 ; qporq = (pq.p <= pq.q) ; while(1){ dinvr(&status,&t,&fx,&qleft,&qhi) ; if( status != 1 ) return t ; /* done! */ tpq = tnonc_s2pq( t , dof , nonc ) ; /* get cdf */ /* goal of dinvr is to drive fx to zero */ fx = (qporq) ? pq.p-tpq.p : pq.q-tpq.q ; } return BIGG ; /* unreachable */ } /*---------------------------------------------------------------- Chi distribution (sqrt of chi-squared, duh). ------------------------------------------------------------------*/ static pqpair chi_s2pq( double xx , double dof ) { pqpair pq={0.0,1.0} ; if( xx <= 0.0 || dof <= 0.0 ) return pq ; return chisq_s2pq( xx*xx , dof ) ; } /*------------------------------*/ static double chi_pq2s( pqpair pq , double dof ) { if( pq.p <= 0.0 ) return 0.0 ; if( pq.q <= 0.0 ) return BIGG ; return sqrt(chisq_pq2s(pq,dof)) ; } /*---------------------------------------------------------------- Extreme value type I: cdf(x) = exp(-exp(-x)). ------------------------------------------------------------------*/ static pqpair extval1_s2pq( double x ) { double p,q,y ; pqpair pq ; if( x > -5.0 ){ y = exp(-x) ; p = exp(-y) ; } else { y = 1.0 ; p = 0.0 ; } if( y >= 1.e-4 ) q = 1.0-p ; else q = y*(1.0+y*(-0.5+y*(1.0/6.0-y/24.0))) ; pq.p = p ; pq.q = q ; return pq ; } /*------------------------------*/ static double extval1_pq2s( pqpair pq ) { if( pq.p <= 0.0 ) return -BIGG ; else if( pq.p >= 1.0 ) return BIGG ; return -log(-log(pq.p)) ; } /*---------------------------------------------------------------- Weibull distribution: cdf(x) = 1 - exp( -x^c ) for x>0 and c>0. ------------------------------------------------------------------*/ static pqpair weibull_s2pq( double x , double c ) { double y ; pqpair pq={0.0,1.0} ; if( x <= 0.0 || c <= 0.0 ) return pq ; y = pow(x,c) ; pq.q = exp(-y) ; if( y >= 1.e-4 ) pq.p = 1.0-pq.q ; else pq.p = y*(1.0+y*(-0.5+y*(1.0/6.0-y/24.0))) ; return pq ; } /*------------------------------*/ static double weibull_pq2s( pqpair pq , double c ) { if( pq.p <= 0.0 || c <= 0.0 ) return 0.0 ; else if( pq.q <= 0.0 ) return BIGG ; return pow( -log(pq.q) , 1.0/c ) ; } /*---------------------------------------------------------------- Inverse Gaussian: density proportional to exp(-0.5*c(x+1/x))/x^1.5 (x,c >0). ------------------------------------------------------------------*/ static pqpair invgauss_s2pq( double x, double c ) { double y , p1,q1 , p2,q2 , v ; pqpair pq={0.0,1.0} ; if( x <= 0.0 || c <= 0.0 ) return pq ; y = sqrt(c/x) ; v = y*(x-1.0) ; cumnor( &v , &p1,&q1 ) ; v = -y*(x+1.0) ; cumnor( &v , &p2,&q2 ) ; pq.p = p1 ; if( p2 > 0.0 ) pq.p += exp(2.0*c+log(p2)) ; pq.q = 1.0-pq.p ; return pq ; } /*------------------------------*/ /* Inverse to above function; uses cdflib dstinv()/dinvr() to solve the equation. --------------------------------*/ static double invgauss_pq2s( pqpair pq , double c ) { double t ; /* will be result */ double tbot,ttop , dt ; double T6=1.e-50,T7=1.e-8 ; double K4=0.5,K5=5.0 ; double fx ; unsigned long qhi,qleft ; int status , qporq , ite ; pqpair tpq ; if( c <= 0.0 ) return BIGG ; /* bad user */ if( pq.p <= 0.0 ) return 0.0 ; if( pq.q <= 0.0 ) return BIGG ; /* initial guess is t=1; scan down for lower bound */ tbot = 1.01 ; dt = 0.9 ; for( ite=0 ; ite < 1000 ; ite++ ){ tpq = invgauss_s2pq( tbot , c ) ; if( tpq.p <= pq.p ) break ; tbot *= dt ; } if( ite >= 1000 ) return 0.0 ; /* scan up for upper bound */ dt = 1.1 ; ttop = tbot*dt ; for( ite=0 ; ite < 1000 ; ite++ ){ tpq = invgauss_s2pq( ttop , c ) ; if( tpq.p >= pq.p ) break ; ttop *= dt ; } if( ite >= 1000 ) return BIGG ; t = sqrt(tbot*ttop) ; /* start at geometric mean */ /* initialize searching parameters */ dstinv(&tbot,&ttop,&K4,&K4,&K5,&T6,&T7); status = 0 ; qporq = (pq.p <= pq.q) ; while(1){ dinvr(&status,&t,&fx,&qleft,&qhi) ; if( status != 1 ) return t ; /* done! */ tpq = invgauss_s2pq( t , c ) ; /* goal is to drive fx to zero */ fx = (qporq) ? pq.p-tpq.p : pq.q-tpq.q ; } return BIGG ; /* unreachable */ } /*--------------------------------------------------------------------------*/ /*! Given a value, calculate both its cdf and reversed cdf (1.0-cdf). - If an error occurs, you'll probably get back {0.0,1.0}. - All the actual work is done in utility functions for each distribution. ----------------------------------------------------------------------------*/ static pqpair stat2pq(double val, int code, double p1, double p2, double p3) { pqpair pq = {0.0, 1.0}; switch (code) { case NIFTI_INTENT_CORREL: pq = correl_s2pq(val, p1); break; case NIFTI_INTENT_TTEST: pq = student_s2pq(val, p1); break; case NIFTI_INTENT_FTEST: pq = fstat_s2pq(val, p1, p2); break; case NIFTI_INTENT_ZSCORE: pq = normal_s2pq(val); break; case NIFTI_INTENT_CHISQ: pq = chisq_s2pq(val, p1); break; case NIFTI_INTENT_BETA: pq = beta_s2pq(val, p1, p2); break; case NIFTI_INTENT_BINOM: pq = binomial_s2pq(val, p1, p2); break; case NIFTI_INTENT_GAMMA: pq = gamma_s2pq(val, p1, p2); break; case NIFTI_INTENT_POISSON: pq = poisson_s2pq(val, p1); break; case NIFTI_INTENT_FTEST_NONC: pq = fnonc_s2pq(val, p1, p2, p3); break; case NIFTI_INTENT_CHISQ_NONC: pq = chsqnonc_s2pq(val, p1, p2); break; case NIFTI_INTENT_TTEST_NONC: pq = tnonc_s2pq(val, p1, p2); break; case NIFTI_INTENT_CHI: pq = chi_s2pq(val, p1); break; /* these distributions are shifted and scaled copies of a standard case */ case NIFTI_INTENT_INVGAUSS: if (p1 > 0.0 && p2 > 0.0) pq = invgauss_s2pq(val / p1, p2 / p1); break; case NIFTI_INTENT_WEIBULL: if (p2 > 0.0 && p3 > 0.0) pq = weibull_s2pq((val - p1) / p2, p3); break; case NIFTI_INTENT_EXTVAL: if (p2 > 0.0) pq = extval1_s2pq((val - p1) / p2); break; case NIFTI_INTENT_NORMAL: if (p2 > 0.0) pq = normal_s2pq((val - p1) / p2); break; case NIFTI_INTENT_LOGISTIC: if (p2 > 0.0) pq = logistic_s2pq((val - p1) / p2); break; case NIFTI_INTENT_LAPLACE: if (p2 > 0.0) pq = laplace_s2pq((val - p1) / p2); break; case NIFTI_INTENT_UNIFORM: if (p2 > p1) pq = uniform_s2pq((val - p1) / (p2 - p1)); break; /* these cases are trivial (note what is called 'p' is really 'q') */ case NIFTI_INTENT_PVAL: if (val >= 0.0 && val <= 1.0) pq.q = val; pq.p = 1.0 - pq.q; break; case NIFTI_INTENT_LOGPVAL: pq.q = exp(-fabs(val)); pq.p = 1.0 - pq.q; break; case NIFTI_INTENT_LOG10PVAL: pq.q = pow(10., -fabs(val)); pq.p = 1.0 - pq.q; break; } return pq; } /*--------------------------------------------------------------------------*/ /*! Given a pq value (cdf and 1-cdf), compute the value that gives this. - If an error occurs, you'll probably get back a BIGG number. - All the actual work is done in utility functions for each distribution. - Note that for the LOGPVAL and LOG10PVAL cases, the returned value will be -log(q) and -log10(q). ----------------------------------------------------------------------------*/ static double pq2stat( pqpair pq, int code, double p1,double p2,double p3 ) { double val = BIGG; if (pq.p < 0.0 || pq.q < 0.0 || pq.p > 1.0 || pq.q > 1.0) return val; switch (code) { case NIFTI_INTENT_CORREL: val = correl_pq2s(pq, p1); break; case NIFTI_INTENT_TTEST: val = student_pq2s(pq, p1); break; case NIFTI_INTENT_FTEST: val = fstat_pq2s(pq, p1, p2); break; case NIFTI_INTENT_ZSCORE: val = normal_pq2s(pq); break; case NIFTI_INTENT_CHISQ: val = chisq_pq2s(pq, p1); break; case NIFTI_INTENT_BETA: val = beta_pq2s(pq, p1, p2); break; case NIFTI_INTENT_BINOM: val = binomial_pq2s(pq, p1, p2); break; case NIFTI_INTENT_GAMMA: val = gamma_pq2s(pq, p1, p2); break; case NIFTI_INTENT_POISSON: val = poisson_pq2s(pq, p1); break; case NIFTI_INTENT_FTEST_NONC: val = fnonc_pq2s(pq, p1, p2, p3); break; case NIFTI_INTENT_CHISQ_NONC: val = chsqnonc_pq2s(pq, p1, p2); break; case NIFTI_INTENT_TTEST_NONC: val = tnonc_pq2s(pq, p1, p2); break; case NIFTI_INTENT_CHI: val = chi_pq2s(pq, p1); break; /* these distributions are shifted and scaled copies of a standard case */ case NIFTI_INTENT_INVGAUSS: if (p1 > 0.0 && p2 > 0.0) val = p1 * invgauss_pq2s(pq, p2 / p1); break; case NIFTI_INTENT_WEIBULL: if (p2 > 0.0 && p3 > 0.0) val = p1 + p2 * weibull_pq2s(pq, p3); break; case NIFTI_INTENT_EXTVAL: if (p2 > 0.0) val = p1 + p2 * extval1_pq2s(pq); break; case NIFTI_INTENT_NORMAL: if (p2 > 0.0) val = p1 + p2 * normal_pq2s(pq); break; case NIFTI_INTENT_LOGISTIC: if (p2 > 0.0) val = p1 + p2 * logistic_pq2s(pq); break; case NIFTI_INTENT_LAPLACE: if (p2 > 0.0) val = p1 + p2 * laplace_pq2s(pq); break; case NIFTI_INTENT_UNIFORM: if (p2 > p1) val = p1 + (p2 - p1) * uniform_pq2s(pq); break; /* these cases are trivial */ case NIFTI_INTENT_PVAL: val = pq.q; break; case NIFTI_INTENT_LOGPVAL: val = (pq.q > 0.0) ? -log(pq.q) : BIGG; break; case NIFTI_INTENT_LOG10PVAL: val = (pq.q > 0.0) ? -log10(pq.q) : BIGG; break; } return val; } /****************************************************************************/ /*[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]*/ /*..........................................................................*/ /*............. AT LAST! Functions to be called by the user! ..............*/ /*..........................................................................*/ /*[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]*/ /****************************************************************************/ /**************************************************************************** Statistical codes implemented here: NIFTI_INTENT_CORREL = correlation statistic NIFTI_INTENT_TTEST = t statistic (central) NIFTI_INTENT_FTEST = F statistic (central) NIFTI_INTENT_ZSCORE = N(0,1) statistic NIFTI_INTENT_CHISQ = Chi-squared (central) NIFTI_INTENT_BETA = Beta variable (central) NIFTI_INTENT_BINOM = Binomial variable NIFTI_INTENT_GAMMA = Gamma distribution NIFTI_INTENT_POISSON = Poisson distribution NIFTI_INTENT_FTEST_NONC = noncentral F statistic NIFTI_INTENT_CHISQ_NONC = noncentral chi-squared NIFTI_INTENT_TTEST_NONC = noncentral t statistic NIFTI_INTENT_CHI = Chi statistic (central) NIFTI_INTENT_INVGAUSS = inverse Gaussian variable NIFTI_INTENT_WEIBULL = Weibull distribution NIFTI_INTENT_EXTVAL = Extreme value type I NIFTI_INTENT_NORMAL = N(mu,variance) normal NIFTI_INTENT_LOGISTIC = Logistic distribution NIFTI_INTENT_LAPLACE = Laplace distribution NIFTI_INTENT_UNIFORM = Uniform distribution NIFTI_INTENT_PVAL = "p-value" NIFTI_INTENT_LOGPVAL = -ln(p) NIFTI_INTENT_LOG10PVAL = -log10(p) *****************************************************************************/ char const * const inam[]={ NULL , NULL , "CORREL" , "TTEST" , "FTEST" , "ZSCORE" , "CHISQ" , "BETA" , "BINOM" , "GAMMA" , "POISSON" , "NORMAL" , "FTEST_NONC" , "CHISQ_NONC" , "LOGISTIC" , "LAPLACE" , "UNIFORM" , "TTEST_NONC" , "WEIBULL" , "CHI" , "INVGAUSS" , "EXTVAL" , "PVAL" , "LOGPVAL" , "LOG10PVAL" , NULL } ; /*--------------------------------------------------------------------------*/ /*! Given a string name for a statistic, return its integer code. - Input string can be any case. - Returns -1 if name isn't found in the table. ----------------------------------------------------------------------------*/ int nifti_intent_code( char *name ) { char *unam , *upt ; int ii ; if( name == NULL || *name == '\0' ) return -1 ; unam = (char *)malloc(strlen(name)+1); strcpy(unam,name); for( upt=unam ; *upt != '\0' ; upt++ ) *upt = (char)toupper(*upt) ; for( ii=NIFTI_FIRST_STATCODE ; ii <= NIFTI_LAST_STATCODE ; ii++ ) if( strcmp(inam[ii],unam) == 0 ) break ; free(unam) ; return (ii <= NIFTI_LAST_STATCODE) ? ii : -1 ; } /*--------------------------------------------------------------------------*/ /*! Given a value, return its cumulative distribution function (cdf): - val = statistic - code = NIFTI_INTENT_* statistical code - p1,p2,p3 = parameters of the distribution If an error occurs, you'll probably get back 0.0. ----------------------------------------------------------------------------*/ double nifti_stat2cdf( double val, int code, double p1,double p2,double p3 ) { pqpair pq ; pq = stat2pq( val, code, p1,p2,p3 ) ; return pq.p ; } /*--------------------------------------------------------------------------*/ /*! Given a value, return its reversed cumulative distribution function (1-cdf): - val = statistic - code = NIFTI_INTENT_* statistical code - p1,p2,p3 = parameters of the distribution If an error transpires, you'll probably get back 1.0. ----------------------------------------------------------------------------*/ double nifti_stat2rcdf( double val, int code, double p1,double p2,double p3 ) { pqpair pq ; pq = stat2pq( val, code, p1,p2,p3 ) ; return pq.q ; } /*--------------------------------------------------------------------------*/ /*! Given a cdf probability, find the value that gave rise to it. - p = cdf; 0 < p < 1 - code = NIFTI_INTENT_* statistical code - p1,p2,p3 = parameters of the distribution If an error transpires, you'll probably get back a BIGG number. ----------------------------------------------------------------------------*/ double nifti_cdf2stat( double p , int code, double p1,double p2,double p3 ) { pqpair pq ; pq.p = p ; pq.q = 1.0-p ; return pq2stat(pq,code,p1,p2,p3) ; } #if defined(__COMPILE_UNUSED_FUNCTIONS__) /*--------------------------------------------------------------------------*/ /*! Given a reversed cdf probability, find the value that gave rise to it. - q = 1-cdf; 0 < q < 1 - code = NIFTI_INTENT_* statistical code - p1,p2,p3 = parameters of the distribution If an error transpires, you'll probably get back a BIGG number. ----------------------------------------------------------------------------*/ double nifti_rcdf2stat( double q , int code, double p1,double p2,double p3 ) { pqpair pq ; pq.p = 1.0-q ; pq.q = q ; return pq2stat(pq,code,p1,p2,p3) ; } #endif/*(__COMPILE_UNUSED_FUNCTIONS__)*/ /*--------------------------------------------------------------------------*/ /*! Given a statistic, compute a z-score from it. That is, the output is z such that cdf(z) of a N(0,1) variable is the same as the cdf of the given distribution at val. ----------------------------------------------------------------------------*/ double nifti_stat2zscore( double val , int code, double p1,double p2,double p3 ) { pqpair pq ; if( code == NIFTI_INTENT_ZSCORE ) return val ; /* trivial */ if( code == NIFTI_INTENT_NORMAL ) return (val-p1)/p2 ; /* almost so */ pq = stat2pq( val, code, p1,p2,p3 ) ; /* find cdf */ return normal_pq2s( pq ) ; /* find z */ } /*--------------------------------------------------------------------------*/ /*! Given a statistic, compute a half-z-score from it. That is, the output is z such that cdf(z) of a half-N(0,1) variable is the same as the cdf of the given distribution at val. A half-N(0,1) variable has density zero for z < 0 and twice the usual N(0,1) density for z > 0. ----------------------------------------------------------------------------*/ double nifti_stat2hzscore( double val, int code, double p1,double p2,double p3 ) { pqpair pq ; pq = stat2pq( val, code, p1,p2,p3 ) ; /* find cdf */ pq.q = 0.5*(1.0-pq.p) ; pq.p = 0.5*(1.0+pq.p) ; /* mangle it */ return normal_pq2s( pq ) ; /* find z */ } nifti_clib-3.0.1/nifticdf/nifticdf.h000066400000000000000000000214711371325713600173570ustar00rootroot00000000000000 /************************************************************************/ /** Functions to compute cumulative distributions and their inverses **/ /** for the NIfTI-1 statistical types. Much of this code is taken **/ /** from other sources. In particular, the cdflib functions by **/ /** Brown and Lovato make up the bulk of this file. That code **/ /** was placed in the public domain. The code by K. Krishnamoorthy **/ /** is also released for unrestricted use. Finally, the other parts **/ /** of this file (by RW Cox) are released to the public domain. **/ /** **/ /** Most of this file comprises a set of "static" functions, to be **/ /** called by the user-level functions at the very end of the file. **/ /** At the end of the file is a simple main program to drive these **/ /** functions. **/ /** **/ /** To find the user-level functions, search forward for the string **/ /** "nifti_", which will be at about line 11000. **/ /************************************************************************/ /*****==============================================================*****/ /***** Neither the National Institutes of Health (NIH), the DFWG, *****/ /***** nor any of the members or employees of these institutions *****/ /***** imply any warranty of usefulness of this material for any *****/ /***** purpose, and do not assume any liability for damages, *****/ /***** incidental or otherwise, caused by any use of this document. *****/ /***** If these conditions are not acceptable, do not use this! *****/ /*****==============================================================*****/ /************************************************************************/ #include /**************************************************************************** Statistical codes implemented : NIFTI_INTENT_CORREL = correlation statistic NIFTI_INTENT_TTEST = t statistic (central) NIFTI_INTENT_FTEST = F statistic (central) NIFTI_INTENT_ZSCORE = N(0,1) statistic NIFTI_INTENT_CHISQ = Chi-squared (central) NIFTI_INTENT_BETA = Beta variable (central) NIFTI_INTENT_BINOM = Binomial variable NIFTI_INTENT_GAMMA = Gamma distribution NIFTI_INTENT_POISSON = Poisson distribution NIFTI_INTENT_FTEST_NONC = noncentral F statistic NIFTI_INTENT_CHISQ_NONC = noncentral chi-squared NIFTI_INTENT_TTEST_NONC = noncentral t statistic NIFTI_INTENT_CHI = Chi statistic (central) NIFTI_INTENT_INVGAUSS = inverse Gaussian variable NIFTI_INTENT_WEIBULL = Weibull distribution NIFTI_INTENT_EXTVAL = Extreme value type I NIFTI_INTENT_NORMAL = N(mu,variance) normal NIFTI_INTENT_LOGISTIC = Logistic distribution NIFTI_INTENT_LAPLACE = Laplace distribution NIFTI_INTENT_UNIFORM = Uniform distribution NIFTI_INTENT_PVAL = "p-value" NIFTI_INTENT_LOGPVAL = -ln(p) NIFTI_INTENT_LOG10PVAL = -log10(p) *****************************************************************************/ extern char const * const inam[]; int nifti_intent_code( char *name ); double nifti_stat2cdf( double val, int code, double p1,double p2,double p3 ); double nifti_stat2rcdf( double val, int code, double p1,double p2,double p3 ); double nifti_cdf2stat( double p , int code, double p1,double p2,double p3 ); #if defined(__COMPILE_UNUSED_FUNCTIONS__) double nifti_rcdf2stat( double q , int code, double p1,double p2,double p3 ); #endif/*(__COMPILE_UNUSED_FUNCTIONS__)*/ double nifti_stat2zscore( double val , int code, double p1,double p2,double p3); double nifti_stat2hzscore( double val, int code, double p1,double p2,double p3); /** Prototypes for cdflib functions **/ double algdiv(const double*,const double*); double alngam(const double*); double alnrel(const double*); double apser(const double*,double*,const double*,const double*); double basym(double*,double*,const double*,const double*); double bcorr(const double*,const double*); double betaln(const double*,const double*); double bfrac(double*,double*,double*,double*,const double*,const double*); void bgrat(double*,double*,const double*,const double*,double*,double*,int*ierr); double bpser(double*,double*,const double*,const double*); void bratio(const double*,const double*,const double*,const double*,double*,double*,int*); double brcmp1(int*,double*,double*,const double*,const double*); double brcomp(double*,double*,const double*,const double*); double bup(double*,double*,double*,double*,const int*,const double*); void cdfbet(const int*,double*,double*,double*,double*,double*,double*, int*,double*); void cdfbin(const int*,double*,double*,double*,double*,double*,double*, int*,double*); void cdfchi(const int*,double*,double*,double*,double*,int*,double*); void cdfchn(const int*,double*,double*,double*,double*,double*,int*,double*); void cdff(const int*,double*,double*,double*,double*,double*,int*,double*); void cdffnc(const int*,double*,double*,double*,double*,double*,double*, int*status,double*); void cdfgam(const int*,double*,double*,double*,double*,double*,int*,double*); #if defined(__COMPILE_UNUSED_FUNCTIONS__) void cdfnbn(int*,double*,double*,double*,double*,double*,double*, int*,double*); void cdfnor(int*,double*,double*,double*,double*,double*,int*,double*); #endif /*defined(__COMPILE_UNUSED_FUNCTIONS__)*/ void cdfpoi(const int*,double*,double*,double*,double*,int*,double*); void cdft(const int*,double*,double*,double*,double*,int*,double*); void cumbet(double*,double*,double*,double*,double*,double*); void cumbin(const double*,const double*,double*,double*,double*,double*); void cumchi(const double*,const double*,double*,double*); void cumchn(double*,double*,const double*,double*,double*); void cumf(const double*,const double*,const double*,double*,double*); void cumfnc(double*,double*,double*,const double*,double*,double*); void cumgam(double*,double*,double*,double*); #if defined(__COMPILE_UNUSED_FUNCTIONS__) void cumnbn(double*,double*,double*,double*,double*,double*); #endif /*defined(__COMPILE_UNUSED_FUNCTIONS__)*/ void cumnor(const double*,double*,double*); void cumpoi(const double*,const double*,double*,double*); void cumt(const double*,const double*,double*,double*); #if defined(__COMPILE_UNUSED_FUNCTIONS__) double dbetrm(double*,double*); #endif /*defined(__COMPILE_UNUSED_FUNCTIONS__)*/ double devlpl(const double [],const int*,const double*); #if defined(__COMPILE_UNUSED_FUNCTIONS__) double dexpm1(double*); double dinvnr(const double *p,const double *q); #endif /*defined(__COMPILE_UNUSED_FUNCTIONS__)*/ void E0000(int,int*,double*,double*,unsigned long*, unsigned long*,const double*,const double*,const double*, const double*,const double*,const double*,const double*); void dinvr(int*,double*,double*,unsigned long*,unsigned long*); void dstinv(double*,double*,double*,double*,double*,double*, double*); #if defined(__COMPILE_UNUSED_FUNCTIONS__) double dlanor(double*); double dln1mx(double*); double dln1px(double*); double dlnbet(double*,double*); double dlngam(double*); double dstrem(double*); #endif /*defined(__COMPILE_UNUSED_FUNCTIONS__)*/ double dt1(double*,double*,const double*); void E0001(int,int*,double*,const double*,double*,double*, unsigned long*,unsigned long*,const double*,const double*, const double*,const double*); void dzror(int*,double*,double*,double*,double *, unsigned long*,unsigned long*); void dstzr(double *zxlo,double *zxhi,double *zabstl,double *zreltl); double erf1(const double*); double erfc1(const int*,const double*); double esum(const int*,const double*); double exparg(const int*); double fpser(const double*,const double*,const double*,const double*); double gam1(const double*); void gaminv(double*,double*,const double*,const double*,const double*,int*); double gamln(double*); double gamln1(const double*); double Xgamm(const double*); void grat1(double*,const double*,const double*,double*,double*,const double*); void gratio(double*,const double*,double*,double*,const int*); double gsumln(const double*,const double*); double psi(const double*); double rcomp(double*,const double*); double rexp(const double*); double rlog(const double*); double rlog1(const double*); double spmpar(const int*); double stvaln(const double*); double fifdint(double); double fifdmax1(double,double); double fifdmin1(double,double); double fifdsign(double,double); long fifidint(double); long fifmod(long,long); void ftnstop(const char*); int ipmpar(const int*); /** end: prototypes for cdflib functions **/ nifti_clib-3.0.1/nifticdf/nifticdf_version.h000066400000000000000000000013321371325713600211160ustar00rootroot00000000000000/* NOTE: When changing version consider the impact on versions in nifti2_io_version.h nifti1_io_version.h nifticdf_version.h and znzlib.h */ #define NIFTICDF_VERSION_MAJOR 2 #define NIFTICDF_VERSION_MINOR 1 #define NIFTICDF_VERSION_PATCH 0 /* main string macros: NIFTICDF_VERSION and NIFTICDF_SOURCE_VERSION */ #define NIFTICDF_VERSION_TO_STRING(x) NIFTICDF_VERSION_TO_STRING0(x) #define NIFTICDF_VERSION_TO_STRING0(x) #x #define NIFTICDF_VERSION \ NIFTICDF_VERSION_TO_STRING(NIFTICDF_VERSION_MAJOR) \ "." NIFTICDF_VERSION_TO_STRING(NIFTICDF_VERSION_MINOR) \ "." NIFTICDF_VERSION_TO_STRING(NIFTICDF_VERSION_PATCH) #define NIFTICDF_SOURCE_VERSION "NIFTICDF version " NIFTICDF_VERSION nifti_clib-3.0.1/niftilib/000077500000000000000000000000001371325713600154255ustar00rootroot00000000000000nifti_clib-3.0.1/niftilib/CMakeLists.txt000066400000000000000000000266611371325713600202000ustar00rootroot00000000000000set(NIFTI_NIFTILIB_NAME ${NIFTI_PACKAGE_PREFIX}niftiio) add_nifti_library(${NIFTI_NIFTILIB_NAME} nifti1_io.c ) target_link_libraries( ${NIFTI_NIFTILIB_NAME} PUBLIC ${NIFTI_PACKAGE_PREFIX}znz ${NIFTI_SYSTEM_MATH_LIB}) set_target_properties( ${NIFTI_NIFTILIB_NAME} PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_LIST_DIR}/nifti1_io.h;${CMAKE_CURRENT_LIST_DIR}/nifti1.h" ) # Set library version when building shared libs. if(BUILD_SHARED_LIBS) get_lib_version_vars("nifti1_io_version.h" NIFTI_VERSION NIFTI_MAJOR_VERSION) set_target_properties(${NIFTI_NIFTILIB_NAME} PROPERTIES ${NIFTI_LIBRARY_PROPERTIES} VERSION ${NIFTI_VERSION} SOVERSION ${NIFTI_MAJOR_VERSION} ) endif() install_nifti_target(${NIFTI_NIFTILIB_NAME}) if(NIFTI_BUILD_APPLICATIONS) add_nifti_executable(${NIFTI_PACKAGE_PREFIX}nifti1_tool nifti1_tool.c) target_link_libraries(${NIFTI_PACKAGE_PREFIX}nifti1_tool PUBLIC ${NIFTI_NIFTILIB_NAME}) install_nifti_target(${NIFTI_PACKAGE_PREFIX}nifti1_tool) install_man_page( ${NIFTI_PACKAGE_PREFIX}nifti1_tool OPTS "--help-option=-help;--version-option=-ver_man;--no-info" ) endif() if(NIFTI_BUILD_TESTING AND NIFTI_BUILD_APPLICATIONS) add_executable(${NIFTI_PACKAGE_PREFIX}nifti1_test nifti1_test.c) target_link_libraries(${NIFTI_PACKAGE_PREFIX}nifti1_test PUBLIC ${NIFTI_NIFTILIB_NAME}) add_executable(nifti_first_test_program nifti_tester001.c) target_link_libraries(nifti_first_test_program ${NIFTI_PACKAGE_PREFIX}niftiio ) add_executable(nifti_second_test_program nifti_tester002.c) target_link_libraries(nifti_second_test_program ${NIFTI_PACKAGE_PREFIX}niftiio ) add_executable( ${NIFTI_PACKAGE_PREFIX}nifti_tester001 nifti_tester001.c) target_link_libraries(${NIFTI_PACKAGE_PREFIX}nifti_tester001 ${NIFTI_PACKAGE_PREFIX}niftiio ) add_executable( ${NIFTI_PACKAGE_PREFIX}nifti_tester002 nifti_tester002.c) target_link_libraries(${NIFTI_PACKAGE_PREFIX}nifti_tester002 ${NIFTI_PACKAGE_PREFIX}niftiio ) # setup data to be used for other tests add_test( NAME nifti_first_test COMMAND $ ) add_test( NAME nifti_second_test COMMAND $ ) # Do all regression tests set(TOOL_SUFFIX "1") # The suffxi used for this tool "1" for nifti1, and "" for nifti2 set(TEST_PREFIX "${NIFTI_PACKAGE_PREFIX}nifti${TOOL_SUFFIX}") set(TOOL_NAME "${TEST_PREFIX}_tool") add_test( NAME ${TEST_PREFIX}_test_help COMMAND $) add_test( NAME ${TEST_PREFIX}_test_n1 COMMAND $ -n1 ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/ATestReferenceImageForReadingAndWriting.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/n1 ) add_test( NAME ${TEST_PREFIX}_test_n2 COMMAND $ -n2 ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/ATestReferenceImageForReadingAndWriting.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/n2 ) add_test( NAME ${TEST_PREFIX}_test_a2 COMMAND $ -a2 ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/ATestReferenceImageForReadingAndWriting.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/a2 ) add_test( NAME ${TEST_PREFIX}_test_zn1 COMMAND $ -zn1 ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/ATestReferenceImageForReadingAndWriting.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/zn1 ) add_test( NAME ${TEST_PREFIX}_test_zn2 COMMAND $ -zn2 ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/ATestReferenceImageForReadingAndWriting.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/zn2 ) add_test( NAME ${TEST_PREFIX}_test_za2 COMMAND $ -za2 ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/ATestReferenceImageForReadingAndWriting.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/za2 ) add_test( NAME ${TEST_PREFIX}_ver COMMAND $ -nifti_ver) add_test( NAME ${TEST_PREFIX}_tool_ver COMMAND $ -ver) add_test( NAME ${TEST_PREFIX}_help COMMAND $ -help) add_test( NAME ${TEST_PREFIX}_nifti_hist COMMAND $ -nifti_hist) add_test( NAME ${TEST_PREFIX}_hist COMMAND $ -hist) add_test( NAME ${TEST_PREFIX}_disp_hdr COMMAND $ -disp_hdr -infiles ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/anat0.nii ) add_test( NAME ${TEST_PREFIX}_disp_nim COMMAND $ -disp_nim -infiles ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/anat0.nii ) add_test( NAME ${TEST_PREFIX}_disp_ext COMMAND $ -disp_ext -infiles ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/anat0.nii ) add_test( NAME ${TEST_PREFIX}_header_check COMMAND $ -check_hdr -infiles ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/anat0.nii ) add_test( NAME ${TEST_PREFIX}_nim_check COMMAND $ -check_nim -infiles ${fetch_testing_data_SOURCE_DIR}/nifti_regress_data/anat0.nii ) set_tests_properties(${TEST_PREFIX}_disp_hdr PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_disp_nim PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_disp_ext PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_header_check PROPERTIES LABELS NEEDS_DATA) set_tests_properties(${TEST_PREFIX}_nim_check PROPERTIES LABELS NEEDS_DATA) #The help screens always return 1; add_test( NAME ${NIFTI_PACKAGE_PREFIX}nifti1_tool1_help COMMAND $) add_test( NAME ${TEST_PREFIX}_tool_n1 COMMAND $ -disp_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/n1 ) add_test( NAME ${TEST_PREFIX}_tool_n2 COMMAND $ -disp_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/n2 ) add_test( NAME ${TEST_PREFIX}_tool_a2 COMMAND $ -disp_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/a2 ) add_test( NAME ${TEST_PREFIX}_tool_zn1 COMMAND $ -disp_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1 ) add_test( NAME ${TEST_PREFIX}_tool_zn2 COMMAND $ -disp_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/zn2 ) add_test( NAME ${TEST_PREFIX}_tool_za2 COMMAND $ -disp_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/za2 ) add_test( NAME ${TEST_PREFIX}_tool_diff_hdr COMMAND $ -diff_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1 ${CMAKE_CURRENT_BINARY_DIR}/zn1 ) add_test( NAME ${TEST_PREFIX}_tool_diff_nims COMMAND $ -diff_nim -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1 ${CMAKE_CURRENT_BINARY_DIR}/zn1 ) add_test( NAME ${TEST_PREFIX}_tool_copy_brick_list COMMAND $ -cbl -prefix cbl_zn1.nii -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz[0,1]) add_test( NAME ${TEST_PREFIX}_tool_disp_ci COMMAND $ -disp_ci 2 2 2 -1 0 0 0 -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz ) add_test( NAME ${TEST_PREFIX}_tool_disp_ts COMMAND $ -disp_ts 2 2 2 -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz ) add_test( NAME ${TEST_PREFIX}_tool_strip_extras COMMAND $ -strip_extras -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz ) # This test needs a file that has extensions to remove #add_test( NAME ${TEST_PREFIX}_tool_rm_ext /bin/sh ${NIFTI_SOURCE_DIR}/niftilib/rmthenrun rm_ext.nii COMMAND $ -rm_ext ALL -prefix rm_ext.nii -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz ) add_test( NAME ${TEST_PREFIX}_tool_check_hdr COMMAND $ -check_hdr -infile ${CMAKE_CURRENT_BINARY_DIR}/za2 ) add_test( NAME ${TEST_PREFIX}_tool_check_nim COMMAND $ -check_nim -infile ${CMAKE_CURRENT_BINARY_DIR}/za2 ) #add_test( NAME ${TEST_PREFIX}_tool_copy_collapsed_image /bin/sh ${NIFTI_SOURCE_DIR}/niftilib/rmthenrun cci_zn1.nii COMMAND $ -cci 2 2 2 -1 -1 -1 -1 -prefix cci_zn1.nii -infile ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz ) add_test( NAME cleanup_n1 COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/n1.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/n1.nii ) add_test( NAME cleanup_n2 COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/n2.nii ${CMAKE_CURRENT_BINARY_DIR}/n2.hdr ${CMAKE_CURRENT_BINARY_DIR}/n2.img) add_test( NAME cleanup_a2 COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/a2.img ${CMAKE_CURRENT_BINARY_DIR}/a2.hdr ) add_test( NAME cleanup_zn1 COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/zn1.nii.gz ${CMAKE_CURRENT_BINARY_DIR}/cbl_zn1.nii ) add_test( NAME cleanup_zn2 COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/zn2.img.gz ${CMAKE_CURRENT_BINARY_DIR}/zn2.hdr.gz ) add_test( NAME cleanup_za2 COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/za2.img.gz ${CMAKE_CURRENT_BINARY_DIR}/za2.hdr.gz ) # https://crascit.com/2016/10/18/test-fixtures-with-cmake-ctest/ as of cmake 3.7 fixtures are supported foreach( testsuffix "n1" "n2" "a2" "zn1" "zn2" "za2") #message(STATUS "Setting up ${testsuffix}") set_tests_properties( ${TEST_PREFIX}_tool_${testsuffix} PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_${testsuffix} ) set_tests_properties( ${TEST_PREFIX}_test_${testsuffix} PROPERTIES FIXTURES_SETUP NiftiTestGeneratedFiles_${testsuffix}) message(STATUS "NiftiTestGeneratedFiles_${testsuffix}" ) set_tests_properties( ${TEST_PREFIX}_tool_${testsuffix} ${TEST_PREFIX}_test_${testsuffix} PROPERTIES RESOURCE_LOCK Serial_${testsuffix} LABELS NEEDS_DATA ) set_tests_properties(cleanup_${testsuffix} PROPERTIES FIXTURES_CLEANUP NiftiTestGeneratedFiles_${testsuffix} ) endforeach() set_tests_properties( ${TEST_PREFIX}_tool_diff_hdr PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_zn1) set_tests_properties( ${TEST_PREFIX}_tool_diff_nims PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_zn1) set_tests_properties( ${TEST_PREFIX}_tool_copy_brick_list PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_zn1) set_tests_properties( ${TEST_PREFIX}_tool_disp_ci PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_zn1) set_tests_properties( ${TEST_PREFIX}_tool_disp_ts PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_zn1) set_tests_properties( ${TEST_PREFIX}_tool_strip_extras PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_zn1) set_tests_properties( ${TEST_PREFIX}_tool_check_hdr PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_za2 LABELS NEEDS_DATA) set_tests_properties( ${TEST_PREFIX}_tool_check_nim PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFiles_za2 LABELS NEEDS_DATA) #set_tests_properties( ${TEST_PREFIX}_tool_copy_collapsed_image PROPERTIES FIXTURES_REQUIRED NiftiTestGeneratedFileszn1) set_tests_properties( ${TEST_PREFIX}_tool_diff_hdr ${TEST_PREFIX}_tool_diff_nims ${TEST_PREFIX}_tool_copy_brick_list ${TEST_PREFIX}_tool_disp_ci ${TEST_PREFIX}_tool_disp_ts ${TEST_PREFIX}_tool_strip_extras PROPERTIES RESOURCE_LOCK Serial_zn1 LABELS NEEDS_DATA ) #==END NIFTI1 and NIFTI2 common tests ============================================ unset(TEST_SUFFIX) unset(TEST_PREFIX) unset(TOOL_NAME) endif() nifti_clib-3.0.1/niftilib/Makefile000066400000000000000000000025271371325713600170730ustar00rootroot00000000000000include ../Makefile PROJNAME = niftiio TAR ?= /bin/tar RM ?= /bin/rm INCFLAGS = $(ZLIB_INC) $(ZNZ_INC) LIBS = $(ZLIB_LIBS) $(ZNZ_LIBS) $(NIFTI_LIBS) SRCS=nifti1_io.c OBJS=nifti1_io.o MOBJS=mjtest.o SCRIPTS = depend: $(RM) -f depend.mk $(MAKE) depend.mk depend.mk: $(CC) $(DEPENDFLAGS) $(INCFLAGS) $(SRCS) >> depend.mk lib: libniftiio.a nifti1_io.o: nifti1_io.c nifti1_io.h $(CC) -c $(CFLAGS) $(USEZLIB) $(INCFLAGS) $< libniftiio.a: $(OBJS) $(AR) -r libniftiio.a $(OBJS) $(RANLIB) $@ nifti_tool: nifti_tool.c nifti_tool.h $(CC) $(CFLAGS) -Wall -o nifti_tool nifti_tool.c $(NIFTI_INCS) $(ZNZ_INCS) $(NIFTI_LIBS) $(ZNZ_LIBS) nifti1_test: nifti1_test.c $(CC) $(CFLAGS) -o nifti1_test nifti1_test.c $(NIFTI_INCS) $(ZNZ_INCS) $(NIFTI_LIBS) $(ZNZ_LIBS) # get the regression testing data tree regress_data: nifti_regress_test/nifti_regress_data # remove any result directories regress_clean: $(RM) -fr nifti_regress_test/results* # remove any result directories, and remove the data tree regress_clean_all: regress_clean $(RM) -fr nifti_regress_test/nifti_regress_data # download and unpack the regression data tree nifti_regress_test/nifti_regress_data: wget http://nifti.nimh.nih.gov/pub/dist/data/nifti_regress_data.tgz ( cd nifti_regress_test; $(TAR) -xzf ../nifti_regress_data.tgz; ) $(RM) nifti_regress_data.tgz include depend.mk nifti_clib-3.0.1/niftilib/nifti1.h000066400000000000000000002121151371325713600167720ustar00rootroot00000000000000/** \file nifti1.h \brief Official definition of the nifti1 header. Written by Bob Cox, SSCC, NIMH. HISTORY: 29 Nov 2007 [rickr] - added DT_RGBA32 and NIFTI_TYPE_RGBA32 - added NIFTI_INTENT codes: TIME_SERIES, NODE_INDEX, RGB_VECTOR, RGBA_VECTOR, SHAPE 08 Mar 2019 [PT,DRG] - Updated to include [qs]form_code = 5 */ #ifndef _NIFTI_HEADER_ #define _NIFTI_HEADER_ /***************************************************************************** ** This file defines the "NIFTI-1" header format. ** ** It is derived from 2 meetings at the NIH (31 Mar 2003 and ** ** 02 Sep 2003) of the Data Format Working Group (DFWG), ** ** chartered by the NIfTI (Neuroimaging Informatics Technology ** ** Initiative) at the National Institutes of Health (NIH). ** **--------------------------------------------------------------** ** Neither the National Institutes of Health (NIH), the DFWG, ** ** nor any of the members or employees of these institutions ** ** imply any warranty of usefulness of this material for any ** ** purpose, and do not assume any liability for damages, ** ** incidental or otherwise, caused by any use of this document. ** ** If these conditions are not acceptable, do not use this! ** **--------------------------------------------------------------** ** Author: Robert W Cox (NIMH, Bethesda) ** ** Advisors: John Ashburner (FIL, London), ** ** Stephen Smith (FMRIB, Oxford), ** ** Mark Jenkinson (FMRIB, Oxford) ** ******************************************************************************/ /*---------------------------------------------------------------------------*/ /* Note that the ANALYZE 7.5 file header (dbh.h) is (c) Copyright 1986-1995 Biomedical Imaging Resource Mayo Foundation Incorporation of components of dbh.h are by permission of the Mayo Foundation. Changes from the ANALYZE 7.5 file header in this file are released to the public domain, including the functional comments and any amusing asides. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /*! INTRODUCTION TO NIFTI-1: ------------------------ The twin (and somewhat conflicting) goals of this modified ANALYZE 7.5 format are: (a) To add information to the header that will be useful for functional neuroimaging data analysis and display. These additions include: - More basic data types. - Two affine transformations to specify voxel coordinates. - "Intent" codes and parameters to describe the meaning of the data. - Affine scaling of the stored data values to their "true" values. - Optional storage of the header and image data in one file (.nii). (b) To maintain compatibility with non-NIFTI-aware ANALYZE 7.5 compatible software (i.e., such a program should be able to do something useful with a NIFTI-1 dataset -- at least, with one stored in a traditional .img/.hdr file pair). Most of the unused fields in the ANALYZE 7.5 header have been taken, and some of the lesser-used fields have been co-opted for other purposes. Notably, most of the data_history substructure has been co-opted for other purposes, since the ANALYZE 7.5 format describes this substructure as "not required". NIFTI-1 FLAG (MAGIC STRINGS): ---------------------------- To flag such a struct as being conformant to the NIFTI-1 spec, the last 4 bytes of the header must be either the C String "ni1" or "n+1"; in hexadecimal, the 4 bytes 6E 69 31 00 or 6E 2B 31 00 (in any future version of this format, the '1' will be upgraded to '2', etc.). Normally, such a "magic number" or flag goes at the start of the file, but trying to avoid clobbering widely-used ANALYZE 7.5 fields led to putting this marker last. However, recall that "the last shall be first" (Matthew 20:16). If a NIFTI-aware program reads a header file that is NOT marked with a NIFTI magic string, then it should treat the header as an ANALYZE 7.5 structure. NIFTI-1 FILE STORAGE: -------------------- "ni1" means that the image data is stored in the ".img" file corresponding to the header file (starting at file offset 0). "n+1" means that the image data is stored in the same file as the header information. We recommend that the combined header+data filename suffix be ".nii". When the dataset is stored in one file, the first byte of image data is stored at byte location (int)vox_offset in this combined file. The minimum allowed value of vox_offset is 352; for compatibility with some software, vox_offset should be an integral multiple of 16. GRACE UNDER FIRE: ---------------- Most NIFTI-aware programs will only be able to handle a subset of the full range of datasets possible with this format. All NIFTI-aware programs should take care to check if an input dataset conforms to the program's needs and expectations (e.g., check datatype, intent_code, etc.). If the input dataset can't be handled by the program, the program should fail gracefully (e.g., print a useful warning; not crash). SAMPLE CODES: ------------ The associated files nifti1_io.h and nifti1_io.c provide a sample implementation in C of a set of functions to read, write, and manipulate NIFTI-1 files. The file nifti1_test.c is a sample program that uses the nifti1_io.c functions. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* HEADER STRUCT DECLARATION: ------------------------- In the comments below for each field, only NIFTI-1 specific requirements or changes from the ANALYZE 7.5 format are described. For convenience, the 348 byte header is described as a single struct, rather than as the ANALYZE 7.5 group of 3 substructs. Further comments about the interpretation of various elements of this header are after the data type definition itself. Fields that are marked as ++UNUSED++ have no particular interpretation in this standard. (Also see the UNUSED FIELDS comment section, far below.) The presumption below is that the various C types have particular sizes: sizeof(int) = sizeof(float) = 4 ; sizeof(short) = 2 -----------------------------------------------------------------------------*/ /*=================*/ #ifdef __cplusplus extern "C" { #endif /*=================*/ /*! \struct nifti_1_header \brief Data structure defining the fields in the nifti1 header. This binary header should be found at the beginning of a valid NIFTI-1 header file. */ /*************************/ /************************/ struct nifti_1_header { /* NIFTI-1 usage */ /* ANALYZE 7.5 field(s) */ /*************************/ /************************/ /*--- was header_key substruct ---*/ int sizeof_hdr; /*!< MUST be 348 */ /* int sizeof_hdr; */ char data_type[10]; /*!< ++UNUSED++ */ /* char data_type[10]; */ char db_name[18]; /*!< ++UNUSED++ */ /* char db_name[18]; */ int extents; /*!< ++UNUSED++ */ /* int extents; */ short session_error; /*!< ++UNUSED++ */ /* short session_error; */ char regular; /*!< ++UNUSED++ */ /* char regular; */ char dim_info; /*!< MRI slice ordering. */ /* char hkey_un0; */ /*--- was image_dimension substruct ---*/ short dim[8]; /*!< Data array dimensions.*/ /* short dim[8]; */ float intent_p1 ; /*!< 1st intent parameter. */ /* short unused8; */ /* short unused9; */ float intent_p2 ; /*!< 2nd intent parameter. */ /* short unused10; */ /* short unused11; */ float intent_p3 ; /*!< 3rd intent parameter. */ /* short unused12; */ /* short unused13; */ short intent_code ; /*!< NIFTI_INTENT_* code. */ /* short unused14; */ short datatype; /*!< Defines data type! */ /* short datatype; */ short bitpix; /*!< Number bits/voxel. */ /* short bitpix; */ short slice_start; /*!< First slice index. */ /* short dim_un0; */ float pixdim[8]; /*!< Grid spacings. */ /* float pixdim[8]; */ float vox_offset; /*!< Offset into .nii file */ /* float vox_offset; */ float scl_slope ; /*!< Data scaling: slope. */ /* float funused1; */ float scl_inter ; /*!< Data scaling: offset. */ /* float funused2; */ short slice_end; /*!< Last slice index. */ /* float funused3; */ char slice_code ; /*!< Slice timing order. */ char xyzt_units ; /*!< Units of pixdim[1..4] */ float cal_max; /*!< Max display intensity */ /* float cal_max; */ float cal_min; /*!< Min display intensity */ /* float cal_min; */ float slice_duration;/*!< Time for 1 slice. */ /* float compressed; */ float toffset; /*!< Time axis shift. */ /* float verified; */ int glmax; /*!< ++UNUSED++ */ /* int glmax; */ int glmin; /*!< ++UNUSED++ */ /* int glmin; */ /*--- was data_history substruct ---*/ char descrip[80]; /*!< any text you like. */ /* char descrip[80]; */ char aux_file[24]; /*!< auxiliary filename. */ /* char aux_file[24]; */ short qform_code ; /*!< NIFTI_XFORM_* code. */ /*-- all ANALYZE 7.5 ---*/ short sform_code ; /*!< NIFTI_XFORM_* code. */ /* fields below here */ /* are replaced */ float quatern_b ; /*!< Quaternion b param. */ float quatern_c ; /*!< Quaternion c param. */ float quatern_d ; /*!< Quaternion d param. */ float qoffset_x ; /*!< Quaternion x shift. */ float qoffset_y ; /*!< Quaternion y shift. */ float qoffset_z ; /*!< Quaternion z shift. */ float srow_x[4] ; /*!< 1st row affine transform. */ float srow_y[4] ; /*!< 2nd row affine transform. */ float srow_z[4] ; /*!< 3rd row affine transform. */ char intent_name[16];/*!< 'name' or meaning of data. */ char magic[4] ; /*!< MUST be "ni1\0" or "n+1\0". */ } ; /**** 348 bytes total ****/ typedef struct nifti_1_header nifti_1_header ; /*---------------------------------------------------------------------------*/ /* HEADER EXTENSIONS: ----------------- After the end of the 348 byte header (e.g., after the magic field), the next 4 bytes are a char array field named "extension". By default, all 4 bytes of this array should be set to zero. In a .nii file, these 4 bytes will always be present, since the earliest start point for the image data is byte #352. In a separate .hdr file, these bytes may or may not be present. If not present (i.e., if the length of the .hdr file is 348 bytes), then a NIfTI-1 compliant program should use the default value of extension={0,0,0,0}. The first byte (extension[0]) is the only value of this array that is specified at present. The other 3 bytes are reserved for future use. If extension[0] is nonzero, it indicates that extended header information is present in the bytes following the extension array. In a .nii file, this extended header data is before the image data (and vox_offset must be set correctly to allow for this). In a .hdr file, this extended data follows extension and proceeds (potentially) to the end of the file. The format of extended header data is weakly specified. Each extension must be an integer multiple of 16 bytes long. The first 8 bytes of each extension comprise 2 integers: int esize , ecode ; These values may need to be byte-swapped, as indicated by dim[0] for the rest of the header. * esize is the number of bytes that form the extended header data + esize must be a positive integral multiple of 16 + this length includes the 8 bytes of esize and ecode themselves * ecode is a non-negative integer that indicates the format of the extended header data that follows + different ecode values are assigned to different developer groups + at present, the "registered" values for code are = 0 = unknown private format (not recommended!) = 2 = DICOM format (i.e., attribute tags and values) = 4 = AFNI group (i.e., ASCII XML-ish elements) In the interests of interoperability (a primary rationale for NIfTI), groups developing software that uses this extension mechanism are encouraged to document and publicize the format of their extensions. To this end, the NIfTI DFWG will assign even numbered codes upon request to groups submitting at least rudimentary documentation for the format of their extension; at present, the contact is mailto:rwcox@nih.gov. The assigned codes and documentation will be posted on the NIfTI website. All odd values of ecode (and 0) will remain unassigned; at least, until the even ones are used up, when we get to 2,147,483,646. Note that the other contents of the extended header data section are totally unspecified by the NIfTI-1 standard. In particular, if binary data is stored in such a section, its byte order is not necessarily the same as that given by examining dim[0]; it is incumbent on the programs dealing with such data to determine the byte order of binary extended header data. Multiple extended header sections are allowed, each starting with an esize,ecode value pair. The first esize value, as described above, is at bytes #352-355 in the .hdr or .nii file (files start at byte #0). If this value is positive, then the second (esize2) will be found starting at byte #352+esize1 , the third (esize3) at byte #352+esize1+esize2, et cetera. Of course, in a .nii file, the value of vox_offset must be compatible with these extensions. If a malformed file indicates that an extended header data section would run past vox_offset, then the entire extended header section should be ignored. In a .hdr file, if an extended header data section would run past the end-of-file, that extended header data should also be ignored. With the above scheme, a program can successively examine the esize and ecode values, and skip over each extended header section if the program doesn't know how to interpret the data within. Of course, any program can simply ignore all extended header sections simply by jumping straight to the image data using vox_offset. -----------------------------------------------------------------------------*/ /*! \struct nifti1_extender \brief This structure represents a 4-byte string that should follow the binary nifti_1_header data in a NIFTI-1 header file. If the char values are {1,0,0,0}, the file is expected to contain extensions, values of {0,0,0,0} imply the file does not contain extensions. Other sequences of values are not currently defined. */ struct nifti1_extender { char extension[4] ; } ; typedef struct nifti1_extender nifti1_extender ; /*! \struct nifti1_extension \brief Data structure defining the fields of a header extension. */ struct nifti1_extension { int esize ; /*!< size of extension, in bytes (must be multiple of 16) */ int ecode ; /*!< extension code, one of the NIFTI_ECODE_ values */ char * edata ; /*!< raw data, with no byte swapping (length is esize-8) */ } ; typedef struct nifti1_extension nifti1_extension ; /*---------------------------------------------------------------------------*/ /* DATA DIMENSIONALITY (as in ANALYZE 7.5): --------------------------------------- dim[0] = number of dimensions; - if dim[0] is outside range 1..7, then the header information needs to be byte swapped appropriately - ANALYZE supports dim[0] up to 7, but NIFTI-1 reserves dimensions 1,2,3 for space (x,y,z), 4 for time (t), and 5,6,7 for anything else needed. dim[i] = length of dimension #i, for i=1..dim[0] (must be positive) - also see the discussion of intent_code, far below pixdim[i] = voxel width along dimension #i, i=1..dim[0] (positive) - cf. ORIENTATION section below for use of pixdim[0] - the units of pixdim can be specified with the xyzt_units field (also described far below). Number of bits per voxel value is in bitpix, which MUST correspond with the datatype field. The total number of bytes in the image data is dim[1] * ... * dim[dim[0]] * bitpix / 8 In NIFTI-1 files, dimensions 1,2,3 are for space, dimension 4 is for time, and dimension 5 is for storing multiple values at each spatiotemporal voxel. Some examples: - A typical whole-brain FMRI experiment's time series: - dim[0] = 4 - dim[1] = 64 pixdim[1] = 3.75 xyzt_units = NIFTI_UNITS_MM - dim[2] = 64 pixdim[2] = 3.75 | NIFTI_UNITS_SEC - dim[3] = 20 pixdim[3] = 5.0 - dim[4] = 120 pixdim[4] = 2.0 - A typical T1-weighted anatomical volume: - dim[0] = 3 - dim[1] = 256 pixdim[1] = 1.0 xyzt_units = NIFTI_UNITS_MM - dim[2] = 256 pixdim[2] = 1.0 - dim[3] = 128 pixdim[3] = 1.1 - A single slice EPI time series: - dim[0] = 4 - dim[1] = 64 pixdim[1] = 3.75 xyzt_units = NIFTI_UNITS_MM - dim[2] = 64 pixdim[2] = 3.75 | NIFTI_UNITS_SEC - dim[3] = 1 pixdim[3] = 5.0 - dim[4] = 1200 pixdim[4] = 0.2 - A 3-vector stored at each point in a 3D volume: - dim[0] = 5 - dim[1] = 256 pixdim[1] = 1.0 xyzt_units = NIFTI_UNITS_MM - dim[2] = 256 pixdim[2] = 1.0 - dim[3] = 128 pixdim[3] = 1.1 - dim[4] = 1 pixdim[4] = 0.0 - dim[5] = 3 intent_code = NIFTI_INTENT_VECTOR - A single time series with a 3x3 matrix at each point: - dim[0] = 5 - dim[1] = 1 xyzt_units = NIFTI_UNITS_SEC - dim[2] = 1 - dim[3] = 1 - dim[4] = 1200 pixdim[4] = 0.2 - dim[5] = 9 intent_code = NIFTI_INTENT_GENMATRIX - intent_p1 = intent_p2 = 3.0 (indicates matrix dimensions) -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* DATA STORAGE: ------------ If the magic field is "n+1", then the voxel data is stored in the same file as the header. In this case, the voxel data starts at offset (int)vox_offset into the header file. Thus, vox_offset=352.0 means that the data starts immediately after the NIFTI-1 header. If vox_offset is greater than 352, the NIFTI-1 format does not say much about the contents of the dataset file between the end of the header and the start of the data. FILES: ----- If the magic field is "ni1", then the voxel data is stored in the associated ".img" file, starting at offset 0 (i.e., vox_offset is not used in this case, and should be set to 0.0). When storing NIFTI-1 datasets in pairs of files, it is customary to name the files in the pattern "name.hdr" and "name.img", as in ANALYZE 7.5. When storing in a single file ("n+1"), the file name should be in the form "name.nii" (the ".nft" and ".nif" suffixes are already taken; cf. http://www.icdatamaster.com/n.html ). BYTE ORDERING: ------------- The byte order of the data arrays is presumed to be the same as the byte order of the header (which is determined by examining dim[0]). Floating point types are presumed to be stored in IEEE-754 format. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* DETAILS ABOUT vox_offset: ------------------------ In a .nii file, the vox_offset field value is interpreted as the start location of the image data bytes in that file. In a .hdr/.img file pair, the vox_offset field value is the start location of the image data bytes in the .img file. * If vox_offset is less than 352 in a .nii file, it is equivalent to 352 (i.e., image data never starts before byte #352 in a .nii file). * The default value for vox_offset in a .nii file is 352. * In a .hdr file, the default value for vox_offset is 0. * vox_offset should be an integer multiple of 16; otherwise, some programs may not work properly (e.g., SPM). This is to allow memory-mapped input to be properly byte-aligned. Note that since vox_offset is an IEEE-754 32 bit float (for compatibility with the ANALYZE-7.5 format), it effectively has a 24 bit mantissa. All integers from 0 to 2^24 can be represented exactly in this format, but not all larger integers are exactly storable as IEEE-754 32 bit floats. However, unless you plan to have vox_offset be potentially larger than 16 MB, this should not be an issue. (Actually, any integral multiple of 16 up to 2^27 can be represented exactly in this format, which allows for up to 128 MB of random information before the image data. If that isn't enough, then perhaps this format isn't right for you.) In a .img file (i.e., image data stored separately from the NIfTI-1 header), data bytes between #0 and #vox_offset-1 (inclusive) are completely undefined and unregulated by the NIfTI-1 standard. One potential use of having vox_offset > 0 in the .hdr/.img file pair storage method is to make the .img file be a copy of (or link to) a pre-existing image file in some other format, such as DICOM; then vox_offset would be set to the offset of the image data in this file. (It may not be possible to follow the "multiple-of-16 rule" with an arbitrary external file; using the NIfTI-1 format in such a case may lead to a file that is incompatible with software that relies on vox_offset being a multiple of 16.) In a .nii file, data bytes between #348 and #vox_offset-1 (inclusive) may be used to store user-defined extra information; similarly, in a .hdr file, any data bytes after byte #347 are available for user-defined extra information. The (very weak) regulation of this extra header data is described elsewhere. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* DATA SCALING: ------------ If the scl_slope field is nonzero, then each voxel value in the dataset should be scaled as y = scl_slope * x + scl_inter where x = voxel value stored y = "true" voxel value Normally, we would expect this scaling to be used to store "true" floating values in a smaller integer datatype, but that is not required. That is, it is legal to use scaling even if the datatype is a float type (crazy, perhaps, but legal). - However, the scaling is to be ignored if datatype is DT_RGB24. - If datatype is a complex type, then the scaling is to be applied to both the real and imaginary parts. The cal_min and cal_max fields (if nonzero) are used for mapping (possibly scaled) dataset values to display colors: - Minimum display intensity (black) corresponds to dataset value cal_min. - Maximum display intensity (white) corresponds to dataset value cal_max. - Dataset values below cal_min should display as black also, and values above cal_max as white. - Colors "black" and "white", of course, may refer to any scalar display scheme (e.g., a color lookup table specified via aux_file). - cal_min and cal_max only make sense when applied to scalar-valued datasets (i.e., dim[0] < 5 or dim[5] = 1). -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* TYPE OF DATA (acceptable values for datatype field): --------------------------------------------------- Values of datatype smaller than 256 are ANALYZE 7.5 compatible. Larger values are NIFTI-1 additions. These are all multiples of 256, so that no bits below position 8 are set in datatype. But there is no need to use only powers-of-2, as the original ANALYZE 7.5 datatype codes do. The additional codes are intended to include a complete list of basic scalar types, including signed and unsigned integers from 8 to 64 bits, floats from 32 to 128 bits, and complex (float pairs) from 64 to 256 bits. Note that most programs will support only a few of these datatypes! A NIFTI-1 program should fail gracefully (e.g., print a warning message) when it encounters a dataset with a type it doesn't like. -----------------------------------------------------------------------------*/ #undef DT_UNKNOWN /* defined in dirent.h on some Unix systems */ /*! \defgroup NIFTI1_DATATYPES \brief nifti1 datatype codes @{ */ /*--- the original ANALYZE 7.5 type codes ---*/ #define DT_NONE 0 #define DT_UNKNOWN 0 /* what it says, dude */ #define DT_BINARY 1 /* binary (1 bit/voxel) */ #define DT_UNSIGNED_CHAR 2 /* unsigned char (8 bits/voxel) */ #define DT_SIGNED_SHORT 4 /* signed short (16 bits/voxel) */ #define DT_SIGNED_INT 8 /* signed int (32 bits/voxel) */ #define DT_FLOAT 16 /* float (32 bits/voxel) */ #define DT_COMPLEX 32 /* complex (64 bits/voxel) */ #define DT_DOUBLE 64 /* double (64 bits/voxel) */ #define DT_RGB 128 /* RGB triple (24 bits/voxel) */ #define DT_ALL 255 /* not very useful (?) */ /*----- another set of names for the same ---*/ #define DT_UINT8 2 #define DT_INT16 4 #define DT_INT32 8 #define DT_FLOAT32 16 #define DT_COMPLEX64 32 #define DT_FLOAT64 64 #define DT_RGB24 128 /*------------------- new codes for NIFTI ---*/ #define DT_INT8 256 /* signed char (8 bits) */ #define DT_UINT16 512 /* unsigned short (16 bits) */ #define DT_UINT32 768 /* unsigned int (32 bits) */ #define DT_INT64 1024 /* long long (64 bits) */ #define DT_UINT64 1280 /* unsigned long long (64 bits) */ #define DT_FLOAT128 1536 /* long double (128 bits) */ #define DT_COMPLEX128 1792 /* double pair (128 bits) */ #define DT_COMPLEX256 2048 /* long double pair (256 bits) */ #define DT_RGBA32 2304 /* 4 byte RGBA (32 bits/voxel) */ /* @} */ /*------- aliases for all the above codes ---*/ /*! \defgroup NIFTI1_DATATYPE_ALIASES \brief aliases for the nifti1 datatype codes @{ */ /*! unsigned char. */ #define NIFTI_TYPE_UINT8 2 /*! signed short. */ #define NIFTI_TYPE_INT16 4 /*! signed int. */ #define NIFTI_TYPE_INT32 8 /*! 32 bit float. */ #define NIFTI_TYPE_FLOAT32 16 /*! 64 bit complex = 2 32 bit floats. */ #define NIFTI_TYPE_COMPLEX64 32 /*! 64 bit float = double. */ #define NIFTI_TYPE_FLOAT64 64 /*! 3 8 bit bytes. */ #define NIFTI_TYPE_RGB24 128 /*! signed char. */ #define NIFTI_TYPE_INT8 256 /*! unsigned short. */ #define NIFTI_TYPE_UINT16 512 /*! unsigned int. */ #define NIFTI_TYPE_UINT32 768 /*! signed long long. */ #define NIFTI_TYPE_INT64 1024 /*! unsigned long long. */ #define NIFTI_TYPE_UINT64 1280 /*! 128 bit float = long double. */ #define NIFTI_TYPE_FLOAT128 1536 /*! 128 bit complex = 2 64 bit floats. */ #define NIFTI_TYPE_COMPLEX128 1792 /*! 256 bit complex = 2 128 bit floats */ #define NIFTI_TYPE_COMPLEX256 2048 /*! 4 8 bit bytes. */ #define NIFTI_TYPE_RGBA32 2304 /* @} */ /*-------- sample typedefs for complicated types ---*/ #if 0 typedef struct { float r,i; } complex_float ; typedef struct { double r,i; } complex_double ; typedef struct { long double r,i; } complex_longdouble ; typedef struct { unsigned char r,g,b; } rgb_byte ; #endif /*---------------------------------------------------------------------------*/ /* INTERPRETATION OF VOXEL DATA: ---------------------------- The intent_code field can be used to indicate that the voxel data has some particular meaning. In particular, a large number of codes is given to indicate that the the voxel data should be interpreted as being drawn from a given probability distribution. VECTOR-VALUED DATASETS: ---------------------- The 5th dimension of the dataset, if present (i.e., dim[0]=5 and dim[5] > 1), contains multiple values (e.g., a vector) to be stored at each spatiotemporal location. For example, the header values - dim[0] = 5 - dim[1] = 64 - dim[2] = 64 - dim[3] = 20 - dim[4] = 1 (indicates no time axis) - dim[5] = 3 - datatype = DT_FLOAT - intent_code = NIFTI_INTENT_VECTOR mean that this dataset should be interpreted as a 3D volume (64x64x20), with a 3-vector of floats defined at each point in the 3D grid. A program reading a dataset with a 5th dimension may want to reformat the image data to store each voxels' set of values together in a struct or array. This programming detail, however, is beyond the scope of the NIFTI-1 file specification! Uses of dimensions 6 and 7 are also not specified here. STATISTICAL PARAMETRIC DATASETS (i.e., SPMs): -------------------------------------------- Values of intent_code from NIFTI_FIRST_STATCODE to NIFTI_LAST_STATCODE (inclusive) indicate that the numbers in the dataset should be interpreted as being drawn from a given distribution. Most such distributions have auxiliary parameters (e.g., NIFTI_INTENT_TTEST has 1 DOF parameter). If the dataset DOES NOT have a 5th dimension, then the auxiliary parameters are the same for each voxel, and are given in header fields intent_p1, intent_p2, and intent_p3. If the dataset DOES have a 5th dimension, then the auxiliary parameters are different for each voxel. For example, the header values - dim[0] = 5 - dim[1] = 128 - dim[2] = 128 - dim[3] = 1 (indicates a single slice) - dim[4] = 1 (indicates no time axis) - dim[5] = 2 - datatype = DT_FLOAT - intent_code = NIFTI_INTENT_TTEST mean that this is a 2D dataset (128x128) of t-statistics, with the t-statistic being in the first "plane" of data and the degrees-of-freedom parameter being in the second "plane" of data. If the dataset 5th dimension is used to store the voxel-wise statistical parameters, then dim[5] must be 1 plus the number of parameters required by that distribution (e.g., intent_code=NIFTI_INTENT_TTEST implies dim[5] must be 2, as in the example just above). Note: intent_code values 2..10 are compatible with AFNI 1.5x (which is why there is no code with value=1, which is obsolescent in AFNI). OTHER INTENTIONS: ---------------- The purpose of the intent_* fields is to help interpret the values stored in the dataset. Some non-statistical values for intent_code and conventions are provided for storing other complex data types. The intent_name field provides space for a 15 character (plus 0 byte) 'name' string for the type of data stored. Examples: - intent_code = NIFTI_INTENT_ESTIMATE; intent_name = "T1"; could be used to signify that the voxel values are estimates of the NMR parameter T1. - intent_code = NIFTI_INTENT_TTEST; intent_name = "House"; could be used to signify that the voxel values are t-statistics for the significance of 'activation' response to a House stimulus. - intent_code = NIFTI_INTENT_DISPVECT; intent_name = "ToMNI152"; could be used to signify that the voxel values are a displacement vector that transforms each voxel (x,y,z) location to the corresponding location in the MNI152 standard brain. - intent_code = NIFTI_INTENT_SYMMATRIX; intent_name = "DTI"; could be used to signify that the voxel values comprise a diffusion tensor image. If no data name is implied or needed, intent_name[0] should be set to 0. -----------------------------------------------------------------------------*/ /*! default: no intention is indicated in the header. */ #define NIFTI_INTENT_NONE 0 /*-------- These codes are for probability distributions ---------------*/ /* Most distributions have a number of parameters, below denoted by p1, p2, and p3, and stored in - intent_p1, intent_p2, intent_p3 if dataset doesn't have 5th dimension - image data array if dataset does have 5th dimension Functions to compute with many of the distributions below can be found in the CDF library from U Texas. Formulas for and discussions of these distributions can be found in the following books: [U] Univariate Discrete Distributions, NL Johnson, S Kotz, AW Kemp. [C1] Continuous Univariate Distributions, vol. 1, NL Johnson, S Kotz, N Balakrishnan. [C2] Continuous Univariate Distributions, vol. 2, NL Johnson, S Kotz, N Balakrishnan. */ /*----------------------------------------------------------------------*/ /*! [C2, chap 32] Correlation coefficient R (1 param): p1 = degrees of freedom R/sqrt(1-R*R) is t-distributed with p1 DOF. */ /*! \defgroup NIFTI1_INTENT_CODES \brief nifti1 intent codes, to describe intended meaning of dataset contents @{ */ #define NIFTI_INTENT_CORREL 2 /*! [C2, chap 28] Student t statistic (1 param): p1 = DOF. */ #define NIFTI_INTENT_TTEST 3 /*! [C2, chap 27] Fisher F statistic (2 params): p1 = numerator DOF, p2 = denominator DOF. */ #define NIFTI_INTENT_FTEST 4 /*! [C1, chap 13] Standard normal (0 params): Density = N(0,1). */ #define NIFTI_INTENT_ZSCORE 5 /*! [C1, chap 18] Chi-squared (1 param): p1 = DOF. Density(x) proportional to exp(-x/2) * x^(p1/2-1). */ #define NIFTI_INTENT_CHISQ 6 /*! [C2, chap 25] Beta distribution (2 params): p1=a, p2=b. Density(x) proportional to x^(a-1) * (1-x)^(b-1). */ #define NIFTI_INTENT_BETA 7 /*! [U, chap 3] Binomial distribution (2 params): p1 = number of trials, p2 = probability per trial. Prob(x) = (p1 choose x) * p2^x * (1-p2)^(p1-x), for x=0,1,...,p1. */ #define NIFTI_INTENT_BINOM 8 /*! [C1, chap 17] Gamma distribution (2 params): p1 = shape, p2 = scale. Density(x) proportional to x^(p1-1) * exp(-p2*x). */ #define NIFTI_INTENT_GAMMA 9 /*! [U, chap 4] Poisson distribution (1 param): p1 = mean. Prob(x) = exp(-p1) * p1^x / x! , for x=0,1,2,.... */ #define NIFTI_INTENT_POISSON 10 /*! [C1, chap 13] Normal distribution (2 params): p1 = mean, p2 = standard deviation. */ #define NIFTI_INTENT_NORMAL 11 /*! [C2, chap 30] Noncentral F statistic (3 params): p1 = numerator DOF, p2 = denominator DOF, p3 = numerator noncentrality parameter. */ #define NIFTI_INTENT_FTEST_NONC 12 /*! [C2, chap 29] Noncentral chi-squared statistic (2 params): p1 = DOF, p2 = noncentrality parameter. */ #define NIFTI_INTENT_CHISQ_NONC 13 /*! [C2, chap 23] Logistic distribution (2 params): p1 = location, p2 = scale. Density(x) proportional to sech^2((x-p1)/(2*p2)). */ #define NIFTI_INTENT_LOGISTIC 14 /*! [C2, chap 24] Laplace distribution (2 params): p1 = location, p2 = scale. Density(x) proportional to exp(-abs(x-p1)/p2). */ #define NIFTI_INTENT_LAPLACE 15 /*! [C2, chap 26] Uniform distribution: p1 = lower end, p2 = upper end. */ #define NIFTI_INTENT_UNIFORM 16 /*! [C2, chap 31] Noncentral t statistic (2 params): p1 = DOF, p2 = noncentrality parameter. */ #define NIFTI_INTENT_TTEST_NONC 17 /*! [C1, chap 21] Weibull distribution (3 params): p1 = location, p2 = scale, p3 = power. Density(x) proportional to ((x-p1)/p2)^(p3-1) * exp(-((x-p1)/p2)^p3) for x > p1. */ #define NIFTI_INTENT_WEIBULL 18 /*! [C1, chap 18] Chi distribution (1 param): p1 = DOF. Density(x) proportional to x^(p1-1) * exp(-x^2/2) for x > 0. p1 = 1 = 'half normal' distribution p1 = 2 = Rayleigh distribution p1 = 3 = Maxwell-Boltzmann distribution. */ #define NIFTI_INTENT_CHI 19 /*! [C1, chap 15] Inverse Gaussian (2 params): p1 = mu, p2 = lambda Density(x) proportional to exp(-p2*(x-p1)^2/(2*p1^2*x)) / x^3 for x > 0. */ #define NIFTI_INTENT_INVGAUSS 20 /*! [C2, chap 22] Extreme value type I (2 params): p1 = location, p2 = scale cdf(x) = exp(-exp(-(x-p1)/p2)). */ #define NIFTI_INTENT_EXTVAL 21 /*! Data is a 'p-value' (no params). */ #define NIFTI_INTENT_PVAL 22 /*! Data is ln(p-value) (no params). To be safe, a program should compute p = exp(-abs(this_value)). The nifti_stats.c library returns this_value as positive, so that this_value = -log(p). */ #define NIFTI_INTENT_LOGPVAL 23 /*! Data is log10(p-value) (no params). To be safe, a program should compute p = pow(10.,-abs(this_value)). The nifti_stats.c library returns this_value as positive, so that this_value = -log10(p). */ #define NIFTI_INTENT_LOG10PVAL 24 /*! Smallest intent_code that indicates a statistic. */ #define NIFTI_FIRST_STATCODE 2 /*! Largest intent_code that indicates a statistic. */ #define NIFTI_LAST_STATCODE 24 /*---------- these values for intent_code aren't for statistics ----------*/ /*! To signify that the value at each voxel is an estimate of some parameter, set intent_code = NIFTI_INTENT_ESTIMATE. The name of the parameter may be stored in intent_name. */ #define NIFTI_INTENT_ESTIMATE 1001 /*! To signify that the value at each voxel is an index into some set of labels, set intent_code = NIFTI_INTENT_LABEL. The filename with the labels may stored in aux_file. */ #define NIFTI_INTENT_LABEL 1002 /*! To signify that the value at each voxel is an index into the NeuroNames labels set, set intent_code = NIFTI_INTENT_NEURONAME. */ #define NIFTI_INTENT_NEURONAME 1003 /*! To store an M x N matrix at each voxel: - dataset must have a 5th dimension (dim[0]=5 and dim[5]>1) - intent_code must be NIFTI_INTENT_GENMATRIX - dim[5] must be M*N - intent_p1 must be M (in float format) - intent_p2 must be N (ditto) - the matrix values A[i][[j] are stored in row-order: - A[0][0] A[0][1] ... A[0][N-1] - A[1][0] A[1][1] ... A[1][N-1] - etc., until - A[M-1][0] A[M-1][1] ... A[M-1][N-1] */ #define NIFTI_INTENT_GENMATRIX 1004 /*! To store an NxN symmetric matrix at each voxel: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_SYMMATRIX - dim[5] must be N*(N+1)/2 - intent_p1 must be N (in float format) - the matrix values A[i][[j] are stored in row-order: - A[0][0] - A[1][0] A[1][1] - A[2][0] A[2][1] A[2][2] - etc.: row-by-row */ #define NIFTI_INTENT_SYMMATRIX 1005 /*! To signify that the vector value at each voxel is to be taken as a displacement field or vector: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_DISPVECT - dim[5] must be the dimensionality of the displacment vector (e.g., 3 for spatial displacement, 2 for in-plane) */ #define NIFTI_INTENT_DISPVECT 1006 /* specifically for displacements */ #define NIFTI_INTENT_VECTOR 1007 /* for any other type of vector */ /*! To signify that the vector value at each voxel is really a spatial coordinate (e.g., the vertices or nodes of a surface mesh): - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_POINTSET - dim[0] = 5 - dim[1] = number of points - dim[2] = dim[3] = dim[4] = 1 - dim[5] must be the dimensionality of space (e.g., 3 => 3D space). - intent_name may describe the object these points come from (e.g., "pial", "gray/white" , "EEG", "MEG"). */ #define NIFTI_INTENT_POINTSET 1008 /*! To signify that the vector value at each voxel is really a triple of indexes (e.g., forming a triangle) from a pointset dataset: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_TRIANGLE - dim[0] = 5 - dim[1] = number of triangles - dim[2] = dim[3] = dim[4] = 1 - dim[5] = 3 - datatype should be an integer type (preferably DT_INT32) - the data values are indexes (0,1,...) into a pointset dataset. */ #define NIFTI_INTENT_TRIANGLE 1009 /*! To signify that the vector value at each voxel is a quaternion: - dataset must have a 5th dimension - intent_code must be NIFTI_INTENT_QUATERNION - dim[0] = 5 - dim[5] = 4 - datatype should be a floating point type */ #define NIFTI_INTENT_QUATERNION 1010 /*! Dimensionless value - no params - although, as in _ESTIMATE the name of the parameter may be stored in intent_name. */ #define NIFTI_INTENT_DIMLESS 1011 /*---------- these values apply to GIFTI datasets ----------*/ /*! To signify that the value at each location is from a time series. */ #define NIFTI_INTENT_TIME_SERIES 2001 /*! To signify that the value at each location is a node index, from a complete surface dataset. */ #define NIFTI_INTENT_NODE_INDEX 2002 /*! To signify that the vector value at each location is an RGB triplet, of whatever type. - dataset must have a 5th dimension - dim[0] = 5 - dim[1] = number of nodes - dim[2] = dim[3] = dim[4] = 1 - dim[5] = 3 */ #define NIFTI_INTENT_RGB_VECTOR 2003 /*! To signify that the vector value at each location is a 4 valued RGBA vector, of whatever type. - dataset must have a 5th dimension - dim[0] = 5 - dim[1] = number of nodes - dim[2] = dim[3] = dim[4] = 1 - dim[5] = 4 */ #define NIFTI_INTENT_RGBA_VECTOR 2004 /*! To signify that the value at each location is a shape value, such as the curvature. */ #define NIFTI_INTENT_SHAPE 2005 /*! The following intent codes have been used by FSL FNIRT for displacement/coefficient files. These codes are included to prevent clashes in community-created extensions to NIfTI. Encoding and decoding behavior for these intents is not specified by the standard, and support is OPTIONAL for conforming implementations. */ #define NIFTI_INTENT_FSL_FNIRT_DISPLACEMENT_FIELD 2006 #define NIFTI_INTENT_FSL_CUBIC_SPLINE_COEFFICIENTS 2007 #define NIFTI_INTENT_FSL_DCT_COEFFICIENTS 2008 #define NIFTI_INTENT_FSL_QUADRATIC_SPLINE_COEFFICIENTS 2009 /*! The following intent codes have been used by FSL TOPUP for displacement/coefficient files. These codes are included to prevent clashes in community-created extensions to NIfTI. Encoding and decoding behavior for these intents is not specified by the standard, and support is OPTIONAL for conforming implementations. */ #define NIFTI_INTENT_FSL_TOPUP_CUBIC_SPLINE_COEFFICIENTS 2016 #define NIFTI_INTENT_FSL_TOPUP_QUADRATIC_SPLINE_COEFFICIENTS 2017 #define NIFTI_INTENT_FSL_TOPUP_FIELD 2018 /* @} */ /*---------------------------------------------------------------------------*/ /* 3D IMAGE (VOLUME) ORIENTATION AND LOCATION IN SPACE: --------------------------------------------------- There are 3 different methods by which continuous coordinates can attached to voxels. The discussion below emphasizes 3D volumes, and the continuous coordinates are referred to as (x,y,z). The voxel index coordinates (i.e., the array indexes) are referred to as (i,j,k), with valid ranges: i = 0 .. dim[1]-1 j = 0 .. dim[2]-1 (if dim[0] >= 2) k = 0 .. dim[3]-1 (if dim[0] >= 3) The (x,y,z) coordinates refer to the CENTER of a voxel. In methods 2 and 3, the (x,y,z) axes refer to a subject-based coordinate system, with +x = Right +y = Anterior +z = Superior. This is a right-handed coordinate system. However, the exact direction these axes point with respect to the subject depends on qform_code (Method 2) and sform_code (Method 3). N.B.: The i index varies most rapidly, j index next, k index slowest. Thus, voxel (i,j,k) is stored starting at location (i + j*dim[1] + k*dim[1]*dim[2]) * (bitpix/8) into the dataset array. N.B.: The ANALYZE 7.5 coordinate system is +x = Left +y = Anterior +z = Superior which is a left-handed coordinate system. This backwardness is too difficult to tolerate, so this NIFTI-1 standard specifies the coordinate order which is most common in functional neuroimaging. N.B.: The 3 methods below all give the locations of the voxel centers in the (x,y,z) coordinate system. In many cases, programs will wish to display image data on some other grid. In such a case, the program will need to convert its desired (x,y,z) values into (i,j,k) values in order to extract (or interpolate) the image data. This operation would be done with the inverse transformation to those described below. N.B.: Method 2 uses a factor 'qfac' which is either -1 or 1; qfac is stored in the otherwise unused pixdim[0]. If pixdim[0]=0.0 (which should not occur), we take qfac=1. Of course, pixdim[0] is only used when reading a NIFTI-1 header, not when reading an ANALYZE 7.5 header. N.B.: The units of (x,y,z) can be specified using the xyzt_units field. METHOD 1 (the "old" way, used only when qform_code = 0): ------------------------------------------------------- The coordinate mapping from (i,j,k) to (x,y,z) is the ANALYZE 7.5 way. This is a simple scaling relationship: x = pixdim[1] * i y = pixdim[2] * j z = pixdim[3] * k No particular spatial orientation is attached to these (x,y,z) coordinates. (NIFTI-1 does not have the ANALYZE 7.5 orient field, which is not general and is often not set properly.) This method is not recommended, and is present mainly for compatibility with ANALYZE 7.5 files. METHOD 2 (used when qform_code > 0, which should be the "normal" case): --------------------------------------------------------------------- The (x,y,z) coordinates are given by the pixdim[] scales, a rotation matrix, and a shift. This method is intended to represent "scanner-anatomical" coordinates, which are often embedded in the image header (e.g., DICOM fields (0020,0032), (0020,0037), (0028,0030), and (0018,0050)), and represent the nominal orientation and location of the data. This method can also be used to represent "aligned" coordinates, which would typically result from some post-acquisition alignment of the volume to a standard orientation (e.g., the same subject on another day, or a rigid rotation to true anatomical orientation from the tilted position of the subject in the scanner). The formula for (x,y,z) in terms of header parameters and (i,j,k) is: [ x ] [ R11 R12 R13 ] [ pixdim[1] * i ] [ qoffset_x ] [ y ] = [ R21 R22 R23 ] [ pixdim[2] * j ] + [ qoffset_y ] [ z ] [ R31 R32 R33 ] [ qfac * pixdim[3] * k ] [ qoffset_z ] The qoffset_* shifts are in the NIFTI-1 header. Note that the center of the (i,j,k)=(0,0,0) voxel (first value in the dataset array) is just (x,y,z)=(qoffset_x,qoffset_y,qoffset_z). The rotation matrix R is calculated from the quatern_* parameters. This calculation is described below. The scaling factor qfac is either 1 or -1. The rotation matrix R defined by the quaternion parameters is "proper" (has determinant 1). This may not fit the needs of the data; for example, if the image grid is i increases from Left-to-Right j increases from Anterior-to-Posterior k increases from Inferior-to-Superior Then (i,j,k) is a left-handed triple. In this example, if qfac=1, the R matrix would have to be [ 1 0 0 ] [ 0 -1 0 ] which is "improper" (determinant = -1). [ 0 0 1 ] If we set qfac=-1, then the R matrix would be [ 1 0 0 ] [ 0 -1 0 ] which is proper. [ 0 0 -1 ] This R matrix is represented by quaternion [a,b,c,d] = [0,1,0,0] (which encodes a 180 degree rotation about the x-axis). METHOD 3 (used when sform_code > 0): ----------------------------------- The (x,y,z) coordinates are given by a general affine transformation of the (i,j,k) indexes: x = srow_x[0] * i + srow_x[1] * j + srow_x[2] * k + srow_x[3] y = srow_y[0] * i + srow_y[1] * j + srow_y[2] * k + srow_y[3] z = srow_z[0] * i + srow_z[1] * j + srow_z[2] * k + srow_z[3] The srow_* vectors are in the NIFTI_1 header. Note that no use is made of pixdim[] in this method. WHY 3 METHODS? -------------- Method 1 is provided only for backwards compatibility. The intention is that Method 2 (qform_code > 0) represents the nominal voxel locations as reported by the scanner, or as rotated to some fiducial orientation and location. Method 3, if present (sform_code > 0), is to be used to give the location of the voxels in some standard space. The sform_code indicates which standard space is present. Both methods 2 and 3 can be present, and be useful in different contexts (method 2 for displaying the data on its original grid; method 3 for displaying it on a standard grid). In this scheme, a dataset would originally be set up so that the Method 2 coordinates represent what the scanner reported. Later, a registration to some standard space can be computed and inserted in the header. Image display software can use either transform, depending on its purposes and needs. In Method 2, the origin of coordinates would generally be whatever the scanner origin is; for example, in MRI, (0,0,0) is the center of the gradient coil. In Method 3, the origin of coordinates would depend on the value of sform_code; for example, for the Talairach coordinate system, (0,0,0) corresponds to the Anterior Commissure. QUATERNION REPRESENTATION OF ROTATION MATRIX (METHOD 2) ------------------------------------------------------- The orientation of the (x,y,z) axes relative to the (i,j,k) axes in 3D space is specified using a unit quaternion [a,b,c,d], where a*a+b*b+c*c+d*d=1. The (b,c,d) values are all that is needed, since we require that a = sqrt(1.0-(b*b+c*c+d*d)) be nonnegative. The (b,c,d) values are stored in the (quatern_b,quatern_c,quatern_d) fields. The quaternion representation is chosen for its compactness in representing rotations. The (proper) 3x3 rotation matrix that corresponds to [a,b,c,d] is [ a*a+b*b-c*c-d*d 2*b*c-2*a*d 2*b*d+2*a*c ] R = [ 2*b*c+2*a*d a*a+c*c-b*b-d*d 2*c*d-2*a*b ] [ 2*b*d-2*a*c 2*c*d+2*a*b a*a+d*d-c*c-b*b ] [ R11 R12 R13 ] = [ R21 R22 R23 ] [ R31 R32 R33 ] If (p,q,r) is a unit 3-vector, then rotation of angle h about that direction is represented by the quaternion [a,b,c,d] = [cos(h/2), p*sin(h/2), q*sin(h/2), r*sin(h/2)]. Requiring a >= 0 is equivalent to requiring -Pi <= h <= Pi. (Note that [-a,-b,-c,-d] represents the same rotation as [a,b,c,d]; there are 2 quaternions that can be used to represent a given rotation matrix R.) To rotate a 3-vector (x,y,z) using quaternions, we compute the quaternion product [0,x',y',z'] = [a,b,c,d] * [0,x,y,z] * [a,-b,-c,-d] which is equivalent to the matrix-vector multiply [ x' ] [ x ] [ y' ] = R [ y ] (equivalence depends on a*a+b*b+c*c+d*d=1) [ z' ] [ z ] Multiplication of 2 quaternions is defined by the following: [a,b,c,d] = a*1 + b*I + c*J + d*K where I*I = J*J = K*K = -1 (I,J,K are square roots of -1) I*J = K J*K = I K*I = J J*I = -K K*J = -I I*K = -J (not commutative!) For example [a,b,0,0] * [0,0,0,1] = [0,0,-b,a] since this expands to (a+b*I)*(K) = (a*K+b*I*K) = (a*K-b*J). The above formula shows how to go from quaternion (b,c,d) to rotation matrix and direction cosines. Conversely, given R, we can compute the fields for the NIFTI-1 header by a = 0.5 * sqrt(1+R11+R22+R33) (not stored) b = 0.25 * (R32-R23) / a => quatern_b c = 0.25 * (R13-R31) / a => quatern_c d = 0.25 * (R21-R12) / a => quatern_d If a=0 (a 180 degree rotation), alternative formulas are needed. See the nifti1_io.c function mat44_to_quatern() for an implementation of the various cases in converting R to [a,b,c,d]. Note that R-transpose (= R-inverse) would lead to the quaternion [a,-b,-c,-d]. The choice to specify the qoffset_x (etc.) values in the final coordinate system is partly to make it easy to convert DICOM images to this format. The DICOM attribute "Image Position (Patient)" (0020,0032) stores the (Xd,Yd,Zd) coordinates of the center of the first voxel. Here, (Xd,Yd,Zd) refer to DICOM coordinates, and Xd=-x, Yd=-y, Zd=z, where (x,y,z) refers to the NIFTI coordinate system discussed above. (i.e., DICOM +Xd is Left, +Yd is Posterior, +Zd is Superior, whereas +x is Right, +y is Anterior , +z is Superior. ) Thus, if the (0020,0032) DICOM attribute is extracted into (px,py,pz), then qoffset_x = -px qoffset_y = -py qoffset_z = pz is a reasonable setting when qform_code=NIFTI_XFORM_SCANNER_ANAT. That is, DICOM's coordinate system is 180 degrees rotated about the z-axis from the neuroscience/NIFTI coordinate system. To transform between DICOM and NIFTI, you just have to negate the x- and y-coordinates. The DICOM attribute (0020,0037) "Image Orientation (Patient)" gives the orientation of the x- and y-axes of the image data in terms of 2 3-vectors. The first vector is a unit vector along the x-axis, and the second is along the y-axis. If the (0020,0037) attribute is extracted into the value (xa,xb,xc,ya,yb,yc), then the first two columns of the R matrix would be [ -xa -ya ] [ -xb -yb ] [ xc yc ] The negations are because DICOM's x- and y-axes are reversed relative to NIFTI's. The third column of the R matrix gives the direction of displacement (relative to the subject) along the slice-wise direction. This orientation is not encoded in the DICOM standard in a simple way; DICOM is mostly concerned with 2D images. The third column of R will be either the cross-product of the first 2 columns or its negative. It is possible to infer the sign of the 3rd column by examining the coordinates in DICOM attribute (0020,0032) "Image Position (Patient)" for successive slices. However, this method occasionally fails for reasons that I (RW Cox) do not understand. -----------------------------------------------------------------------------*/ /* [qs]form_code value: */ /* x,y,z coordinate system refers to: */ /*-----------------------*/ /*---------------------------------------*/ /*! \defgroup NIFTI1_XFORM_CODES \brief nifti1 xform codes to describe the "standard" coordinate system @{ */ /*! Arbitrary coordinates (Method 1). */ #define NIFTI_XFORM_UNKNOWN 0 /*! Scanner-based anatomical coordinates */ #define NIFTI_XFORM_SCANNER_ANAT 1 /*! Coordinates aligned to another file's, or to anatomical "truth". */ #define NIFTI_XFORM_ALIGNED_ANAT 2 /*! Coordinates aligned to Talairach- Tournoux Atlas; (0,0,0)=AC, etc. */ #define NIFTI_XFORM_TALAIRACH 3 /*! MNI 152 normalized coordinates. */ #define NIFTI_XFORM_MNI_152 4 /*! Normalized coordinates (for any general standard template space). Added March 8, 2019. */ #define NIFTI_XFORM_TEMPLATE_OTHER 5 /* @} */ /*---------------------------------------------------------------------------*/ /* UNITS OF SPATIAL AND TEMPORAL DIMENSIONS: ---------------------------------------- The codes below can be used in xyzt_units to indicate the units of pixdim. As noted earlier, dimensions 1,2,3 are for x,y,z; dimension 4 is for time (t). - If dim[4]=1 or dim[0] < 4, there is no time axis. - A single time series (no space) would be specified with - dim[0] = 4 (for scalar data) or dim[0] = 5 (for vector data) - dim[1] = dim[2] = dim[3] = 1 - dim[4] = number of time points - pixdim[4] = time step - xyzt_units indicates units of pixdim[4] - dim[5] = number of values stored at each time point Bits 0..2 of xyzt_units specify the units of pixdim[1..3] (e.g., spatial units are values 1..7). Bits 3..5 of xyzt_units specify the units of pixdim[4] (e.g., temporal units are multiples of 8). This compression of 2 distinct concepts into 1 byte is due to the limited space available in the 348 byte ANALYZE 7.5 header. The macros XYZT_TO_SPACE and XYZT_TO_TIME can be used to mask off the undesired bits from the xyzt_units fields, leaving "pure" space and time codes. Inversely, the macro SPACE_TIME_TO_XYZT can be used to assemble a space code (0,1,2,...,7) with a time code (0,8,16,32,...,56) into the combined value for xyzt_units. Note that codes are provided to indicate the "time" axis units are actually frequency in Hertz (_HZ), in part-per-million (_PPM) or in radians-per-second (_RADS). The toffset field can be used to indicate a nonzero start point for the time axis. That is, time point #m is at t=toffset+m*pixdim[4] for m=0..dim[4]-1. -----------------------------------------------------------------------------*/ /*! \defgroup NIFTI1_UNITS \brief nifti1 units codes to describe the unit of measurement for each dimension of the dataset @{ */ /*! NIFTI code for unspecified units. */ #define NIFTI_UNITS_UNKNOWN 0 /** Space codes are multiples of 1. **/ /*! NIFTI code for meters. */ #define NIFTI_UNITS_METER 1 /*! NIFTI code for millimeters. */ #define NIFTI_UNITS_MM 2 /*! NIFTI code for micrometers. */ #define NIFTI_UNITS_MICRON 3 /** Time codes are multiples of 8. **/ /*! NIFTI code for seconds. */ #define NIFTI_UNITS_SEC 8 /*! NIFTI code for milliseconds. */ #define NIFTI_UNITS_MSEC 16 /*! NIFTI code for microseconds. */ #define NIFTI_UNITS_USEC 24 /*** These units are for spectral data: ***/ /*! NIFTI code for Hertz. */ #define NIFTI_UNITS_HZ 32 /*! NIFTI code for ppm. */ #define NIFTI_UNITS_PPM 40 /*! NIFTI code for radians per second. */ #define NIFTI_UNITS_RADS 48 /* @} */ #undef XYZT_TO_SPACE #undef XYZT_TO_TIME #define XYZT_TO_SPACE(xyzt) ( (xyzt) & 0x07 ) #define XYZT_TO_TIME(xyzt) ( (xyzt) & 0x38 ) #undef SPACE_TIME_TO_XYZT #define SPACE_TIME_TO_XYZT(ss,tt) ( (((char)(ss)) & 0x07) \ | (((char)(tt)) & 0x38) ) /*---------------------------------------------------------------------------*/ /* MRI-SPECIFIC SPATIAL AND TEMPORAL INFORMATION: --------------------------------------------- A few fields are provided to store some extra information that is sometimes important when storing the image data from an FMRI time series experiment. (After processing such data into statistical images, these fields are not likely to be useful.) { freq_dim } = These fields encode which spatial dimension (1,2, or 3) { phase_dim } = corresponds to which acquisition dimension for MRI data. { slice_dim } = Examples: Rectangular scan multi-slice EPI: freq_dim = 1 phase_dim = 2 slice_dim = 3 (or some permutation) Spiral scan multi-slice EPI: freq_dim = phase_dim = 0 slice_dim = 3 since the concepts of frequency- and phase-encoding directions don't apply to spiral scan slice_duration = If this is positive, AND if slice_dim is nonzero, indicates the amount of time used to acquire 1 slice. slice_duration*dim[slice_dim] can be less than pixdim[4] with a clustered acquisition method, for example. slice_code = If this is nonzero, AND if slice_dim is nonzero, AND if slice_duration is positive, indicates the timing pattern of the slice acquisition. The following codes are defined: NIFTI_SLICE_SEQ_INC == sequential increasing NIFTI_SLICE_SEQ_DEC == sequential decreasing NIFTI_SLICE_ALT_INC == alternating increasing NIFTI_SLICE_ALT_DEC == alternating decreasing NIFTI_SLICE_ALT_INC2 == alternating increasing #2 NIFTI_SLICE_ALT_DEC2 == alternating decreasing #2 { slice_start } = Indicates the start and end of the slice acquisition { slice_end } = pattern, when slice_code is nonzero. These values are present to allow for the possible addition of "padded" slices at either end of the volume, which don't fit into the slice timing pattern. If there are no padding slices, then slice_start=0 and slice_end=dim[slice_dim]-1 are the correct values. For these values to be meaningful, slice_start must be non-negative and slice_end must be greater than slice_start. Otherwise, they should be ignored. The following table indicates the slice timing pattern, relative to time=0 for the first slice acquired, for some sample cases. Here, dim[slice_dim]=7 (there are 7 slices, labeled 0..6), slice_duration=0.1, and slice_start=1, slice_end=5 (1 padded slice on each end). slice index SEQ_INC SEQ_DEC ALT_INC ALT_DEC ALT_INC2 ALT_DEC2 6 : n/a n/a n/a n/a n/a n/a n/a = not applicable 5 : 0.4 0.0 0.2 0.0 0.4 0.2 (slice time offset 4 : 0.3 0.1 0.4 0.3 0.1 0.0 doesn't apply to 3 : 0.2 0.2 0.1 0.1 0.3 0.3 slices outside 2 : 0.1 0.3 0.3 0.4 0.0 0.1 the range 1 : 0.0 0.4 0.0 0.2 0.2 0.4 slice_start .. 0 : n/a n/a n/a n/a n/a n/a slice_end) The SEQ slice_codes are sequential ordering (uncommon but not unknown), either increasing in slice number or decreasing (INC or DEC), as illustrated above. The ALT slice codes are alternating ordering. The 'standard' way for these to operate (without the '2' on the end) is for the slice timing to start at the edge of the slice_start .. slice_end group (at slice_start for INC and at slice_end for DEC). For the 'ALT_*2' slice_codes, the slice timing instead starts at the first slice in from the edge (at slice_start+1 for INC2 and at slice_end-1 for DEC2). This latter acquisition scheme is found on some Siemens scanners. The fields freq_dim, phase_dim, slice_dim are all squished into the single byte field dim_info (2 bits each, since the values for each field are limited to the range 0..3). This unpleasantness is due to lack of space in the 348 byte allowance. The macros DIM_INFO_TO_FREQ_DIM, DIM_INFO_TO_PHASE_DIM, and DIM_INFO_TO_SLICE_DIM can be used to extract these values from the dim_info byte. The macro FPS_INTO_DIM_INFO can be used to put these 3 values into the dim_info byte. -----------------------------------------------------------------------------*/ #undef DIM_INFO_TO_FREQ_DIM #undef DIM_INFO_TO_PHASE_DIM #undef DIM_INFO_TO_SLICE_DIM #define DIM_INFO_TO_FREQ_DIM(di) ( ((di) ) & 0x03 ) #define DIM_INFO_TO_PHASE_DIM(di) ( ((di) >> 2) & 0x03 ) #define DIM_INFO_TO_SLICE_DIM(di) ( ((di) >> 4) & 0x03 ) #undef FPS_INTO_DIM_INFO #define FPS_INTO_DIM_INFO(fd,pd,sd) ( ( ( ((char)(fd)) & 0x03) ) | \ ( ( ((char)(pd)) & 0x03) << 2 ) | \ ( ( ((char)(sd)) & 0x03) << 4 ) ) /*! \defgroup NIFTI1_SLICE_ORDER \brief nifti1 slice order codes, describing the acquisition order of the slices @{ */ #define NIFTI_SLICE_UNKNOWN 0 #define NIFTI_SLICE_SEQ_INC 1 #define NIFTI_SLICE_SEQ_DEC 2 #define NIFTI_SLICE_ALT_INC 3 #define NIFTI_SLICE_ALT_DEC 4 #define NIFTI_SLICE_ALT_INC2 5 /* 05 May 2005: RWCox */ #define NIFTI_SLICE_ALT_DEC2 6 /* 05 May 2005: RWCox */ /* @} */ /*---------------------------------------------------------------------------*/ /* UNUSED FIELDS: ------------- Some of the ANALYZE 7.5 fields marked as ++UNUSED++ may need to be set to particular values for compatibility with other programs. The issue of interoperability of ANALYZE 7.5 files is a murky one -- not all programs require exactly the same set of fields. (Unobscuring this murkiness is a principal motivation behind NIFTI-1.) Some of the fields that may need to be set for other (non-NIFTI aware) software to be happy are: extents dbh.h says this should be 16384 regular dbh.h says this should be the character 'r' glmin, } dbh.h says these values should be the min and max voxel glmax } values for the entire dataset It is best to initialize ALL fields in the NIFTI-1 header to 0 (e.g., with calloc()), then fill in what is needed. -----------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* MISCELLANEOUS C MACROS -----------------------------------------------------------------------------*/ /*.................*/ /*! Given a nifti_1_header struct, check if it has a good magic number. Returns NIFTI version number (1..9) if magic is good, 0 if it is not. */ #define NIFTI_VERSION(h) \ ( ( (h).magic[0]=='n' && (h).magic[3]=='\0' && \ ( (h).magic[1]=='i' || (h).magic[1]=='+' ) && \ ( (h).magic[2]>='1' && (h).magic[2]<='9' ) ) \ ? (h).magic[2]-'0' : 0 ) /*.................*/ /*! Check if a nifti_1_header struct says if the data is stored in the same file or in a separate file. Returns 1 if the data is in the same file as the header, 0 if it is not. */ #define NIFTI_ONEFILE(h) ( (h).magic[1] == '+' ) /*.................*/ /*! Check if a nifti_1_header struct needs to be byte swapped. Returns 1 if it needs to be swapped, 0 if it does not. */ #define NIFTI_NEEDS_SWAP(h) ( (h).dim[0] < 0 || (h).dim[0] > 7 ) /*.................*/ /*! Check if a nifti_1_header struct contains a 5th (vector) dimension. Returns size of 5th dimension if > 1, returns 0 otherwise. */ #define NIFTI_5TH_DIM(h) ( ((h).dim[0]>4 && (h).dim[5]>1) ? (h).dim[5] : 0 ) /*****************************************************************************/ /*=================*/ #ifdef __cplusplus } #endif /*=================*/ #endif /* _NIFTI_HEADER_ */ nifti_clib-3.0.1/niftilib/nifti1_io.c000066400000000000000000010237451371325713600174660ustar00rootroot00000000000000#define _NIFTI1_IO_C_ #include "nifti1_io.h" /* typedefs, prototypes, macros, etc. */ #include "nifti1_io_version.h" /*****===================================================================*****/ /***** Sample functions to deal with NIFTI-1 and ANALYZE files *****/ /*****...................................................................*****/ /***** This code is released to the public domain. *****/ /*****...................................................................*****/ /***** Author: Robert W Cox, SSCC/DIRP/NIMH/NIH/DHHS/USA/EARTH *****/ /***** Date: August 2003 *****/ /*****...................................................................*****/ /***** Neither the National Institutes of Health (NIH), nor any of its *****/ /***** employees imply any warranty of usefulness of this software for *****/ /***** any purpose, and do not assume any liability for damages, *****/ /***** incidental or otherwise, caused by any use of this document. *****/ /*****===================================================================*****/ /** \file nifti1_io.c \brief main collection of nifti1 i/o routines - written by Bob Cox, SSCC NIMH - revised by Mark Jenkinson, FMRIB - revised by Rick Reynolds, SSCC, NIMH - revised by Kate Fissell, University of Pittsburgh The library history can be viewed via "nifti_tool -nifti_hist".
The library version can be viewed via "nifti_tool -nifti_ver". */ /*! global history and version strings, for printing */ static char const * const gni_history[] = { "----------------------------------------------------------------------\n" "history (of nifti library changes):\n" "\n", "0.0 August, 2003 [rwcox]\n" " (Robert W Cox of the National Institutes of Health, SSCC/DIRP/NIMH)\n" " - initial version\n" "\n", "0.1 July/August, 2004 [Mark Jenkinson]\n" " (FMRIB Centre, University of Oxford, UK)\n" " - Mainly adding low-level IO and changing things to allow gzipped\n" " files to be read and written\n" " - Full backwards compatability should have been maintained\n" "\n", "0.2 16 Nov 2004 [rickr]\n" " (Rick Reynolds of the National Institutes of Health, SSCC/DIRP/NIMH)\n" " - included Mark's changes in the AFNI distribution (including znzlib/)\n" " (HAVE_ZLIB is commented out for the standard distribution)\n" " - modified nifti_validfilename() and nifti_makebasename()\n" " - added nifti_find_file_extension()\n" "\n", "0.3 3 Dec 2004 [rickr]\n" " - note: header extensions are not yet checked for\n" " - added formatted history as global string, for printing\n" " - added nifti_disp_lib_hist(), to display the nifti library history\n" " - added nifti_disp_lib_version(), to display the nifti library history\n", " - re-wrote nifti_findhdrname()\n" " o used nifti_find_file_extension()\n" " o changed order of file tests (default is .nii, depends on input)\n" " o free hdrname on failure\n" " - made similar changes to nifti_findimgname()\n" " - check for NULL return from nifti_findhdrname() calls\n", " - removed most of ERREX() macros\n" " - modified nifti_image_read()\n" " o added debug info and error checking (on gni_debug > 0, only)\n" " o fail if workingname is NULL\n" " o check for failure to open header file\n" " o free workingname on failure\n" " o check for failure of nifti_image_load()\n" " o check for failure of nifti_convert_nhdr2nim()\n", " - changed nifti_image_load() to int, and check nifti_read_buffer return\n" " - changed nifti_read_buffer() to fail on short read, and to count float\n" " fixes (to print on debug)\n" " - changed nifti_image_infodump to print to stderr\n" " - updated function header comments, or moved comments above header\n" " - removed const keyword\n" " - added LNI_FERR() macro for error reporting on input files\n" "\n", "0.4 10 Dec 2004 [rickr] - added header extensions\n" " - in nifti1_io.h:\n" " o added num_ext and ext_list to the definition of nifti_image\n" " o made many functions static (more to follow)\n" " o added LNI_MAX_NIA_EXT_LEN, for max nifti_type 3 extension length\n", " - added __DATE__ to version output in nifti_disp_lib_version()\n" " - added nifti_disp_matrix_orient() to print orientation information\n" " - added '.nia' as a valid file extension in nifti_find_file_extension()\n" " - added much more debug output\n" " - in nifti_image_read(), in the case of an ASCII header, check for\n" " extensions after the end of the header\n", " - added nifti_read_extensions() function\n" " - added nifti_read_next_extension() function\n" " - added nifti_add_exten_to_list() function\n" " - added nifti_check_extension() function\n" " - added nifti_write_extensions() function\n" " - added nifti_extension_size() function\n" " - in nifti_set_iname_offest():\n" " o adjust offset by the extension size and the extender size\n", " o fixed the 'ceiling modulo 16' computation\n" " - in nifti_image_write_hdr_img2(): \n" " o added extension writing\n" " o check for NULL return from nifti_findimgname()\n" " - include number of extensions in nifti_image_to_ascii() output\n" " - in nifti_image_from_ascii():\n" " o return bytes_read as a parameter, computed from the final spos\n" " o extract num_ext from ASCII header\n" "\n", "0.5 14 Dec 2004 [rickr] - added sub-brick reading functions\n" " - added nifti_brick_list type to nifti1_io.h, along with new prototypes\n" " - added main nifti_image_read_bricks() function, with description\n" " - added nifti_image_load_bricks() - library function (requires nim)\n" " - added valid_nifti_brick_list() - library function\n" " - added free_NBL() - library function\n", " - added update_nifti_image_for_brick_list() for dimension update\n" " - added nifti_load_NBL_bricks(), nifti_alloc_NBL_mem(),\n" " nifti_copynsort() and force_positive() (static functions)\n" " - in nifti_image_read(), check for failed load only if read_data is set\n" " - broke most of nifti_image_load() into nifti_image_load_prep()\n" "\n", "0.6 15 Dec 2004 [rickr] - added sub-brick writing functionality\n" " - in nifti1_io.h, removed znzlib directory from include - all nifti\n" " library files are now under the nifti directory\n" " - nifti_read_extensions(): print no offset warning for nifti_type 3\n" " - nifti_write_all_data():\n" " o pass nifti_brick_list * NBL, for optional writing\n" " o if NBL, write each sub-brick, sequentially\n", " - nifti_set_iname_offset(): case 1 must have sizeof() cast to int\n" " - pass NBL to nifti_image_write_hdr_img2(), and allow NBL or data\n" " - added nifti_image_write_bricks() wrapper for ...write_hdr_img2()\n" " - included compression abilities\n" "\n", "0.7 16 Dec 2004 [rickr] - minor changes to extension reading\n" "\n", "0.8 21 Dec 2004 [rickr] - restrict extension reading, and minor changes\n" " - in nifti_image_read(), compute bytes for extensions (see remaining)\n" " - in nifti_read_extensions(), pass 'remain' as space for extensions,\n" " pass it to nifti_read_next_ext(), and update for each one read \n" " - in nifti_check_extension(), require (size <= remain)\n", " - in update_nifti_image_brick_list(), update nvox\n" " - in nifti_image_load_bricks(), make explicit check for nbricks <= 0\n" " - in int_force_positive(), check for (!list)\n" " - in swap_nifti_header(), swap sizeof_hdr, and reorder to struct order\n" " - change get_filesize functions to signed ( < 0 is no file or error )\n", " - in nifti_validfilename(), lose redundant (len < 0) check\n" " - make print_hex_vals() static\n" " - in disp_nifti_1_header, restrict string field widths\n" "\n", "0.9 23 Dec 2004 [rickr] - minor changes\n" " - broke ASCII header reading out of nifti_image_read(), into new\n" " functions has_ascii_header() and read_ascii_image()\n", " - check image_read failure and znzseek failure\n" " - altered some debug output\n" " - nifti_write_all_data() now returns an int\n" "\n", "0.10 29 Dec 2004 [rickr]\n" " - renamed nifti_valid_extension() to nifti_check_extension()\n" " - added functions nifti_makehdrname() and nifti_makeimgname()\n" " - added function valid_nifti_extensions()\n" " - in nifti_write_extensions(), check for validity before writing\n", " - rewrote nifti_image_write_hdr_img2():\n" " o set write_data and leave_open flags from write_opts\n" " o add debug print statements\n" " o use nifti_write_ascii_image() for the ascii case\n" " o rewrote the logic of all cases to be easier to follow\n", " - broke out code as nifti_write_ascii_image() function\n" " - added debug to top-level write functions, and free the znzFile\n" " - removed unused internal function nifti_image_open()\n" "\n", "0.11 30 Dec 2004 [rickr] - small mods\n" " - moved static function prototypes from header to C file\n" " - free extensions in nifti_image_free()\n" "\n", "1.0 07 Jan 2005 [rickr] - INITIAL RELEASE VERSION\n" " - added function nifti_set_filenames()\n" " - added function nifti_read_header()\n" " - added static function nhdr_looks_good()\n" " - added static function need_nhdr_swap()\n" " - exported nifti_add_exten_to_list symbol\n", " - fixed #bytes written in nifti_write_extensions()\n" " - only modify offset if it is too small (nifti_set_iname_offset)\n" " - added nifti_type 3 to nifti_makehdrname and nifti_makeimgname\n" " - added function nifti_set_filenames()\n" "\n", "1.1 07 Jan 2005 [rickr]\n" " - in nifti_read_header(), swap if needed\n" "\n", "1.2 07 Feb 2005 [kate fissell c/o rickr] \n" " - nifti1.h: added doxygen comments for main struct and #define groups\n" " - nifti1_io.h: added doxygen comments for file and nifti_image struct\n" " - nifti1_io.h: added doxygen comments for file and some functions\n" " - nifti1_io.c: changed nifti_copy_nim_info to use memcpy\n" "\n", "1.3 09 Feb 2005 [rickr]\n" " - nifti1.h: added doxygen comments for extension structs\n" " - nifti1_io.h: put most #defines in #ifdef _NIFTI1_IO_C_ block\n" " - added a doxygen-style description to every exported function\n" " - added doxygen-style comments within some functions\n" " - re-exported many znzFile functions that I had made static\n" " - re-added nifti_image_open (sorry, Mark)\n" " - every exported function now has 'nifti' in the name (19 functions)\n", " - made sure every alloc() has a failure test\n" " - added nifti_copy_extensions function, for use in nifti_copy_nim_info\n" " - nifti_is_gzfile: added initial strlen test\n" " - nifti_set_filenames: added set_byte_order parameter option\n" " (it seems appropriate to set the BO when new files are associated)\n" " - disp_nifti_1_header: prints to stdout (a.o.t. stderr), with fflush\n" "\n", "1.4 23 Feb 2005 [rickr] - sourceforge merge\n" " - merged into the nifti_io CVS directory structure at sourceforge.net\n" " - merged in 4 changes by Mark, and re-added his const keywords\n" " - cast some pointers to (void *) for -pedantic compile option\n" " - added nifti_free_extensions()\n" "\n", "1.5 02 Mar 2005 [rickr] - started nifti global options\n" " - gni_debug is now g_opts.debug\n" " - added validity check parameter to nifti_read_header\n" " - need_nhdr_swap no longer does test swaps on the stack\n" "\n", "1.6 05 April 2005 [rickr] - validation and collapsed_image_read\n" " - added nifti_read_collapsed_image(), an interface for reading partial\n" " datasets, specifying a subset of array indices\n" " - for read_collapsed_image, added static functions: rci_read_data(),\n" " rci_alloc_mem(), and make_pivot_list()\n", " - added nifti_nim_is_valid() to check for consistency (more to do)\n" " - added nifti_nim_has_valid_dims() to do many dimensions tests\n" "\n", "1.7 08 April 2005 [rickr]\n" " - added nifti_update_dims_from_array() - to update dimensions\n" " - modified nifti_makehdrname() and nifti_makeimgname():\n" " if prefix has a valid extension, use it (else make one up)\n" " - added nifti_get_intlist - for making an array of ints\n" " - fixed init of NBL->bsize in nifti_alloc_NBL_mem() {thanks, Bob}\n" "\n", "1.8 14 April 2005 [rickr]\n" " - added nifti_set_type_from_names(), for nifti_set_filenames()\n" " (only updates type if number of files does not match it)\n" " - added is_valid_nifti_type(), just to be sure\n" " - updated description of nifti_read_collapsed_image() for *data change\n" " (if *data is already set, assume memory exists for results)\n" " - modified rci_alloc_mem() to allocate only if *data is NULL\n" "\n", "1.9 19 April 2005 [rickr]\n" " - added extension codes NIFTI_ECODE_COMMENT and NIFTI_ECODE_XCEDE\n" " - added nifti_type codes NIFTI_MAX_ECODE and NIFTI_MAX_FTYPE\n" " - added nifti_add_extension() {exported}\n" " - added nifti_fill_extension() as a static function\n" " - added nifti_is_valid_ecode() {exported}\n", " - nifti_type values are now NIFTI_FTYPE_* file codes\n" " - in nifti_read_extensions(), decrement 'remain' by extender size, 4\n" " - in nifti_set_iname_offset(), case 1, update if offset differs\n" " - only output '-d writing nifti file' if debug > 1\n" "\n", "1.10 10 May 2005 [rickr]\n" " - files are read using ZLIB only if they end in '.gz'\n" "\n", "1.11 12 August 2005 [kate fissell]\n" " - Kate's 0.2 release packaging, for sourceforge\n" "\n", "1.12 17 August 2005 [rickr] - comment (doxygen) updates\n" " - updated comments for most functions (2 updates from Cinly Ooi)\n" " - added nifti_type_and_names_match()\n" "\n", "1.12a 24 August 2005 [rickr] - remove all tabs from Clibs/*/*.[ch]\n", "1.12b 25 August 2005 [rickr] - changes by Hans Johnson\n", "1.13 25 August 2005 [rickr]\n", " - finished changes by Hans for Insight\n" " - added const in all appropraite parameter locations (30-40)\n" " (any pointer referencing data that will not change)\n" " - shortened all string constants below 509 character limit\n" "1.14 28 October 2005 [HJohnson]\n", " - use nifti_set_filenames() in nifti_convert_nhdr2nim()\n" "1.15 02 November 2005 [rickr]\n", " - added skip_blank_ext to nifti_global_options\n" " - added nifti_set_skip_blank_ext(), to set option\n" " - if skip_blank_ext and no extensions, do not read/write extender\n" "1.16 18 November 2005 [rickr]\n", " - removed any test or access of dim[i], i>dim[0]\n" " - do not set pixdim for collapsed dims to 1.0, leave them as they are\n" " - added magic and dim[i] tests in nifti_hdr_looks_good()\n" " - added 2 size_t casts\n" "1.17 22 November 2005 [rickr]\n", " - in hdr->nim, for i > dim[0], pass 0 or 1, else set to 1\n" "1.18 02 March 2006 [rickr]\n", " - in nifti_alloc_NBL_mem(), fixed nt=0 case from 1.17 change\n" "1.19 23 May 2006 [HJohnson,rickr]\n", " - nifti_write_ascii_image(): free(hstr)\n" " - nifti_copy_extensions(): clear num_ext and ext_list\n" "1.20 27 Jun 2006 [rickr]\n", " - nifti_findhdrname(): fixed assign of efirst to match stated logic\n" " (problem found by Atle Bjørnerud)\n" "1.21 05 Sep 2006 [rickr] update for nifticlib-0.4 release\n", " - was reminded to actually add nifti_set_skip_blank_ext()\n" " - init g_opts.skip_blank_ext to 0\n" "1.22 01 Jun 2007 nifticlib-0.5 release\n", "1.23 05 Jun 2007 nifti_add_exten_to_list: revert on failure, free old list\n" "1.24 07 Jun 2007 nifti_copy_extensions: use esize-8 for data size\n" "1.25 12 Jun 2007 [rickr] EMPTY_IMAGE creation\n", " - added nifti_make_new_header() - to create from dims/dtype\n" " - added nifti_make_new_nim() - to create from dims/dtype/fill\n" " - added nifti_is_valid_datatype(), and more debug info\n", "1.26 27 Jul 2007 [rickr] handle single volumes > 2^31 bytes (but < 2^32)\n", "1.27 28 Jul 2007 [rickr] nim->nvox, NBL-bsize are now type size_t\n" "1.28 30 Jul 2007 [rickr] size_t updates\n", "1.29 08 Aug 2007 [rickr] for list, valid_nifti_brick_list requires 3 dims\n" "1.30 08 Nov 2007 [Yaroslav/rickr]\n" " - fix ARM struct alignment problem in byte-swapping routines\n", "1.31 29 Nov 2007 [rickr] for nifticlib-1.0.0\n" " - added nifti_datatype_to/from_string routines\n" " - added DT_RGBA32/NIFTI_TYPE_RGBA32 datatype macros (2304)\n" " - added NIFTI_ECODE_FREESURFER (14)\n", "1.32 08 Dec 2007 [rickr]\n" " - nifti_hdr_looks_good() allows ANALYZE headers (req. by V. Luccio)\n" " - added nifti_datatype_is_valid()\n", "1.33 05 Feb 2008 [hansj,rickr] - block nia.gz use\n" "1.34 13 Jun 2008 [rickr] - added nifti_compiled_with_zlib()\n" "1.35 03 Aug 2008 [rickr]\n", " - deal with swapping, so that CPU type does not affect output\n" " (motivated by C Burns)\n" " - added nifti_analyze75 structure and nifti_swap_as_analyze()\n" " - previous swap_nifti_header is saved as old_swap_nifti_header\n" " - also swap UNUSED fields in nifti_1_header struct\n", "1.36 07 Oct 2008 [rickr]\n", " - added nifti_NBL_matches_nim() check for write_bricks()\n" "1.37 10 Mar 2009 [rickr]\n", " - H Johnson cast updates (06 Feb)\n" " - added NIFTI_ECODE_PYPICKLE for PyNIfTI (06 Feb)\n" " - added NIFTI_ECODEs 18-28 for the LONI MiND group\n" "1.38 28 Apr 2009 [rickr]\n", " - uppercase extensions are now valid (requested by M. Coursolle)\n" " - nifti_set_allow_upper_fext controls this option (req by C. Ooi)\n" "1.39 23 Jun 2009 [rickr]: added 4 checks of alloc() returns\n", "1.40 16 Mar 2010 [rickr]: added NIFTI_ECODE_VOXBO for D. Kimberg\n", "1.41 28 Apr 2010 [rickr]: added NIFTI_ECODE_CARET for J. Harwell\n", "1.42 06 Jul 2010 [rickr]: trouble with large (gz) files\n", " - noted/investigated by M Hanke and Y Halchenko\n" " - fixed znzread/write, noting example by M Adler\n" " - changed nifti_swap_* routines/calls to take size_t (6)\n" "1.43 07 Jul 2010 [rickr]: fixed znzR/W to again return nmembers\n", "1.44 19 Jul 2013 [rickr]: ITK compatibility updates from H Johnson\n", "1.45 10 May 2019 [rickr]: added NIFTI_ECODE_QUANTIPHYSE\n", "1.46 26 Sep 2019 [rickr]:\n" " - nifti_read_ascii_image no longer closes fp or free's fname\n", "2.1.0 18 Jun 2020 [leej3,hmjohnson,rickr]:\n" " - big version jump - changed to more formal library versioning\n", "----------------------------------------------------------------------\n" }; static const char gni_version[] = NIFTI1_IO_SOURCE_VERSION " (18 Jun, 2020)"; /*! global nifti options structure - init with defaults */ static nifti_global_options g_opts = { 1, /* debug level */ 0, /* skip_blank_ext - skip extender if no extensions */ 1 /* allow_upper_fext - allow uppercase file extensions */ }; /*! global nifti types structure list (per type, ordered oldest to newest) */ static const nifti_type_ele nifti_type_list[] = { /* type nbyper swapsize name */ { 0, 0, 0, "DT_UNKNOWN" }, { 0, 0, 0, "DT_NONE" }, { 1, 0, 0, "DT_BINARY" }, /* not usable */ { 2, 1, 0, "DT_UNSIGNED_CHAR" }, { 2, 1, 0, "DT_UINT8" }, { 2, 1, 0, "NIFTI_TYPE_UINT8" }, { 4, 2, 2, "DT_SIGNED_SHORT" }, { 4, 2, 2, "DT_INT16" }, { 4, 2, 2, "NIFTI_TYPE_INT16" }, { 8, 4, 4, "DT_SIGNED_INT" }, { 8, 4, 4, "DT_INT32" }, { 8, 4, 4, "NIFTI_TYPE_INT32" }, { 16, 4, 4, "DT_FLOAT" }, { 16, 4, 4, "DT_FLOAT32" }, { 16, 4, 4, "NIFTI_TYPE_FLOAT32" }, { 32, 8, 4, "DT_COMPLEX" }, { 32, 8, 4, "DT_COMPLEX64" }, { 32, 8, 4, "NIFTI_TYPE_COMPLEX64" }, { 64, 8, 8, "DT_DOUBLE" }, { 64, 8, 8, "DT_FLOAT64" }, { 64, 8, 8, "NIFTI_TYPE_FLOAT64" }, { 128, 3, 0, "DT_RGB" }, { 128, 3, 0, "DT_RGB24" }, { 128, 3, 0, "NIFTI_TYPE_RGB24" }, { 255, 0, 0, "DT_ALL" }, { 256, 1, 0, "DT_INT8" }, { 256, 1, 0, "NIFTI_TYPE_INT8" }, { 512, 2, 2, "DT_UINT16" }, { 512, 2, 2, "NIFTI_TYPE_UINT16" }, { 768, 4, 4, "DT_UINT32" }, { 768, 4, 4, "NIFTI_TYPE_UINT32" }, { 1024, 8, 8, "DT_INT64" }, { 1024, 8, 8, "NIFTI_TYPE_INT64" }, { 1280, 8, 8, "DT_UINT64" }, { 1280, 8, 8, "NIFTI_TYPE_UINT64" }, { 1536, 16, 16, "DT_FLOAT128" }, { 1536, 16, 16, "NIFTI_TYPE_FLOAT128" }, { 1792, 16, 8, "DT_COMPLEX128" }, { 1792, 16, 8, "NIFTI_TYPE_COMPLEX128" }, { 2048, 32, 16, "DT_COMPLEX256" }, { 2048, 32, 16, "NIFTI_TYPE_COMPLEX256" }, { 2304, 4, 0, "DT_RGBA32" }, { 2304, 4, 0, "NIFTI_TYPE_RGBA32" }, }; /*---------------------------------------------------------------------------*/ /* prototypes for internal functions - not part of exported library */ /* extension routines */ static int nifti_read_extensions( nifti_image *nim, znzFile fp, int remain ); static int nifti_read_next_extension( nifti1_extension * nex, nifti_image *nim, int remain, znzFile fp ); static int nifti_check_extension(nifti_image *nim, int size,int code, int rem); static void update_nifti_image_for_brick_list(nifti_image * nim , int nbricks); static int nifti_add_exten_to_list(nifti1_extension * new_ext, nifti1_extension ** list, int new_length); static int nifti_fill_extension(nifti1_extension * ext, const char * data, int len, int ecode); /* NBL routines */ static int nifti_load_NBL_bricks(nifti_image * nim , const int * slist, const int * sindex, nifti_brick_list * NBL, znzFile fp ); static int nifti_alloc_NBL_mem( nifti_image * nim, int nbricks, nifti_brick_list * nbl); static int nifti_copynsort(int nbricks, const int *blist, int **slist, int **sindex); static int nifti_NBL_matches_nim(const nifti_image *nim, const nifti_brick_list *NBL); /* for nifti_read_collapsed_image: */ static int rci_read_data(nifti_image *nim, int *pivots, int *prods, int nprods, const int dims[], char *data, znzFile fp, size_t base_offset); static int rci_alloc_mem(void ** data, const int prods[8], int nprods, int nbyper ); static int make_pivot_list(nifti_image * nim, const int dims[], int pivots[], int prods[], int * nprods ); /* misc */ static int compare_strlist (const char * str, char ** strlist, int len); static int fileext_compare (const char * test_ext, const char * known_ext); static int fileext_n_compare (const char * test_ext, const char * known_ext, size_t maxlen); static int is_mixedcase (const char * str); static int is_uppercase (const char * str); static int make_lowercase (char * str); static int make_uppercase (char * str); static int need_nhdr_swap (short dim0, int hdrsize); static int print_hex_vals (const char * data, size_t nbytes, FILE * fp); static int unescape_string (char *str); /* string utility functions */ static char *escapize_string (const char *str); /* internal I/O routines */ static znzFile nifti_image_load_prep( nifti_image *nim ); static int has_ascii_header(znzFile fp); /*---------------------------------------------------------------------------*/ /* for calling from some main program */ /*----------------------------------------------------------------------*/ /*! display the nifti library module history (via stdout) *//*--------------------------------------------------------------------*/ void nifti_disp_lib_hist( void ) { int c, len = sizeof(gni_history)/sizeof(char *); for( c = 0; c < len; c++ ) fputs(gni_history[c], stdout); } /*----------------------------------------------------------------------*/ /*! display the nifti library version (via stdout) *//*--------------------------------------------------------------------*/ void nifti_disp_lib_version( void ) { printf("%s, compiled %s\n", gni_version, __DATE__); } /*----------------------------------------------------------------------*/ /*! nifti_image_read_bricks - read nifti data as array of bricks * * 13 Dec 2004 [rickr] * * \param hname - filename of dataset to read (must be valid) * \param nbricks - number of sub-bricks to read * (if blist is valid, nbricks must be > 0) * \param blist - list of sub-bricks to read * (can be NULL; if NULL, read complete dataset) * \param NBL - pointer to empty nifti_brick_list struct * (must be a valid pointer) * * \return *
nim - same as nifti_image_read, but * nim->nt = NBL->nbricks (or nt*nu*nv*nw) * nim->nu,nv,nw = 1 * nim->data = NULL *
NBL - filled with data volumes * * By default, this function will read the nifti dataset and break the data * into a list of nt*nu*nv*nw sub-bricks, each having size nx*ny*nz elements. * That is to say, instead of reading the entire dataset as a single array, * break it up into sub-bricks (volumes), each of size nx*ny*nz elements. * * Note: in the returned nifti_image, nu, nv and nw will always be 1. The * intention of this function is to collapse the dataset into a single * array of volumes (of length nbricks or nt*nu*nv*nw). * * If 'blist' is valid, it is taken to be a list of sub-bricks, of length * 'nbricks'. The data will still be separated into sub-bricks of size * nx*ny*nz elements, but now 'nbricks' sub-bricks will be returned, of the * caller's choosing via 'blist'. * * E.g. consider a dataset with 12 sub-bricks (numbered 0..11), and the * following code: * *
 * { nifti_brick_list   NB_orig, NB_select;
 *   nifti_image      * nim_orig, * nim_select;
 *   int                blist[5] = { 7, 0, 5, 5, 9 };
 *
 *   nim_orig   = nifti_image_read_bricks("myfile.nii", 0, NULL,  &NB_orig);
 *   nim_select = nifti_image_read_bricks("myfile.nii", 5, blist, &NB_select);
 * }
 * 
* * Here, nim_orig gets the entire dataset, where NB_orig.nbricks = 12. But * nim_select has NB_select.nbricks = 5. * * Note that the first case is not quite the same as just calling the * nifti_image_read function, as here the data is separated into sub-bricks. * * Note that valid blist elements are in [0..nt*nu*nv*nw-1], * or written [ 0 .. (dim[4]*dim[5]*dim[6]*dim[7] - 1) ]. * * Note that, as is the case with all of the reading functions, the * data will be allocated, read in, and properly byte-swapped, if * necessary. * * \sa nifti_image_load_bricks, nifti_free_NBL, valid_nifti_brick_list, nifti_image_read *//*----------------------------------------------------------------------*/ nifti_image *nifti_image_read_bricks(const char * hname, int nbricks, const int * blist, nifti_brick_list * NBL) { nifti_image * nim; if( !hname || !NBL ){ fprintf(stderr,"** nifti_image_read_bricks: bad params (%p,%p)\n", hname, (void *)NBL); return NULL; } if( blist && nbricks <= 0 ){ fprintf(stderr,"** nifti_image_read_bricks: bad nbricks, %d\n", nbricks); return NULL; } nim = nifti_image_read(hname, 0); /* read header, but not data */ if( !nim ) return NULL; /* errors were already printed */ /* if we fail, free image and return */ if( nifti_image_load_bricks(nim, nbricks, blist, NBL) <= 0 ){ nifti_image_free(nim); return NULL; } if( blist ) update_nifti_image_for_brick_list(nim, nbricks); return nim; } /*---------------------------------------------------------------------- * update_nifti_image_for_brick_list - update nifti_image * * When loading a specific brick list, the distinction between * nt, nu, nv and nw is lost. So put everything in t, and set * dim[0] = 4. *----------------------------------------------------------------------*/ static void update_nifti_image_for_brick_list( nifti_image * nim , int nbricks ) { int ndim; if( g_opts.debug > 2 ){ fprintf(stderr,"+d updating image dimensions for %d bricks in list\n", nbricks); fprintf(stderr," ndim = %d\n",nim->ndim); fprintf(stderr," nx,ny,nz,nt,nu,nv,nw: (%d,%d,%d,%d,%d,%d,%d)\n", nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->nv, nim->nw); } nim->nt = nbricks; nim->nu = nim->nv = nim->nw = 1; nim->dim[4] = nbricks; nim->dim[5] = nim->dim[6] = nim->dim[7] = 1; /* compute nvox */ /* do not rely on dimensions above dim[0] 16 Nov 2005 [rickr] */ for( nim->nvox = 1, ndim = 1; ndim <= nim->dim[0]; ndim++ ) nim->nvox *= nim->dim[ndim]; /* update the dimensions to 4 or lower */ for( ndim = 4; (ndim > 1) && (nim->dim[ndim] <= 1); ndim-- ) ; if( g_opts.debug > 2 ){ fprintf(stderr,"+d ndim = %d -> %d\n",nim->ndim, ndim); fprintf(stderr," --> (%d,%d,%d,%d,%d,%d,%d)\n", nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->nv, nim->nw); } nim->dim[0] = nim->ndim = ndim; } /*----------------------------------------------------------------------*/ /*! nifti_update_dims_from_array - update nx, ny, ... from nim->dim[] Fix all the dimension information, based on a new nim->dim[]. Note: we assume that dim[0] will not increase. Check for updates to pixdim[], dx,..., nx,..., nvox, ndim, dim[0]. *//*--------------------------------------------------------------------*/ int nifti_update_dims_from_array( nifti_image * nim ) { int c, ndim; if( !nim ){ fprintf(stderr,"** update_dims: missing nim\n"); return 1; } if( g_opts.debug > 2 ){ fprintf(stderr,"+d updating image dimensions given nim->dim:"); for( c = 0; c < 8; c++ ) fprintf(stderr," %d", nim->dim[c]); fputc('\n',stderr); } /* verify dim[0] first */ if(nim->dim[0] < 1 || nim->dim[0] > 7){ fprintf(stderr,"** invalid dim[0], dim[] = "); for( c = 0; c < 8; c++ ) fprintf(stderr," %d", nim->dim[c]); fputc('\n',stderr); return 1; } /* set nx, ny ..., dx, dy, ..., one by one */ /* less than 1, set to 1, else copy */ if(nim->dim[1] < 1) nim->nx = nim->dim[1] = 1; else nim->nx = nim->dim[1]; nim->dx = nim->pixdim[1]; /* if undefined, or less than 1, set to 1 */ if(nim->dim[0] < 2 || (nim->dim[0] >= 2 && nim->dim[2] < 1)) nim->ny = nim->dim[2] = 1; else nim->ny = nim->dim[2]; /* copy delta values, in any case */ nim->dy = nim->pixdim[2]; if(nim->dim[0] < 3 || (nim->dim[0] >= 3 && nim->dim[3] < 1)) nim->nz = nim->dim[3] = 1; else /* just copy vals from arrays */ nim->nz = nim->dim[3]; nim->dz = nim->pixdim[3]; if(nim->dim[0] < 4 || (nim->dim[0] >= 4 && nim->dim[4] < 1)) nim->nt = nim->dim[4] = 1; else /* just copy vals from arrays */ nim->nt = nim->dim[4]; nim->dt = nim->pixdim[4]; if(nim->dim[0] < 5 || (nim->dim[0] >= 5 && nim->dim[5] < 1)) nim->nu = nim->dim[5] = 1; else /* just copy vals from arrays */ nim->nu = nim->dim[5]; nim->du = nim->pixdim[5]; if(nim->dim[0] < 6 || (nim->dim[0] >= 6 && nim->dim[6] < 1)) nim->nv = nim->dim[6] = 1; else /* just copy vals from arrays */ nim->nv = nim->dim[6]; nim->dv = nim->pixdim[6]; if(nim->dim[0] < 7 || (nim->dim[0] >= 7 && nim->dim[7] < 1)) nim->nw = nim->dim[7] = 1; else /* just copy vals from arrays */ nim->nw = nim->dim[7]; nim->dw = nim->pixdim[7]; for( c = 1, nim->nvox = 1; c <= nim->dim[0]; c++ ) nim->nvox *= nim->dim[c]; /* compute ndim, assuming it can be no larger than the old one */ for( ndim = nim->dim[0]; (ndim > 1) && (nim->dim[ndim] <= 1); ndim-- ) ; if( g_opts.debug > 2 ){ fprintf(stderr,"+d ndim = %d -> %d\n",nim->ndim, ndim); fprintf(stderr," --> (%d,%d,%d,%d,%d,%d,%d)\n", nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->nv, nim->nw); } nim->dim[0] = nim->ndim = ndim; return 0; } /*----------------------------------------------------------------------*/ /*! Load the image data from disk into an already-prepared image struct. * * \param nim - initialized nifti_image, without data * \param nbricks - the length of blist (must be 0 if blist is NULL) * \param blist - an array of xyz volume indices to read (can be NULL) * \param NBL - pointer to struct where resulting data will be stored * * If blist is NULL, read all sub-bricks. * * \return the number of loaded bricks (NBL->nbricks), * 0 on failure, < 0 on error * * NOTE: it is likely that another function will copy the data pointers * out of NBL, in which case the only pointer the calling function * will want to free is NBL->bricks (not each NBL->bricks[i]). *//*--------------------------------------------------------------------*/ int nifti_image_load_bricks( nifti_image * nim , int nbricks, const int * blist, nifti_brick_list * NBL ) { int * slist = NULL, * sindex = NULL, rv; znzFile fp; /* we can have blist == NULL */ if( !nim || !NBL ){ fprintf(stderr,"** nifti_image_load_bricks, bad params (%p,%p)\n", (void *)nim, (void *)NBL); return -1; } if( blist && nbricks <= 0 ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d load_bricks: received blist with nbricks = %d," "ignoring blist\n", nbricks); blist = NULL; /* pretend nothing was passed */ } if( blist && ! valid_nifti_brick_list(nim, nbricks, blist, g_opts.debug>0) ) return -1; /* for efficiency, let's read the file in order */ if( blist && nifti_copynsort( nbricks, blist, &slist, &sindex ) != 0 ) return -1; /* open the file and position the FILE pointer */ fp = nifti_image_load_prep( nim ); if( !fp ){ if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_image_load_bricks, failed load_prep\n"); if( blist ){ free(slist); free(sindex); } return -1; } /* this will flag to allocate defaults */ if( !blist ) nbricks = 0; if( nifti_alloc_NBL_mem( nim, nbricks, NBL ) != 0 ){ if( blist ){ free(slist); free(sindex); } znzclose(fp); return -1; } rv = nifti_load_NBL_bricks(nim, slist, sindex, NBL, fp); if( rv != 0 ){ nifti_free_NBL( NBL ); /* failure! */ NBL->nbricks = 0; /* repetative, but clear */ } if( slist ){ free(slist); free(sindex); } znzclose(fp); return NBL->nbricks; } /*----------------------------------------------------------------------*/ /*! nifti_free_NBL - free all pointers and clear structure * * note: this does not presume to free the structure pointer *//*--------------------------------------------------------------------*/ void nifti_free_NBL( nifti_brick_list * NBL ) { int c; if( NBL->bricks ){ for( c = 0; c < NBL->nbricks; c++ ) if( NBL->bricks[c] ) free(NBL->bricks[c]); free(NBL->bricks); NBL->bricks = NULL; } NBL->bsize = NBL->nbricks = 0; } /*---------------------------------------------------------------------- * nifti_load_NBL_bricks - read the file data into the NBL struct * * return 0 on success, -1 on failure *----------------------------------------------------------------------*/ static int nifti_load_NBL_bricks( nifti_image * nim , const int * slist, const int * sindex, nifti_brick_list * NBL, znzFile fp ) { size_t oposn, fposn; /* orig and current file positions */ size_t rv; long test; int c; int prev, isrc, idest; /* previous and current sub-brick, and new index */ test = znztell(fp); /* store current file position */ if( test < 0 ){ fprintf(stderr,"** load bricks: ztell failed??\n"); return -1; } fposn = oposn = test; /* first, handle the default case, no passed blist */ if( !slist ){ for( c = 0; c < NBL->nbricks; c++ ) { rv = nifti_read_buffer(fp, NBL->bricks[c], NBL->bsize, nim); if( rv != NBL->bsize ){ fprintf(stderr,"** load bricks: cannot read brick %d from '%s'\n", c, nim->iname ? nim->iname : nim->fname); return -1; } } if( g_opts.debug > 1 ) fprintf(stderr,"+d read %d default %u-byte bricks from file %s\n", NBL->nbricks, (unsigned int)NBL->bsize, nim->iname ? nim->iname:nim->fname ); return 0; } if( !sindex ){ fprintf(stderr,"** load_NBL_bricks: missing index list\n"); return -1; } prev = -1; /* use prev for previous sub-brick */ for( c = 0; c < NBL->nbricks; c++ ){ isrc = slist[c]; /* this is original brick index (c is new one) */ idest = sindex[c]; /* this is the destination index for this data */ /* if this sub-brick is not the previous, we must read from disk */ if( isrc != prev ){ /* if we are not looking at the correct sub-brick, scan forward */ if( fposn != (oposn + isrc*NBL->bsize) ){ fposn = oposn + isrc*NBL->bsize; if( znzseek(fp, (long)fposn, SEEK_SET) < 0 ){ fprintf(stderr,"** failed to locate brick %d in file '%s'\n", isrc, nim->iname ? nim->iname : nim->fname); return -1; } } /* only 10,000 lines later and we're actually reading something! */ rv = nifti_read_buffer(fp, NBL->bricks[idest], NBL->bsize, nim); if( rv != NBL->bsize ){ fprintf(stderr,"** failed to read brick %d from file '%s'\n", isrc, nim->iname ? nim->iname : nim->fname); if( g_opts.debug > 1 ) fprintf(stderr," (read %u of %u bytes)\n", (unsigned int)rv, (unsigned int)NBL->bsize); return -1; } fposn += NBL->bsize; } else { /* we have already read this sub-brick, just copy the previous one */ /* note that this works because they are sorted */ memcpy(NBL->bricks[idest], NBL->bricks[sindex[c-1]], NBL->bsize); } prev = isrc; /* in any case, note the now previous sub-brick */ } return 0; } /*---------------------------------------------------------------------- * nifti_alloc_NBL_mem - allocate memory for bricks * * return 0 on success, -1 on failure *----------------------------------------------------------------------*/ static int nifti_alloc_NBL_mem(nifti_image * nim, int nbricks, nifti_brick_list * nbl) { int c; /* if nbricks is not specified, use the default */ if( nbricks > 0 ) nbl->nbricks = nbricks; else { /* I missed this one with the 1.17 change 02 Mar 2006 [rickr] */ nbl->nbricks = 1; for( c = 4; c <= nim->ndim; c++ ) nbl->nbricks *= nim->dim[c]; } nbl->bsize = (size_t)nim->nx * nim->ny * nim->nz * nim->nbyper;/* bytes */ nbl->bricks = (void **)malloc(nbl->nbricks * sizeof(void *)); if( ! nbl->bricks ){ fprintf(stderr,"** NANM: failed to alloc %d void ptrs\n",nbricks); return -1; } for( c = 0; c < nbl->nbricks; c++ ){ nbl->bricks[c] = (void *)malloc(nbl->bsize); if( ! nbl->bricks[c] ){ fprintf(stderr,"** NANM: failed to alloc %u bytes for brick %d\n", (unsigned int)nbl->bsize, c); /* so free and clear everything before returning */ while( c > 0 ){ c--; free(nbl->bricks[c]); } free(nbl->bricks); nbl->bricks = NULL; nbl->bsize = nbl->nbricks = 0; return -1; } } if( g_opts.debug > 2 ) fprintf(stderr,"+d NANM: alloc'd %d bricks of %u bytes for NBL\n", nbl->nbricks, (unsigned int)nbl->bsize); return 0; } /*---------------------------------------------------------------------- * nifti_copynsort - copy int list, and sort with indices * * 1. duplicate the incoming list * 2. create an sindex list, and init with 0..nbricks-1 * 3. do a slow insertion sort on the small slist, along with sindex list * 4. check results, just to be positive * * So slist is sorted, and sindex hold original positions. * * return 0 on success, -1 on failure *----------------------------------------------------------------------*/ static int nifti_copynsort(int nbricks, const int * blist, int ** slist, int ** sindex) { int * stmp, * itmp; /* for ease of typing/reading */ int c1, c2, spos, tmp; *slist = (int *)malloc(nbricks * sizeof(int)); *sindex = (int *)malloc(nbricks * sizeof(int)); if( !*slist || !*sindex ){ fprintf(stderr,"** NCS: failed to alloc %d ints for sorting\n",nbricks); if(*slist) free(*slist); /* maybe one succeeded */ if(*sindex) free(*sindex); return -1; } /* init the lists */ memcpy(*slist, blist, nbricks*sizeof(int)); for( c1 = 0; c1 < nbricks; c1++ ) (*sindex)[c1] = c1; /* now actually sort slist */ stmp = *slist; itmp = *sindex; for( c1 = 0; c1 < nbricks-1; c1++ ) { /* find smallest value, init to current */ spos = c1; for( c2 = c1+1; c2 < nbricks; c2++ ) if( stmp[c2] < stmp[spos] ) spos = c2; if( spos != c1 ) /* swap: fine, don't maintain sub-order, see if I care */ { tmp = stmp[c1]; /* first swap the sorting values */ stmp[c1] = stmp[spos]; stmp[spos] = tmp; tmp = itmp[c1]; /* then swap the index values */ itmp[c1] = itmp[spos]; itmp[spos] = tmp; } } if( g_opts.debug > 2 ){ fprintf(stderr, "+d sorted indexing list:\n"); fprintf(stderr, " orig : "); for( c1 = 0; c1 < nbricks; c1++ ) fprintf(stderr," %d",blist[c1]); fprintf(stderr,"\n new : "); for( c1 = 0; c1 < nbricks; c1++ ) fprintf(stderr," %d",stmp[c1]); fprintf(stderr,"\n indices: "); for( c1 = 0; c1 < nbricks; c1++ ) fprintf(stderr," %d",itmp[c1]); fputc('\n', stderr); } /* check the sort (why not? I've got time...) */ for( c1 = 0; c1 < nbricks-1; c1++ ){ if( (stmp[c1] > stmp[c1+1]) || (blist[itmp[c1]] != stmp[c1]) ){ fprintf(stderr,"** sorting screw-up, way to go, rick!\n"); free(stmp); free(itmp); *slist = NULL; *sindex = NULL; return -1; } } if( g_opts.debug > 2 ) fprintf(stderr,"-d sorting is okay\n"); return 0; } /*----------------------------------------------------------------------*/ /*! valid_nifti_brick_list - check sub-brick list for image * * This function verifies that nbricks and blist are appropriate * for use with this nim, based on the dimensions. * * \param nim nifti_image to check against * \param nbricks number of brick indices in blist * \param blist list of brick indices to check in nim * \param disp_error if this flag is set, report errors to user * * \return 1 if valid, 0 if not *//*--------------------------------------------------------------------*/ int valid_nifti_brick_list(nifti_image * nim , int nbricks, const int * blist, int disp_error) { int c, nsubs; if( !nim ){ if( disp_error || g_opts.debug > 0 ) fprintf(stderr,"** valid_nifti_brick_list: missing nifti image\n"); return 0; } if( nbricks <= 0 || !blist ){ if( disp_error || g_opts.debug > 1 ) fprintf(stderr,"** valid_nifti_brick_list: no brick list to check\n"); return 0; } if( nim->dim[0] < 3 ){ if( disp_error || g_opts.debug > 1 ) fprintf(stderr,"** cannot read explict brick list from %d-D dataset\n", nim->dim[0]); return 0; } /* nsubs sub-brick is nt*nu*nv*nw */ for( c = 4, nsubs = 1; c <= nim->dim[0]; c++ ) nsubs *= nim->dim[c]; if( nsubs <= 0 ){ fprintf(stderr,"** VNBL warning: bad dim list (%d,%d,%d,%d)\n", nim->dim[4], nim->dim[5], nim->dim[6], nim->dim[7]); return 0; } for( c = 0; c < nbricks; c++ ) if( (blist[c] < 0) || (blist[c] >= nsubs) ){ if( disp_error || g_opts.debug > 1 ) fprintf(stderr, "** volume index %d (#%d) is out of range [0,%d]\n", blist[c], c, nsubs-1); return 0; } return 1; /* all is well */ } /*----------------------------------------------------------------------*/ /* verify that NBL struct is a valid data source for the image * * return 1 if so, 0 otherwise *//*--------------------------------------------------------------------*/ static int nifti_NBL_matches_nim(const nifti_image *nim, const nifti_brick_list *NBL) { size_t volbytes = 0; /* bytes per volume */ int ind, errs = 0, nvols = 0; if( !nim || !NBL ) { if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_NBL_matches_nim: NULL pointer(s)\n"); return 0; } /* for nim, compute volbytes and nvols */ if( nim->ndim > 0 ) { /* first 3 indices are over a single volume */ volbytes = (size_t)nim->nbyper; for( ind = 1; ind <= nim->ndim && ind < 4; ind++ ) volbytes *= (size_t)nim->dim[ind]; for( ind = 4, nvols = 1; ind <= nim->ndim; ind++ ) nvols *= nim->dim[ind]; } if( volbytes != NBL->bsize ) { if( g_opts.debug > 1 ) fprintf(stderr,"** NBL/nim mismatch, volbytes = %u, %u\n", (unsigned)NBL->bsize, (unsigned)volbytes); errs++; } if( nvols != NBL->nbricks ) { if( g_opts.debug > 1 ) fprintf(stderr,"** NBL/nim mismatch, nvols = %d, %d\n", NBL->nbricks, nvols); errs++; } if( errs ) return 0; else if ( g_opts.debug > 2 ) fprintf(stderr,"-- nim/NBL agree: nvols = %d, nbytes = %u\n", nvols, (unsigned)volbytes); return 1; } /* end of new nifti_image_read_bricks() functionality */ /*----------------------------------------------------------------------*/ /*! display the orientation from the quaternian fields * * \param mesg if non-NULL, display this message first * \param mat the matrix to convert to "nearest" orientation * * \return -1 if results cannot be determined, 0 if okay *//*--------------------------------------------------------------------*/ int nifti_disp_matrix_orient( const char * mesg, mat44 mat ) { int i, j, k; if ( mesg ) fputs( mesg, stderr ); /* use stdout? */ nifti_mat44_to_orientation( mat, &i,&j,&k ); if ( i <= 0 || j <= 0 || k <= 0 ) return -1; /* so we have good codes */ fprintf(stderr, " 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; } /*----------------------------------------------------------------------*/ /*! duplicate the given string (alloc length+1) * * \return allocated pointer (or NULL on failure) *//*--------------------------------------------------------------------*/ char *nifti_strdup(const char *str) { char *dup; if( !str ) return NULL; /* allow calls passing NULL */ dup = (char *)malloc(strlen(str) + 1); /* check for failure */ if( dup ) strcpy(dup, str); else fprintf(stderr,"** nifti_strdup: failed to alloc %u bytes\n", (unsigned int)strlen(str)+1); return dup; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI datatype. \param dt NIfTI-1 datatype \return pointer to static string holding the datatype name \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_DATATYPES group in nifti1.h *//*-------------------------------------------------------------------------*/ char const * nifti_datatype_string( int dt ) { switch( dt ){ case DT_UNKNOWN: return "UNKNOWN" ; case DT_BINARY: return "BINARY" ; case DT_INT8: return "INT8" ; case DT_UINT8: return "UINT8" ; case DT_INT16: return "INT16" ; case DT_UINT16: return "UINT16" ; case DT_INT32: return "INT32" ; case DT_UINT32: return "UINT32" ; case DT_INT64: return "INT64" ; case DT_UINT64: return "UINT64" ; case DT_FLOAT32: return "FLOAT32" ; case DT_FLOAT64: return "FLOAT64" ; case DT_FLOAT128: return "FLOAT128" ; case DT_COMPLEX64: return "COMPLEX64" ; case DT_COMPLEX128: return "COMPLEX128" ; case DT_COMPLEX256: return "COMPLEX256" ; case DT_RGB24: return "RGB24" ; case DT_RGBA32: return "RGBA32" ; } return "**ILLEGAL**" ; } /*----------------------------------------------------------------------*/ /*! Determine if the datatype code dt is an integer type (1=YES, 0=NO). \return whether the given NIfTI-1 datatype code is valid \sa NIFTI1_DATATYPES group in nifti1.h *//*--------------------------------------------------------------------*/ int nifti_is_inttype( int dt ) { switch( dt ){ case DT_UNKNOWN: return 0 ; case DT_BINARY: return 0 ; case DT_INT8: return 1 ; case DT_UINT8: return 1 ; case DT_INT16: return 1 ; case DT_UINT16: return 1 ; case DT_INT32: return 1 ; case DT_UINT32: return 1 ; case DT_INT64: return 1 ; case DT_UINT64: return 1 ; case DT_FLOAT32: return 0 ; case DT_FLOAT64: return 0 ; case DT_FLOAT128: return 0 ; case DT_COMPLEX64: return 0 ; case DT_COMPLEX128: return 0 ; case DT_COMPLEX256: return 0 ; case DT_RGB24: return 1 ; case DT_RGBA32: return 1 ; } return 0 ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI units type. \param uu NIfTI-1 unit code \return pointer to static string for the given unit type \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_UNITS group in nifti1.h *//*-------------------------------------------------------------------------*/ char const *nifti_units_string( int uu ) { switch( uu ){ case NIFTI_UNITS_METER: return "m" ; case NIFTI_UNITS_MM: return "mm" ; case NIFTI_UNITS_MICRON: return "um" ; case NIFTI_UNITS_SEC: return "s" ; case NIFTI_UNITS_MSEC: return "ms" ; case NIFTI_UNITS_USEC: return "us" ; case NIFTI_UNITS_HZ: return "Hz" ; case NIFTI_UNITS_PPM: return "ppm" ; case NIFTI_UNITS_RADS: return "rad/s" ; } return "Unknown" ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI transform type. \param xx NIfTI-1 xform code \return pointer to static string describing xform code \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_XFORM_CODES group in nifti1.h *//*-------------------------------------------------------------------------*/ char const *nifti_xform_string( int xx ) { switch( xx ){ case NIFTI_XFORM_SCANNER_ANAT: return "Scanner Anat" ; case NIFTI_XFORM_ALIGNED_ANAT: return "Aligned Anat" ; case NIFTI_XFORM_TALAIRACH: return "Talairach" ; case NIFTI_XFORM_MNI_152: return "MNI_152" ; } return "Unknown" ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI intent type. \param ii NIfTI-1 intent code \return pointer to static string describing code \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_INTENT_CODES group in nifti1.h *//*-------------------------------------------------------------------------*/ char const *nifti_intent_string( int ii ) { switch( ii ){ case NIFTI_INTENT_CORREL: return "Correlation statistic" ; case NIFTI_INTENT_TTEST: return "T-statistic" ; case NIFTI_INTENT_FTEST: return "F-statistic" ; case NIFTI_INTENT_ZSCORE: return "Z-score" ; case NIFTI_INTENT_CHISQ: return "Chi-squared distribution" ; case NIFTI_INTENT_BETA: return "Beta distribution" ; case NIFTI_INTENT_BINOM: return "Binomial distribution" ; case NIFTI_INTENT_GAMMA: return "Gamma distribution" ; case NIFTI_INTENT_POISSON: return "Poisson distribution" ; case NIFTI_INTENT_NORMAL: return "Normal distribution" ; case NIFTI_INTENT_FTEST_NONC: return "F-statistic noncentral" ; case NIFTI_INTENT_CHISQ_NONC: return "Chi-squared noncentral" ; case NIFTI_INTENT_LOGISTIC: return "Logistic distribution" ; case NIFTI_INTENT_LAPLACE: return "Laplace distribution" ; case NIFTI_INTENT_UNIFORM: return "Uniform distribition" ; case NIFTI_INTENT_TTEST_NONC: return "T-statistic noncentral" ; case NIFTI_INTENT_WEIBULL: return "Weibull distribution" ; case NIFTI_INTENT_CHI: return "Chi distribution" ; case NIFTI_INTENT_INVGAUSS: return "Inverse Gaussian distribution" ; case NIFTI_INTENT_EXTVAL: return "Extreme Value distribution" ; case NIFTI_INTENT_PVAL: return "P-value" ; case NIFTI_INTENT_LOGPVAL: return "Log P-value" ; case NIFTI_INTENT_LOG10PVAL: return "Log10 P-value" ; case NIFTI_INTENT_ESTIMATE: return "Estimate" ; case NIFTI_INTENT_LABEL: return "Label index" ; case NIFTI_INTENT_NEURONAME: return "NeuroNames index" ; case NIFTI_INTENT_GENMATRIX: return "General matrix" ; case NIFTI_INTENT_SYMMATRIX: return "Symmetric matrix" ; case NIFTI_INTENT_DISPVECT: return "Displacement vector" ; case NIFTI_INTENT_VECTOR: return "Vector" ; case NIFTI_INTENT_POINTSET: return "Pointset" ; case NIFTI_INTENT_TRIANGLE: return "Triangle" ; case NIFTI_INTENT_QUATERNION: return "Quaternion" ; case NIFTI_INTENT_DIMLESS: return "Dimensionless number" ; } return "Unknown" ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI slice_code. \param ss NIfTI-1 slice order code \return pointer to static string describing code \warning Do not free() or modify this string! It points to static storage. \sa NIFTI1_SLICE_ORDER group in nifti1.h *//*-------------------------------------------------------------------------*/ char const *nifti_slice_string( int ss ) { switch( ss ){ case NIFTI_SLICE_SEQ_INC: return "sequential_increasing" ; case NIFTI_SLICE_SEQ_DEC: return "sequential_decreasing" ; case NIFTI_SLICE_ALT_INC: return "alternating_increasing" ; case NIFTI_SLICE_ALT_DEC: return "alternating_decreasing" ; case NIFTI_SLICE_ALT_INC2: return "alternating_increasing_2" ; case NIFTI_SLICE_ALT_DEC2: return "alternating_decreasing_2" ; } return "Unknown" ; } /*---------------------------------------------------------------------------*/ /*! Return a pointer to a string holding the name of a NIFTI orientation. \param ii orientation code \return pointer to static string holding the orientation information \warning Do not free() or modify the return string! It points to static storage. \sa NIFTI_L2R in nifti1_io.h *//*-------------------------------------------------------------------------*/ char const *nifti_orientation_string( int ii ) { switch( ii ){ case NIFTI_L2R: return "Left-to-Right" ; case NIFTI_R2L: return "Right-to-Left" ; case NIFTI_P2A: return "Posterior-to-Anterior" ; case NIFTI_A2P: return "Anterior-to-Posterior" ; case NIFTI_I2S: return "Inferior-to-Superior" ; case NIFTI_S2I: return "Superior-to-Inferior" ; } return "Unknown" ; } /*--------------------------------------------------------------------------*/ /*! Given a datatype code, set number of bytes per voxel and the swapsize. \param datatype nifti1 datatype code \param nbyper pointer to return value: number of bytes per voxel \param swapsize pointer to return value: size of swap blocks \return appropriate values at nbyper and swapsize The swapsize is set to 0 if this datatype doesn't ever need swapping. \sa NIFTI1_DATATYPES in nifti1.h *//*------------------------------------------------------------------------*/ void nifti_datatype_sizes( int datatype , int *nbyper, int *swapsize ) { int nb=0, ss=0 ; switch( datatype ){ case DT_INT8: case DT_UINT8: nb = 1 ; ss = 0 ; break ; case DT_INT16: case DT_UINT16: nb = 2 ; ss = 2 ; break ; case DT_RGB24: nb = 3 ; ss = 0 ; break ; case DT_RGBA32: nb = 4 ; ss = 0 ; break ; case DT_INT32: case DT_UINT32: case DT_FLOAT32: nb = 4 ; ss = 4 ; break ; case DT_COMPLEX64: nb = 8 ; ss = 4 ; break ; case DT_FLOAT64: case DT_INT64: case DT_UINT64: nb = 8 ; ss = 8 ; break ; case DT_FLOAT128: nb = 16 ; ss = 16 ; break ; case DT_COMPLEX128: nb = 16 ; ss = 8 ; break ; case DT_COMPLEX256: nb = 32 ; ss = 16 ; break ; } ASSIF(nbyper,nb) ; ASSIF(swapsize,ss) ; } /*---------------------------------------------------------------------------*/ /*! Given the quaternion parameters (etc.), compute a transformation matrix. See comments in nifti1.h for details. - qb,qc,qd = quaternion parameters - qx,qy,qz = offset parameters - dx,dy,dz = grid stepsizes (non-negative inputs are set to 1.0) - qfac = sign of dz step (< 0 is negative; >= 0 is positive)
   If qx=qy=qz=0, dx=dy=dz=1, then the output is a rotation matrix.
   For qfac >= 0, the rotation is proper.
   For qfac <  0, the rotation is improper.
   
\see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h \see nifti_mat44_to_quatern, nifti_make_orthog_mat44, nifti_mat44_to_orientation *//*-------------------------------------------------------------------------*/ mat44 nifti_quatern_to_mat44( float qb, float qc, float qd, float qx, float qy, float qz, float dx, float dy, float dz, float qfac ) { mat44 R ; double a,b=qb,c=qc,d=qd , xd,yd,zd ; /* last row is always [ 0 0 0 1 ] */ R.m[3][0]=R.m[3][1]=R.m[3][2] = 0.0f ; R.m[3][3]= 1.0f ; /* compute a parameter from b,c,d */ a = 1.0l - (b*b + c*c + d*d) ; if( a < 1.e-7l ){ /* special case */ a = 1.0l / sqrt(b*b+c*c+d*d) ; b *= a ; c *= a ; d *= a ; /* normalize (b,c,d) vector */ a = 0.0l ; /* a = 0 ==> 180 degree rotation */ } else{ a = sqrt(a) ; /* angle = 2*arccos(a) */ } /* load rotation matrix, including scaling factors for voxel sizes */ xd = (dx > 0.0) ? dx : 1.0l ; /* make sure are positive */ yd = (dy > 0.0) ? dy : 1.0l ; zd = (dz > 0.0) ? dz : 1.0l ; if( qfac < 0.0 ) zd = -zd ; /* left handedness? */ R.m[0][0] = (float)( (a*a+b*b-c*c-d*d) * xd) ; R.m[0][1] = 2.0l * (b*c-a*d ) * yd ; R.m[0][2] = 2.0l * (b*d+a*c ) * zd ; R.m[1][0] = 2.0l * (b*c+a*d ) * xd ; R.m[1][1] = (float)( (a*a+c*c-b*b-d*d) * yd) ; R.m[1][2] = 2.0l * (c*d-a*b ) * zd ; R.m[2][0] = 2.0l * (b*d-a*c ) * xd ; R.m[2][1] = 2.0l * (c*d+a*b ) * yd ; R.m[2][2] = (float)( (a*a+d*d-c*c-b*b) * zd) ; /* load offsets */ R.m[0][3] = qx ; R.m[1][3] = qy ; R.m[2][3] = qz ; return R ; } /*---------------------------------------------------------------------------*/ /*! Given the 3x4 upper corner of the matrix R, compute the quaternion parameters that fit it. - Any NULL pointer on input won't get assigned (e.g., if you don't want dx,dy,dz, just pass NULL in for those pointers). - If the 3 input matrix columns are NOT orthogonal, they will be orthogonalized prior to calculating the parameters, using the polar decomposition to find the orthogonal matrix closest to the column-normalized input matrix. - However, if the 3 input matrix columns are NOT orthogonal, then the matrix produced by nifti_quatern_to_mat44 WILL have orthogonal columns, so it won't be the same as the matrix input here. This "feature" is because the NIFTI 'qform' transform is deliberately not fully general -- it is intended to model a volume with perpendicular axes. - If the 3 input matrix columns are not even linearly independent, you'll just have to take your luck, won't you? \see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h \see nifti_quatern_to_mat44, nifti_make_orthog_mat44, nifti_mat44_to_orientation *//*-------------------------------------------------------------------------*/ void nifti_mat44_to_quatern( mat44 R , float *qb, float *qc, float *qd, float *qx, float *qy, float *qz, float *dx, float *dy, float *dz, float *qfac ) { double r11,r12,r13 , r21,r22,r23 , r31,r32,r33 ; double xd,yd,zd , a,b,c,d ; mat33 P,Q ; /* offset outputs are read write out of input matrix */ ASSIF(qx,R.m[0][3]) ; ASSIF(qy,R.m[1][3]) ; ASSIF(qz,R.m[2][3]) ; /* load 3x3 matrix into local variables */ r11 = R.m[0][0] ; r12 = R.m[0][1] ; r13 = R.m[0][2] ; r21 = R.m[1][0] ; r22 = R.m[1][1] ; r23 = R.m[1][2] ; r31 = R.m[2][0] ; r32 = R.m[2][1] ; r33 = R.m[2][2] ; /* compute lengths of each column; these determine grid spacings */ xd = sqrt( r11*r11 + r21*r21 + r31*r31 ) ; yd = sqrt( r12*r12 + r22*r22 + r32*r32 ) ; zd = sqrt( r13*r13 + r23*r23 + r33*r33 ) ; /* if a column length is zero, patch the trouble */ if( xd == 0.0l ){ r11 = 1.0l ; r21 = r31 = 0.0l ; xd = 1.0l ; } if( yd == 0.0l ){ r22 = 1.0l ; r12 = r32 = 0.0l ; yd = 1.0l ; } if( zd == 0.0l ){ r33 = 1.0l ; r13 = r23 = 0.0l ; zd = 1.0l ; } /* assign the output lengths */ ASSIF(dx,(float)xd) ; ASSIF(dy,(float)yd) ; ASSIF(dz,(float)zd) ; /* normalize the columns */ r11 /= xd ; r21 /= xd ; r31 /= xd ; r12 /= yd ; r22 /= yd ; r32 /= yd ; r13 /= zd ; r23 /= zd ; r33 /= zd ; /* At this point, the matrix has normal columns, but we have to allow for the fact that the hideous user may not have given us a matrix with orthogonal columns. So, now find the orthogonal matrix closest to the current matrix. One reason for using the polar decomposition to get this orthogonal matrix, rather than just directly orthogonalizing the columns, is so that inputting the inverse matrix to R will result in the inverse orthogonal matrix at this point. If we just orthogonalized the columns, this wouldn't necessarily hold. */ Q.m[0][0] = (float)r11 ; Q.m[0][1] = (float)r12 ; Q.m[0][2] = (float)r13 ; /* load Q */ Q.m[1][0] = (float)r21 ; Q.m[1][1] = (float)r22 ; Q.m[1][2] = (float)r23 ; Q.m[2][0] = (float)r31 ; Q.m[2][1] = (float)r32 ; Q.m[2][2] = (float)r33 ; P = nifti_mat33_polar(Q) ; /* P is orthog matrix closest to Q */ r11 = P.m[0][0] ; r12 = P.m[0][1] ; r13 = P.m[0][2] ; /* unload */ r21 = P.m[1][0] ; r22 = P.m[1][1] ; r23 = P.m[1][2] ; r31 = P.m[2][0] ; r32 = P.m[2][1] ; r33 = P.m[2][2] ; /* [ r11 r12 r13 ] */ /* at this point, the matrix [ r21 r22 r23 ] is orthogonal */ /* [ r31 r32 r33 ] */ /* compute the determinant to determine if it is proper */ zd = r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; /* should be -1 or 1 */ if( zd > 0 ){ /* proper */ ASSIF(qfac,1.0f) ; } else { /* improper ==> flip 3rd column */ ASSIF(qfac,-1.0f) ; r13 = -r13 ; r23 = -r23 ; r33 = -r33 ; } /* now, compute quaternion parameters */ a = r11 + r22 + r33 + 1.0l ; if( a > 0.5l ){ /* simplest case */ a = 0.5l * sqrt(a) ; b = 0.25l * (r32-r23) / a ; c = 0.25l * (r13-r31) / a ; d = 0.25l * (r21-r12) / a ; } else { /* trickier case */ xd = 1.0 + r11 - (r22+r33) ; /* 4*b*b */ yd = 1.0 + r22 - (r11+r33) ; /* 4*c*c */ zd = 1.0 + r33 - (r11+r22) ; /* 4*d*d */ if( xd > 1.0 ){ b = 0.5l * sqrt(xd) ; c = 0.25l* (r12+r21) / b ; d = 0.25l* (r13+r31) / b ; a = 0.25l* (r32-r23) / b ; } else if( yd > 1.0 ){ c = 0.5l * sqrt(yd) ; b = 0.25l* (r12+r21) / c ; d = 0.25l* (r23+r32) / c ; a = 0.25l* (r13-r31) / c ; } else { d = 0.5l * sqrt(zd) ; b = 0.25l* (r13+r31) / d ; c = 0.25l* (r23+r32) / d ; a = 0.25l* (r21-r12) / d ; } if( a < 0.0l ){ b=-b ; c=-c ; d=-d;} } ASSIF(qb,(float)b) ; ASSIF(qc,(float)c) ; ASSIF(qd,(float)d); } /*---------------------------------------------------------------------------*/ /*! Compute the inverse of a bordered 4x4 matrix.
   - Some numerical code fragments were generated by Maple 8.
   - If a singular matrix is input, the output matrix will be all zero.
   - You can check for this by examining the [3][3] element, which will
     be 1.0 for the normal case and 0.0 for the bad case.

     The input matrix should have the form:
        [ r11 r12 r13 v1 ]
        [ r21 r22 r23 v2 ]
        [ r31 r32 r33 v3 ]
        [  0   0   0   1 ]
     
*//*-------------------------------------------------------------------------*/ mat44 nifti_mat44_inverse( mat44 R ) { double r11,r12,r13,r21,r22,r23,r31,r32,r33,v1,v2,v3 , deti ; mat44 Q ; /* INPUT MATRIX IS: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 v1 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 v2 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 v3 ] */ v1 = R.m[0][3]; v2 = R.m[1][3]; v3 = R.m[2][3]; /* [ 0 0 0 1 ] */ deti = r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; if( deti != 0.0l ) deti = 1.0l / deti ; Q.m[0][0] = (float)( deti*( r22*r33-r32*r23) ) ; Q.m[0][1] = (float)( deti*(-r12*r33+r32*r13) ) ; Q.m[0][2] = (float)( deti*( r12*r23-r22*r13) ) ; Q.m[0][3] = (float)( deti*(-r12*r23*v3+r12*v2*r33+r22*r13*v3 -r22*v1*r33-r32*r13*v2+r32*v1*r23) ) ; Q.m[1][0] = (float)( deti*(-r21*r33+r31*r23) ) ; Q.m[1][1] = (float)( deti*( r11*r33-r31*r13) ) ; Q.m[1][2] = (float)( deti*(-r11*r23+r21*r13) ) ; Q.m[1][3] = (float)( deti*( r11*r23*v3-r11*v2*r33-r21*r13*v3 +r21*v1*r33+r31*r13*v2-r31*v1*r23) ) ; Q.m[2][0] = (float)( deti*( r21*r32-r31*r22) ) ; Q.m[2][1] = (float)( deti*(-r11*r32+r31*r12) ) ; Q.m[2][2] = (float)( deti*( r11*r22-r21*r12) ) ; Q.m[2][3] = (float)( deti*(-r11*r22*v3+r11*r32*v2+r21*r12*v3 -r21*r32*v1-r31*r12*v2+r31*r22*v1) ) ; Q.m[3][0] = Q.m[3][1] = Q.m[3][2] = 0.0l ; Q.m[3][3] = (deti == 0.0l) ? 0.0l : 1.0l ; /* failure flag if deti == 0 */ return Q ; } /*---------------------------------------------------------------------------*/ /*! Input 9 floats and make an orthgonal mat44 out of them. Each row is normalized, then nifti_mat33_polar() is used to orthogonalize them. If row #3 (r31,r32,r33) is input as zero, then it will be taken to be the cross product of rows #1 and #2. This function can be used to create a rotation matrix for transforming an oblique volume to anatomical coordinates. For this application: - row #1 (r11,r12,r13) is the direction vector along the image i-axis - row #2 (r21,r22,r23) is the direction vector along the image j-axis - row #3 (r31,r32,r33) is the direction vector along the slice direction (if available; otherwise enter it as 0's) The first 2 rows can be taken from the DICOM attribute (0020,0037) "Image Orientation (Patient)". After forming the rotation matrix, the complete affine transformation from (i,j,k) grid indexes to (x,y,z) spatial coordinates can be computed by multiplying each column by the appropriate grid spacing: - column #1 (R.m[0][0],R.m[1][0],R.m[2][0]) by delta-x - column #2 (R.m[0][1],R.m[1][1],R.m[2][1]) by delta-y - column #3 (R.m[0][2],R.m[1][2],R.m[2][2]) by delta-z and by then placing the center (x,y,z) coordinates of voxel (0,0,0) into the column #4 (R.m[0][3],R.m[1][3],R.m[2][3]). \sa nifti_quatern_to_mat44, nifti_mat44_to_quatern, nifti_mat44_to_orientation *//*-------------------------------------------------------------------------*/ mat44 nifti_make_orthog_mat44( float r11, float r12, float r13 , float r21, float r22, float r23 , float r31, float r32, float r33 ) { mat44 R ; mat33 Q , P ; double val ; R.m[3][0] = R.m[3][1] = R.m[3][2] = 0.0l ; R.m[3][3] = 1.0l ; Q.m[0][0] = r11 ; Q.m[0][1] = r12 ; Q.m[0][2] = r13 ; /* load Q */ Q.m[1][0] = r21 ; Q.m[1][1] = r22 ; Q.m[1][2] = r23 ; Q.m[2][0] = r31 ; Q.m[2][1] = r32 ; Q.m[2][2] = r33 ; /* normalize row 1 */ val = Q.m[0][0]*Q.m[0][0] + Q.m[0][1]*Q.m[0][1] + Q.m[0][2]*Q.m[0][2] ; if( val > 0.0l ){ val = 1.0l / sqrt(val) ; Q.m[0][0] *= (float)val ; Q.m[0][1] *= (float)val ; Q.m[0][2] *= (float)val ; } else { Q.m[0][0] = 1.0l ; Q.m[0][1] = 0.0l ; Q.m[0][2] = 0.0l ; } /* normalize row 2 */ val = Q.m[1][0]*Q.m[1][0] + Q.m[1][1]*Q.m[1][1] + Q.m[1][2]*Q.m[1][2] ; if( val > 0.0l ){ val = 1.0l / sqrt(val) ; Q.m[1][0] *= (float)val ; Q.m[1][1] *= (float)val ; Q.m[1][2] *= (float)val ; } else { Q.m[1][0] = 0.0l ; Q.m[1][1] = 1.0l ; Q.m[1][2] = 0.0l ; } /* normalize row 3 */ val = Q.m[2][0]*Q.m[2][0] + Q.m[2][1]*Q.m[2][1] + Q.m[2][2]*Q.m[2][2] ; if( val > 0.0l ){ val = 1.0l / sqrt(val) ; Q.m[2][0] *= (float)val ; Q.m[2][1] *= (float)val ; Q.m[2][2] *= (float)val ; } else { Q.m[2][0] = Q.m[0][1]*Q.m[1][2] - Q.m[0][2]*Q.m[1][1] ; /* cross */ Q.m[2][1] = Q.m[0][2]*Q.m[1][0] - Q.m[0][0]*Q.m[1][2] ; /* product */ Q.m[2][2] = Q.m[0][0]*Q.m[1][1] - Q.m[0][1]*Q.m[1][0] ; } P = nifti_mat33_polar(Q) ; /* P is orthog matrix closest to Q */ R.m[0][0] = P.m[0][0] ; R.m[0][1] = P.m[0][1] ; R.m[0][2] = P.m[0][2] ; R.m[1][0] = P.m[1][0] ; R.m[1][1] = P.m[1][1] ; R.m[1][2] = P.m[1][2] ; R.m[2][0] = P.m[2][0] ; R.m[2][1] = P.m[2][1] ; R.m[2][2] = P.m[2][2] ; R.m[0][3] = R.m[1][3] = R.m[2][3] = 0.0f ; return R ; } /*----------------------------------------------------------------------*/ /*! compute the inverse of a 3x3 matrix *//*--------------------------------------------------------------------*/ mat33 nifti_mat33_inverse( mat33 R ) /* inverse of 3x3 matrix */ { double r11,r12,r13,r21,r22,r23,r31,r32,r33 , deti ; mat33 Q ; /* INPUT MATRIX: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 ] */ deti = r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13 ; if( deti != 0.0l ) deti = 1.0l / deti ; Q.m[0][0] = (float)( deti*( r22*r33-r32*r23) ) ; Q.m[0][1] = (float)( deti*(-r12*r33+r32*r13) ) ; Q.m[0][2] = (float)( deti*( r12*r23-r22*r13) ) ; Q.m[1][0] = (float)( deti*(-r21*r33+r31*r23) ) ; Q.m[1][1] = (float)( deti*( r11*r33-r31*r13) ) ; Q.m[1][2] = (float)( deti*(-r11*r23+r21*r13) ) ; Q.m[2][0] = (float)( deti*( r21*r32-r31*r22) ) ; Q.m[2][1] = (float)( deti*(-r11*r32+r31*r12) ) ; Q.m[2][2] = (float)( deti*( r11*r22-r21*r12) ) ; return Q ; } /*----------------------------------------------------------------------*/ /*! compute the determinant of a 3x3 matrix *//*--------------------------------------------------------------------*/ float nifti_mat33_determ( mat33 R ) /* determinant of 3x3 matrix */ { double r11,r12,r13,r21,r22,r23,r31,r32,r33 ; /* INPUT MATRIX: */ r11 = R.m[0][0]; r12 = R.m[0][1]; r13 = R.m[0][2]; /* [ r11 r12 r13 ] */ r21 = R.m[1][0]; r22 = R.m[1][1]; r23 = R.m[1][2]; /* [ r21 r22 r23 ] */ r31 = R.m[2][0]; r32 = R.m[2][1]; r33 = R.m[2][2]; /* [ r31 r32 r33 ] */ return (float)(r11*r22*r33-r11*r32*r23-r21*r12*r33 +r21*r32*r13+r31*r12*r23-r31*r22*r13) ; } /*----------------------------------------------------------------------*/ /*! compute the max row norm of a 3x3 matrix *//*--------------------------------------------------------------------*/ float nifti_mat33_rownorm( mat33 A ) /* max row norm of 3x3 matrix */ { float r1,r2,r3 ; r1 = (float)( fabs(A.m[0][0])+fabs(A.m[0][1])+fabs(A.m[0][2]) ) ; r2 = (float)( fabs(A.m[1][0])+fabs(A.m[1][1])+fabs(A.m[1][2]) ) ; r3 = (float)( fabs(A.m[2][0])+fabs(A.m[2][1])+fabs(A.m[2][2]) ) ; if( r1 < r2 ) r1 = r2 ; if( r1 < r3 ) r1 = r3 ; return r1 ; } /*----------------------------------------------------------------------*/ /*! compute the max column norm of a 3x3 matrix *//*--------------------------------------------------------------------*/ float nifti_mat33_colnorm( mat33 A ) /* max column norm of 3x3 matrix */ { float r1,r2,r3 ; r1 = (float)( fabs(A.m[0][0])+fabs(A.m[1][0])+fabs(A.m[2][0]) ) ; r2 = (float)( fabs(A.m[0][1])+fabs(A.m[1][1])+fabs(A.m[2][1]) ) ; r3 = (float)( fabs(A.m[0][2])+fabs(A.m[1][2])+fabs(A.m[2][2]) ) ; if( r1 < r2 ) r1 = r2 ; if( r1 < r3 ) r1 = r3 ; return r1 ; } /*----------------------------------------------------------------------*/ /*! multiply 2 3x3 matrices *//*--------------------------------------------------------------------*/ mat33 nifti_mat33_mul( mat33 A , mat33 B ) /* multiply 2 3x3 matrices */ { mat33 C ; int i,j ; for( i=0 ; i < 3 ; i++ ) for( j=0 ; j < 3 ; j++ ) C.m[i][j] = A.m[i][0] * B.m[0][j] + A.m[i][1] * B.m[1][j] + A.m[i][2] * B.m[2][j] ; return C ; } /*---------------------------------------------------------------------------*/ /*! polar decomposition of a 3x3 matrix This finds the closest orthogonal matrix to input A (in both the Frobenius and L2 norms). Algorithm is that from NJ Higham, SIAM J Sci Stat Comput, 7:1160-1174. *//*-------------------------------------------------------------------------*/ mat33 nifti_mat33_polar( mat33 A ) { mat33 X , Y , Z ; float alp,bet,gam,gmi , dif=1.0f ; int k=0 ; X = A ; /* force matrix to be nonsingular */ gam = nifti_mat33_determ(X) ; while( gam == 0.0 ){ /* perturb matrix */ gam = (float)( 0.00001 * ( 0.001 + nifti_mat33_rownorm(X) ) ) ; X.m[0][0] += gam ; X.m[1][1] += gam ; X.m[2][2] += gam ; gam = nifti_mat33_determ(X) ; } while(1){ Y = nifti_mat33_inverse(X) ; if( dif > 0.3 ){ /* far from convergence */ alp = (float)( sqrt( nifti_mat33_rownorm(X) * nifti_mat33_colnorm(X) ) ) ; bet = (float)( sqrt( nifti_mat33_rownorm(Y) * nifti_mat33_colnorm(Y) ) ) ; gam = (float)( sqrt( bet / alp ) ) ; gmi = (float)( 1.0 / gam ) ; } else { gam = gmi = 1.0f ; /* close to convergence */ } Z.m[0][0] = (float)( 0.5 * ( gam*X.m[0][0] + gmi*Y.m[0][0] ) ) ; Z.m[0][1] = (float)( 0.5 * ( gam*X.m[0][1] + gmi*Y.m[1][0] ) ) ; Z.m[0][2] = (float)( 0.5 * ( gam*X.m[0][2] + gmi*Y.m[2][0] ) ) ; Z.m[1][0] = (float)( 0.5 * ( gam*X.m[1][0] + gmi*Y.m[0][1] ) ) ; Z.m[1][1] = (float)( 0.5 * ( gam*X.m[1][1] + gmi*Y.m[1][1] ) ) ; Z.m[1][2] = (float)( 0.5 * ( gam*X.m[1][2] + gmi*Y.m[2][1] ) ) ; Z.m[2][0] = (float)( 0.5 * ( gam*X.m[2][0] + gmi*Y.m[0][2] ) ) ; Z.m[2][1] = (float)( 0.5 * ( gam*X.m[2][1] + gmi*Y.m[1][2] ) ) ; Z.m[2][2] = (float)( 0.5 * ( gam*X.m[2][2] + gmi*Y.m[2][2] ) ) ; dif = (float)( fabs(Z.m[0][0]-X.m[0][0])+fabs(Z.m[0][1]-X.m[0][1]) +fabs(Z.m[0][2]-X.m[0][2])+fabs(Z.m[1][0]-X.m[1][0]) +fabs(Z.m[1][1]-X.m[1][1])+fabs(Z.m[1][2]-X.m[1][2]) +fabs(Z.m[2][0]-X.m[2][0])+fabs(Z.m[2][1]-X.m[2][1]) +fabs(Z.m[2][2]-X.m[2][2]) ); k = k+1 ; if( k > 100 || dif < 3.e-6 ) break ; /* convergence or exhaustion */ X = Z ; } return Z ; } /*---------------------------------------------------------------------------*/ /*! compute the (closest) orientation from a 4x4 ijk->xyz tranformation matrix
   Input:  4x4 matrix that transforms (i,j,k) indexes to (x,y,z) coordinates,
           where +x=Right, +y=Anterior, +z=Superior.
           (Only the upper-left 3x3 corner of R is used herein.)
   Output: 3 orientation codes that correspond to the closest "standard"
           anatomical orientation of the (i,j,k) axes.
   Method: Find which permutation of (x,y,z) has the smallest angle to the
           (i,j,k) axes directions, which are the columns of the R matrix.
   Errors: The codes returned will be zero.

   For example, an axial volume might get return values of
     *icod = NIFTI_R2L   (i axis is mostly Right to Left)
     *jcod = NIFTI_P2A   (j axis is mostly Posterior to Anterior)
     *kcod = NIFTI_I2S   (k axis is mostly Inferior to Superior)
   
\see "QUATERNION REPRESENTATION OF ROTATION MATRIX" in nifti1.h \see nifti_quatern_to_mat44, nifti_mat44_to_quatern, nifti_make_orthog_mat44 *//*-------------------------------------------------------------------------*/ void nifti_mat44_to_orientation( mat44 R , int *icod, int *jcod, int *kcod ) { float xi,xj,xk , yi,yj,yk , zi,zj,zk , val,detQ,detP ; mat33 P , Q , M ; int i,j,k=0,p,q,r , ibest,jbest,kbest,pbest,qbest,rbest ; float vbest ; if( icod == NULL || jcod == NULL || kcod == NULL ) return ; /* bad */ *icod = *jcod = *kcod = 0 ; /* error returns, if sh*t happens */ /* load column vectors for each (i,j,k) direction from matrix */ /*-- i axis --*/ /*-- j axis --*/ /*-- k axis --*/ xi = R.m[0][0] ; xj = R.m[0][1] ; xk = R.m[0][2] ; yi = R.m[1][0] ; yj = R.m[1][1] ; yk = R.m[1][2] ; zi = R.m[2][0] ; zj = R.m[2][1] ; zk = R.m[2][2] ; /* normalize column vectors to get unit vectors along each ijk-axis */ /* normalize i axis */ val = (float)sqrt( xi*xi + yi*yi + zi*zi ) ; if( val == 0.0 ) return ; /* stupid input */ xi /= val ; yi /= val ; zi /= val ; /* normalize j axis */ val = (float)sqrt( xj*xj + yj*yj + zj*zj ) ; if( val == 0.0 ) return ; /* stupid input */ xj /= val ; yj /= val ; zj /= val ; /* orthogonalize j axis to i axis, if needed */ val = xi*xj + yi*yj + zi*zj ; /* dot product between i and j */ if( fabs(val) > 1.e-4 ){ xj -= val*xi ; yj -= val*yi ; zj -= val*zi ; val = (float)sqrt( xj*xj + yj*yj + zj*zj ) ; /* must renormalize */ if( val == 0.0 ) return ; /* j was parallel to i? */ xj /= val ; yj /= val ; zj /= val ; } /* normalize k axis; if it is zero, make it the cross product i x j */ val = (float)sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ){ xk = yi*zj-zi*yj; yk = zi*xj-zj*xi ; zk=xi*yj-yi*xj ; } else { xk /= val ; yk /= val ; zk /= val ; } /* orthogonalize k to i */ val = xi*xk + yi*yk + zi*zk ; /* dot product between i and k */ if( fabs(val) > 1.e-4 ){ xk -= val*xi ; yk -= val*yi ; zk -= val*zi ; val = (float)sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ) return ; /* bad */ xk /= val ; yk /= val ; zk /= val ; } /* orthogonalize k to j */ val = xj*xk + yj*yk + zj*zk ; /* dot product between j and k */ if( fabs(val) > 1.e-4 ){ xk -= val*xj ; yk -= val*yj ; zk -= val*zj ; val = (float)sqrt( xk*xk + yk*yk + zk*zk ) ; if( val == 0.0 ) return ; /* bad */ xk /= val ; yk /= val ; zk /= val ; } Q.m[0][0] = xi ; Q.m[0][1] = xj ; Q.m[0][2] = xk ; Q.m[1][0] = yi ; Q.m[1][1] = yj ; Q.m[1][2] = yk ; Q.m[2][0] = zi ; Q.m[2][1] = zj ; Q.m[2][2] = zk ; /* at this point, Q is the rotation matrix from the (i,j,k) to (x,y,z) axes */ detQ = nifti_mat33_determ( Q ) ; if( detQ == 0.0 ) return ; /* shouldn't happen unless user is a DUFIS */ /* Build and test all possible +1/-1 coordinate permutation matrices P; then find the P such that the rotation matrix M=PQ is closest to the identity, in the sense of M having the smallest total rotation angle. */ /* Despite the formidable looking 6 nested loops, there are only 3*3*3*2*2*2 = 216 passes, which will run very quickly. */ vbest = -666.0f ; ibest=pbest=qbest=rbest=1 ; jbest=2 ; kbest=3 ; for( i=1 ; i <= 3 ; i++ ){ /* i = column number to use for row #1 */ for( j=1 ; j <= 3 ; j++ ){ /* j = column number to use for row #2 */ if( i == j ) continue ; for( k=1 ; k <= 3 ; k++ ){ /* k = column number to use for row #3 */ if( i == k || j == k ) continue ; P.m[0][0] = P.m[0][1] = P.m[0][2] = P.m[1][0] = P.m[1][1] = P.m[1][2] = P.m[2][0] = P.m[2][1] = P.m[2][2] = 0.0f ; for( p=-1 ; p <= 1 ; p+=2 ){ /* p,q,r are -1 or +1 */ for( q=-1 ; q <= 1 ; q+=2 ){ /* and go into rows #1,2,3 */ for( r=-1 ; r <= 1 ; r+=2 ){ P.m[0][i-1] = p ; P.m[1][j-1] = q ; P.m[2][k-1] = r ; detP = nifti_mat33_determ(P) ; /* sign of permutation */ if( detP * detQ <= 0.0 ) continue ; /* doesn't match sign of Q */ M = nifti_mat33_mul(P,Q) ; /* angle of M rotation = 2.0*acos(0.5*sqrt(1.0+trace(M))) */ /* we want largest trace(M) == smallest angle == M nearest to I */ val = M.m[0][0] + M.m[1][1] + M.m[2][2] ; /* trace */ if( val > vbest ){ vbest = val ; ibest = i ; jbest = j ; kbest = k ; pbest = p ; qbest = q ; rbest = r ; } }}}}}} /* At this point ibest is 1 or 2 or 3; pbest is -1 or +1; etc. The matrix P that corresponds is the best permutation approximation to Q-inverse; that is, P (approximately) takes (x,y,z) coordinates to the (i,j,k) axes. For example, the first row of P (which contains pbest in column ibest) determines the way the i axis points relative to the anatomical (x,y,z) axes. If ibest is 2, then the i axis is along the y axis, which is direction P2A (if pbest > 0) or A2P (if pbest < 0). So, using ibest and pbest, we can assign the output code for the i axis. Mutatis mutandis for the j and k axes, of course. */ switch( ibest*pbest ){ case 1: i = NIFTI_L2R ; break ; case -1: i = NIFTI_R2L ; break ; case 2: i = NIFTI_P2A ; break ; case -2: i = NIFTI_A2P ; break ; case 3: i = NIFTI_I2S ; break ; case -3: i = NIFTI_S2I ; break ; } switch( jbest*qbest ){ case 1: j = NIFTI_L2R ; break ; case -1: j = NIFTI_R2L ; break ; case 2: j = NIFTI_P2A ; break ; case -2: j = NIFTI_A2P ; break ; case 3: j = NIFTI_I2S ; break ; case -3: j = NIFTI_S2I ; break ; } switch( kbest*rbest ){ case 1: k = NIFTI_L2R ; break ; case -1: k = NIFTI_R2L ; break ; case 2: k = NIFTI_P2A ; break ; case -2: k = NIFTI_A2P ; break ; case 3: k = NIFTI_I2S ; break ; case -3: k = NIFTI_S2I ; break ; } *icod = i ; *jcod = j ; *kcod = k ; } /*---------------------------------------------------------------------------*/ /* Routines to swap byte arrays in various ways: - 2 at a time: ab -> ba [short] - 4 at a time: abcd -> dcba [int, float] - 8 at a time: abcdDCBA -> ABCDdcba [long long, double] - 16 at a time: abcdefghHGFEDCBA -> ABCDEFGHhgfedcba [long double] -----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /*! swap each byte pair from the given list of n pairs * * Due to alignment of structures at some architectures (e.g. on ARM), * stick to char varaibles. * Fixes http://bugs.debian.org/446893 Yaroslav * *//*--------------------------------------------------------------------*/ void nifti_swap_2bytes( size_t n , void *ar ) /* 2 bytes at a time */ { size_t ii ; unsigned char * cp1 = (unsigned char *)ar, * cp2 ; unsigned char tval; for( ii=0 ; ii < n ; ii++ ){ cp2 = cp1 + 1; tval = *cp1; *cp1 = *cp2; *cp2 = tval; cp1 += 2; } } /*----------------------------------------------------------------------*/ /*! swap 4 bytes at a time from the given list of n sets of 4 bytes *//*--------------------------------------------------------------------*/ void nifti_swap_4bytes( size_t n , void *ar ) /* 4 bytes at a time */ { size_t ii ; unsigned char * cp0 = (unsigned char *)ar, * cp1, * cp2 ; unsigned char tval ; for( ii=0 ; ii < n ; ii++ ){ cp1 = cp0; cp2 = cp0+3; tval = *cp1; *cp1 = *cp2; *cp2 = tval; cp1++; cp2--; tval = *cp1; *cp1 = *cp2; *cp2 = tval; cp0 += 4; } } /*----------------------------------------------------------------------*/ /*! swap 8 bytes at a time from the given list of n sets of 8 bytes * * perhaps use this style for the general Nbytes, as Yaroslav suggests *//*--------------------------------------------------------------------*/ void nifti_swap_8bytes( size_t n , void *ar ) /* 8 bytes at a time */ { size_t ii ; unsigned char * cp0 = (unsigned char *)ar, * cp1, * cp2 ; unsigned char tval ; for( ii=0 ; ii < n ; ii++ ){ cp1 = cp0; cp2 = cp0+7; while ( cp2 > cp1 ) /* unroll? */ { tval = *cp1 ; *cp1 = *cp2 ; *cp2 = tval ; cp1++; cp2--; } cp0 += 8; } } /*----------------------------------------------------------------------*/ /*! swap 16 bytes at a time from the given list of n sets of 16 bytes *//*--------------------------------------------------------------------*/ void nifti_swap_16bytes( size_t n , void *ar ) /* 16 bytes at a time */ { size_t ii ; unsigned char * cp0 = (unsigned char *)ar, * cp1, * cp2 ; unsigned char tval ; for( ii=0 ; ii < n ; ii++ ){ cp1 = cp0; cp2 = cp0+15; while ( cp2 > cp1 ) { tval = *cp1 ; *cp1 = *cp2 ; *cp2 = tval ; cp1++; cp2--; } cp0 += 16; } } #if 0 /* not important: save for version update 6 Jul 2010 [rickr] */ /*----------------------------------------------------------------------*/ /*! generic: swap siz bytes at a time from the given list of n sets *//*--------------------------------------------------------------------*/ void nifti_swap_bytes( size_t n , int siz , void *ar ) { size_t ii ; unsigned char * cp0 = (unsigned char *)ar, * cp1, * cp2 ; unsigned char tval ; for( ii=0 ; ii < n ; ii++ ){ cp1 = cp0; cp2 = cp0+(siz-1); while ( cp2 > cp1 ) { tval = *cp1 ; *cp1 = *cp2 ; *cp2 = tval ; cp1++; cp2--; } cp0 += siz; } return ; } #endif /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /*! based on siz, call the appropriate nifti_swap_Nbytes() function *//*--------------------------------------------------------------------*/ void nifti_swap_Nbytes( size_t n , int siz , void *ar ) /* subsuming case */ { switch( siz ){ case 2: nifti_swap_2bytes ( n , ar ) ; break ; case 4: nifti_swap_4bytes ( n , ar ) ; break ; case 8: nifti_swap_8bytes ( n , ar ) ; break ; case 16: nifti_swap_16bytes( n , ar ) ; break ; default: /* nifti_swap_bytes ( n , siz, ar ) ; */ fprintf(stderr,"** NIfTI: cannot swap in %d byte blocks\n", siz); break ; } } /*-------------------------------------------------------------------------*/ /*! Byte swap NIFTI-1 file header in various places and ways. If is_nifti, swap all (even UNUSED) fields of NIfTI header. Else, swap as a nifti_analyze75 struct. *//*---------------------------------------------------------------------- */ void swap_nifti_header( struct nifti_1_header *h , int is_nifti ) { /* if ANALYZE, swap as such and return */ if( ! is_nifti ) { nifti_swap_as_analyze((nifti_analyze75 *)h); return; } /* otherwise, swap all NIFTI fields */ nifti_swap_4bytes(1, &h->sizeof_hdr); nifti_swap_4bytes(1, &h->extents); nifti_swap_2bytes(1, &h->session_error); nifti_swap_2bytes(8, h->dim); nifti_swap_4bytes(1, &h->intent_p1); nifti_swap_4bytes(1, &h->intent_p2); nifti_swap_4bytes(1, &h->intent_p3); nifti_swap_2bytes(1, &h->intent_code); nifti_swap_2bytes(1, &h->datatype); nifti_swap_2bytes(1, &h->bitpix); nifti_swap_2bytes(1, &h->slice_start); nifti_swap_4bytes(8, h->pixdim); nifti_swap_4bytes(1, &h->vox_offset); nifti_swap_4bytes(1, &h->scl_slope); nifti_swap_4bytes(1, &h->scl_inter); nifti_swap_2bytes(1, &h->slice_end); nifti_swap_4bytes(1, &h->cal_max); nifti_swap_4bytes(1, &h->cal_min); nifti_swap_4bytes(1, &h->slice_duration); nifti_swap_4bytes(1, &h->toffset); nifti_swap_4bytes(1, &h->glmax); nifti_swap_4bytes(1, &h->glmin); nifti_swap_2bytes(1, &h->qform_code); nifti_swap_2bytes(1, &h->sform_code); nifti_swap_4bytes(1, &h->quatern_b); nifti_swap_4bytes(1, &h->quatern_c); nifti_swap_4bytes(1, &h->quatern_d); nifti_swap_4bytes(1, &h->qoffset_x); nifti_swap_4bytes(1, &h->qoffset_y); nifti_swap_4bytes(1, &h->qoffset_z); nifti_swap_4bytes(4, h->srow_x); nifti_swap_4bytes(4, h->srow_y); nifti_swap_4bytes(4, h->srow_z); } /*-------------------------------------------------------------------------*/ /*! Byte swap as an ANALYZE 7.5 header * * return non-zero on failure *//*---------------------------------------------------------------------- */ int nifti_swap_as_analyze( nifti_analyze75 * h ) { if( !h ) return 1; nifti_swap_4bytes(1, &h->sizeof_hdr); nifti_swap_4bytes(1, &h->extents); nifti_swap_2bytes(1, &h->session_error); nifti_swap_2bytes(8, h->dim); nifti_swap_2bytes(1, &h->unused8); nifti_swap_2bytes(1, &h->unused9); nifti_swap_2bytes(1, &h->unused10); nifti_swap_2bytes(1, &h->unused11); nifti_swap_2bytes(1, &h->unused12); nifti_swap_2bytes(1, &h->unused13); nifti_swap_2bytes(1, &h->unused14); nifti_swap_2bytes(1, &h->datatype); nifti_swap_2bytes(1, &h->bitpix); nifti_swap_2bytes(1, &h->dim_un0); nifti_swap_4bytes(8, h->pixdim); nifti_swap_4bytes(1, &h->vox_offset); nifti_swap_4bytes(1, &h->funused1); nifti_swap_4bytes(1, &h->funused2); nifti_swap_4bytes(1, &h->funused3); nifti_swap_4bytes(1, &h->cal_max); nifti_swap_4bytes(1, &h->cal_min); nifti_swap_4bytes(1, &h->compressed); nifti_swap_4bytes(1, &h->verified); nifti_swap_4bytes(1, &h->glmax); nifti_swap_4bytes(1, &h->glmin); nifti_swap_4bytes(1, &h->views); nifti_swap_4bytes(1, &h->vols_added); nifti_swap_4bytes(1, &h->start_field); nifti_swap_4bytes(1, &h->field_skip); nifti_swap_4bytes(1, &h->omax); nifti_swap_4bytes(1, &h->omin); nifti_swap_4bytes(1, &h->smax); nifti_swap_4bytes(1, &h->smin); return 0; } /*-------------------------------------------------------------------------*/ /*! OLD VERSION of swap_nifti_header (left for undo/compare operations) Byte swap NIFTI-1 file header in various places and ways. If is_nifti is nonzero, will also swap the NIFTI-specific components of the header; otherwise, only the components common to NIFTI and ANALYZE will be swapped. *//*---------------------------------------------------------------------- */ void old_swap_nifti_header( struct nifti_1_header *h , int is_nifti ) { /* this stuff is always present, for ANALYZE and NIFTI */ swap_4(h->sizeof_hdr) ; nifti_swap_2bytes( 8 , h->dim ) ; nifti_swap_4bytes( 8 , h->pixdim ) ; swap_2(h->datatype) ; swap_2(h->bitpix) ; swap_4(h->vox_offset); swap_4(h->cal_max); swap_4(h->cal_min); /* this stuff is NIFTI specific */ if( is_nifti ){ swap_4(h->intent_p1); swap_4(h->intent_p2); swap_4(h->intent_p3); swap_2(h->intent_code); swap_2(h->slice_start); swap_2(h->slice_end); swap_4(h->scl_slope); swap_4(h->scl_inter); swap_4(h->slice_duration); swap_4(h->toffset); swap_2(h->qform_code); swap_2(h->sform_code); swap_4(h->quatern_b); swap_4(h->quatern_c); swap_4(h->quatern_d); swap_4(h->qoffset_x); swap_4(h->qoffset_y); swap_4(h->qoffset_z); nifti_swap_4bytes(4,h->srow_x); nifti_swap_4bytes(4,h->srow_y); nifti_swap_4bytes(4,h->srow_z); } } #define USE_STAT #ifdef USE_STAT /*---------------------------------------------------------------------------*/ /* Return the file length (0 if file not found or has no contents). This is a Unix-specific function, since it uses stat(). -----------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------*/ /*! return the size of a file, in bytes \return size of file on success, -1 on error or no file changed to return int, -1 means no file or error 20 Dec 2004 [rickr] *//*-------------------------------------------------------------------------*/ int nifti_get_filesize( const char *pathname ) { struct stat buf ; int ii ; if( pathname == NULL || *pathname == '\0' ) return -1 ; ii = stat( pathname , &buf ); if( ii != 0 ) return -1 ; return (unsigned int)buf.st_size ; } #else /*---------- non-Unix version of the above, less efficient -----------*/ int nifti_get_filesize( const char *pathname ) { znzFile fp ; int len ; if( pathname == NULL || *pathname == '\0' ) return -1 ; fp = znzopen(pathname,"rb",0); if( znz_isnull(fp) ) return -1 ; znzseek(fp,0L,SEEK_END) ; len = znztell(fp) ; znzclose(fp) ; return len ; } #endif /* USE_STAT */ /*----------------------------------------------------------------------*/ /*! return the total volume size, in bytes This is computed as nvox * nbyper. *//*--------------------------------------------------------------------*/ size_t nifti_get_volsize(const nifti_image *nim) { return (size_t)(nim->nbyper) * (size_t)(nim->nvox) ; /* total bytes */ } /*--------------------------------------------------------------------------*/ /* Support functions for filenames in read and write - allows for gzipped files */ /*----------------------------------------------------------------------*/ /*! simple check for file existence \return 1 on existence, 0 otherwise *//*--------------------------------------------------------------------*/ int nifti_fileexists(const char* fname) { znzFile fp; fp = znzopen( fname , "rb" , nifti_is_gzfile(fname) ) ; if( !znz_isnull(fp) ) { znzclose(fp); return 1; } return 0; /* fp is NULL */ } /*----------------------------------------------------------------------*/ /*! return whether the filename is valid Note: uppercase extensions are now valid. 27 Apr 2009 [rickr] The name is considered valid if the file basename has length greater than zero, AND one of the valid nifti extensions is provided. fname input | return | =============================== "myimage" | 0 | "myimage.tif" | 0 | "myimage.tif.gz" | 0 | "myimage.nii" | 1 | ".nii" | 0 | ".myhiddenimage" | 0 | ".myhiddenimage.nii" | 1 | *//*--------------------------------------------------------------------*/ int nifti_is_complete_filename(const char* fname) { const char * ext; /* check input file(s) for sanity */ if( fname == NULL || *fname == '\0' ){ if ( g_opts.debug > 1 ) fprintf(stderr,"-- empty filename in nifti_validfilename()\n"); return 0; } ext = nifti_find_file_extension(fname); if ( ext == NULL ) { /*Invalid extension given */ if ( g_opts.debug > 0 ) fprintf(stderr,"-- no nifti valid extension for filename '%s'\n", fname); return 0; } if ( ext && ext == fname ) { /* then no filename prefix */ if ( g_opts.debug > 0 ) fprintf(stderr,"-- no prefix for filename '%s'\n", fname); return 0; } return 1; } /*----------------------------------------------------------------------*/ /*! return whether the filename is valid Allow uppercase extensions as valid. 27 Apr 2009 [rickr] Any .gz extension case must match the base extension case. The name is considered valid if its length is positive, excluding any nifti filename extension. fname input | return | result of nifti_makebasename ==================================================================== "myimage" | 1 | "myimage" "myimage.tif" | 1 | "myimage.tif" "myimage.tif.gz" | 1 | "myimage.tif" "myimage.nii" | 1 | "myimage" ".nii" | 0 | ".myhiddenimage" | 1 | ".myhiddenimage" ".myhiddenimage.nii | 1 | ".myhiddenimage" *//*--------------------------------------------------------------------*/ int nifti_validfilename(const char* fname) { const char * ext; /* check input file(s) for sanity */ if( fname == NULL || *fname == '\0' ){ if ( g_opts.debug > 1 ) fprintf(stderr,"-- empty filename in nifti_validfilename()\n"); return 0; } ext = nifti_find_file_extension(fname); if ( ext && ext == fname ) { /* then no filename prefix */ if ( g_opts.debug > 0 ) fprintf(stderr,"-- no prefix for filename '%s'\n", fname); return 0; } return 1; } /*----------------------------------------------------------------------*/ /*! check the end of the filename for a valid nifti extension Valid extensions are currently .nii, .hdr, .img, .nia, or any of them followed by .gz. Note that '.' is part of the extension. Uppercase extensions are also valid, but not mixed case. \return a pointer to the extension substring within the original function input parameter name, or NULL if not found. \caution Note that if the input parameter is is immutabale (i.e. a const char *) then this function performs an implicit casting away of the mutability constraint and the return parameter will appear as a mutable even though it is part of the immuttable string. *//*--------------------------------------------------------------------*/ char * nifti_find_file_extension( const char * name ) { const char * ext; char extcopy[8]; int len; char extnii[8] = ".nii"; /* modifiable, for possible uppercase */ char exthdr[8] = ".hdr"; /* (leave space for .gz) */ char extimg[8] = ".img"; char extnia[8] = ".nia"; char extgz[4] = ".gz"; char * elist[4] = { NULL, NULL, NULL, NULL}; /* stupid compiler... */ elist[0] = extnii; elist[1] = exthdr; elist[2] = extimg; elist[3] = extnia; if ( ! name ) return NULL; len = (int)strlen(name); if ( len < 4 ) return NULL; ext = name + len - 4; /* make manipulation copy, and possibly convert to lowercase */ strcpy(extcopy, ext); if( g_opts.allow_upper_fext ) make_lowercase(extcopy); /* if it look like a basic extension, fail or return it */ if( compare_strlist(extcopy, elist, 4) >= 0 ) { if( is_mixedcase(ext) ) { fprintf(stderr,"** mixed case extension '%s' is not valid\n", ext); return NULL; } else return (char *)ext; /* Cast away the constness of the input parameter */ } #ifdef HAVE_ZLIB if ( len < 7 ) return NULL; ext = name + len - 7; /* make manipulation copy, and possibly convert to lowercase */ strcpy(extcopy, ext); if( g_opts.allow_upper_fext ) make_lowercase(extcopy); /* go after .gz extensions using the modifiable strings */ strcat(elist[0], extgz); strcat(elist[1], extgz); strcat(elist[2], extgz); if( compare_strlist(extcopy, elist, 3) >= 0 ) { if( is_mixedcase(ext) ) { fprintf(stderr,"** mixed case extension '%s' is not valid\n", ext); return NULL; } else return (char *)ext; /* Cast away the constness of the input parameter */ } #endif if( g_opts.debug > 1 ) fprintf(stderr,"** find_file_ext: failed for name '%s'\n", name); return NULL; } /*----------------------------------------------------------------------*/ /*! return whether the filename ends in ".gz" *//*--------------------------------------------------------------------*/ int nifti_is_gzfile(const char* fname) { /* return true if the filename ends with .gz */ if (fname == NULL) { return 0; } #ifdef HAVE_ZLIB { /* just so len doesn't generate compile warning */ int len; len = (int)strlen(fname); if (len < 3) return 0; /* so we don't search before the name */ if (fileext_compare(fname + strlen(fname) - 3,".gz")==0) { return 1; } } #endif return 0; } /*----------------------------------------------------------------------*/ /*! return whether the given library was compiled with HAVE_ZLIB set *//*--------------------------------------------------------------------*/ int nifti_compiled_with_zlib(void) { #ifdef HAVE_ZLIB return 1; #else return 0; #endif } /*----------------------------------------------------------------------*/ /*! duplicate the filename, while clearing any extension This allocates memory for basename which should eventually be freed. *//*--------------------------------------------------------------------*/ char * nifti_makebasename(const char* fname) { char *basename; const char *ext; basename=nifti_strdup(fname); ext = nifti_find_file_extension(basename); if ( ext ) { basename[strlen(basename)-strlen(ext)] = '\0'; /* clear out extension */ } return basename; /* in either case */ } /*----------------------------------------------------------------------*/ /*! set nifti's global debug level, for status reporting - 0 : quiet, nothing is printed to the terminal, but errors - 1 : normal execution (the default) - 2, 3 : more details *//*--------------------------------------------------------------------*/ void nifti_set_debug_level( int level ) { g_opts.debug = level; } /*----------------------------------------------------------------------*/ /*! set nifti's global skip_blank_ext flag 5 Sep 2006 [rickr] explicitly set to 0 or 1 *//*--------------------------------------------------------------------*/ void nifti_set_skip_blank_ext( int skip ) { g_opts.skip_blank_ext = skip ? 1 : 0; } /*----------------------------------------------------------------------*/ /*! set nifti's global allow_upper_fext flag 28 Apr 2009 [rickr] explicitly set to 0 or 1 *//*--------------------------------------------------------------------*/ void nifti_set_allow_upper_fext( int allow ) { g_opts.allow_upper_fext = allow ? 1 : 0; } /*----------------------------------------------------------------------*/ /*! check current directory for existing header file \return filename of header on success and NULL if no appropriate file could be found If fname has an uppercase extension, check for uppercase files. NB: it allocates memory for hdrname which should be freed when no longer required *//*-------------------------------------------------------------------*/ char * nifti_findhdrname(const char* fname) { char *basename, *hdrname; const char *ext; char elist[2][5] = { ".hdr", ".nii" }; char extzip[4] = ".gz"; int efirst = 1; /* init to .nii extension */ int eisupper = 0; /* init to lowercase extensions */ /**- check input file(s) for sanity */ if( !nifti_validfilename(fname) ) return NULL; basename = nifti_makebasename(fname); if( !basename ) return NULL; /* only on string alloc failure */ /**- return filename if it has a valid extension and exists (except if it is an .img file (and maybe .gz)) */ ext = nifti_find_file_extension(fname); if( ext ) eisupper = is_uppercase(ext); /* do we look for uppercase? */ /* if the file exists and is a valid header name (not .img), return it */ if ( ext && nifti_fileexists(fname) ) { /* allow for uppercase extension */ if ( fileext_n_compare(ext,".img",4) != 0 ){ hdrname = nifti_strdup(fname); free(basename); return hdrname; } else efirst = 0; /* note for below */ } /* So the requested name is a basename, contains .img, or does not exist. */ /* In any case, use basename. */ /**- if .img, look for .hdr, .hdr.gz, .nii, .nii.gz, in that order */ /**- else, look for .nii, .nii.gz, .hdr, .hdr.gz, in that order */ /* if we get more extension choices, this could be a loop */ /* note: efirst is 0 in the case of ".img" */ /* if the user passed an uppercase entension (.IMG), search for uppercase */ if( eisupper ) { make_uppercase(elist[0]); make_uppercase(elist[1]); make_uppercase(extzip); } hdrname = (char *)calloc(sizeof(char),strlen(basename)+8); if( !hdrname ){ fprintf(stderr,"** nifti_findhdrname: failed to alloc hdrname\n"); free(basename); return NULL; } strcpy(hdrname,basename); strcat(hdrname,elist[efirst]); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #ifdef HAVE_ZLIB strcat(hdrname,extzip); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #endif /* okay, try the other possibility */ efirst = 1 - efirst; strcpy(hdrname,basename); strcat(hdrname,elist[efirst]); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #ifdef HAVE_ZLIB strcat(hdrname,extzip); if (nifti_fileexists(hdrname)) { free(basename); return hdrname; } #endif /**- if nothing has been found, return NULL */ free(basename); free(hdrname); return NULL; } /*------------------------------------------------------------------------*/ /*! check current directory for existing image file \param fname filename to check for \nifti_type nifti_type for dataset - this determines whether to first check for ".nii" or ".img" (since both may exist) \return filename of data/img file on success and NULL if no appropriate file could be found If fname has a valid, uppercase extension, apply all extensions as uppercase. NB: it allocates memory for the image filename, which should be freed when no longer required *//*---------------------------------------------------------------------*/ char * nifti_findimgname(const char* fname , int nifti_type) { /* store all extensions as strings, in case we need to go uppercase */ char *basename, *imgname, elist[2][5] = { ".nii", ".img" }; char extzip[4] = ".gz"; char extnia[5] = ".nia"; const char *ext; int first; /* first extension to use */ /* check input file(s) for sanity */ if( !nifti_validfilename(fname) ) return NULL; basename = nifti_makebasename(fname); imgname = (char *)calloc(sizeof(char),strlen(basename)+8); if( !imgname ){ fprintf(stderr,"** nifti_findimgname: failed to alloc imgname\n"); free(basename); return NULL; } /* if we are looking for uppercase, apply the fact now */ ext = nifti_find_file_extension(fname); if( ext && is_uppercase(ext) ) { make_uppercase(elist[0]); make_uppercase(elist[1]); make_uppercase(extzip); make_uppercase(extnia); } /* only valid extension for ASCII type is .nia, handle first */ if( nifti_type == NIFTI_FTYPE_ASCII ){ strcpy(imgname,basename); strcat(imgname,extnia); if (nifti_fileexists(imgname)) { free(basename); return imgname; } } else { /**- test for .nii and .img (don't assume input type from image type) */ /**- if nifti_type = 1, check for .nii first, else .img first */ /* if we get 3 or more extensions, can make a loop here... */ if (nifti_type == NIFTI_FTYPE_NIFTI1_1) first = 0; /* should match .nii */ else first = 1; /* should match .img */ strcpy(imgname,basename); strcat(imgname,elist[first]); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #ifdef HAVE_ZLIB /* then also check for .gz */ strcat(imgname,extzip); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #endif /* failed to find image file with expected extension, try the other */ strcpy(imgname,basename); strcat(imgname,elist[1-first]); /* can do this with only 2 choices */ if (nifti_fileexists(imgname)) { free(basename); return imgname; } #ifdef HAVE_ZLIB /* then also check for .gz */ strcat(imgname,extzip); if (nifti_fileexists(imgname)) { free(basename); return imgname; } #endif } /**- if nothing has been found, return NULL */ free(basename); free(imgname); return NULL; } /*----------------------------------------------------------------------*/ /*! creates a filename for storing the header, based on nifti_type \param prefix - this will be copied before the suffix is added \param nifti_type - determines the extension, unless one is in prefix \param check - check for existence (fail condition) \param comp - add .gz for compressed name Note that if prefix provides a file suffix, nifti_type is not used. NB: this allocates memory which should be freed \sa nifti_set_filenames *//*-------------------------------------------------------------------*/ char * nifti_makehdrname(const char * prefix, int nifti_type, int check, int comp) { char * iname; const char * ext; char extnii[5] = ".nii"; /* modifiable, for possible uppercase */ char exthdr[5] = ".hdr"; char extimg[5] = ".img"; char extnia[5] = ".nia"; char extgz[5] = ".gz"; if( !nifti_validfilename(prefix) ) return NULL; /* add space for extension, optional ".gz", and null char */ iname = (char *)calloc(sizeof(char),strlen(prefix)+8); if( !iname ){ fprintf(stderr,"** small malloc failure!\n"); return NULL; } strcpy(iname, prefix); /* use any valid extension */ if( (ext = nifti_find_file_extension(iname)) != NULL ){ /* if uppercase, convert all extensions */ if( is_uppercase(ext) ) { make_uppercase(extnii); make_uppercase(exthdr); make_uppercase(extimg); make_uppercase(extnia); make_uppercase(extgz); } if( strncmp(ext,extimg,4) == 0 ) { memcpy(&(iname[strlen(iname)-strlen(ext)]),exthdr,4); /* then convert img name to hdr */ } } /* otherwise, make one up */ else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcat(iname, extnii); else if( nifti_type == NIFTI_FTYPE_ASCII ) strcat(iname, extnia); else strcat(iname, exthdr); #ifdef HAVE_ZLIB /* if compression is requested, make sure of suffix */ if( comp && (!ext || !strstr(iname,extgz)) ) strcat(iname,extgz); #endif /* check for existence failure */ if( check && nifti_fileexists(iname) ){ fprintf(stderr,"** failure: header file '%s' already exists\n",iname); free(iname); return NULL; } if(g_opts.debug > 2) fprintf(stderr,"+d made header filename '%s'\n", iname); return iname; } /*----------------------------------------------------------------------*/ /*! creates a filename for storing the image, based on nifti_type \param prefix - this will be copied before the suffix is added \param nifti_type - determines the extension, unless provided by prefix \param check - check for existence (fail condition) \param comp - add .gz for compressed name Note that if prefix provides a file suffix, nifti_type is not used. NB: it allocates memory which should be freed \sa nifti_set_filenames *//*-------------------------------------------------------------------*/ char * nifti_makeimgname(const char * prefix, int nifti_type, int check, int comp) { char * iname; const char * ext; char extnii[5] = ".nii"; /* modifiable, for possible uppercase */ char exthdr[5] = ".hdr"; char extimg[5] = ".img"; char extnia[5] = ".nia"; char extgz[5] = ".gz"; if( !nifti_validfilename(prefix) ) return NULL; /* add space for extension, optional ".gz", and null char */ iname = (char *)calloc(sizeof(char),strlen(prefix)+8); if( !iname ){ fprintf(stderr,"** small malloc failure!\n"); return NULL; } strcpy(iname, prefix); /* use any valid extension */ if( (ext = nifti_find_file_extension(iname)) != NULL ){ /* if uppercase, convert all extensions */ if( is_uppercase(ext) ) { make_uppercase(extnii); make_uppercase(exthdr); make_uppercase(extimg); make_uppercase(extnia); make_uppercase(extgz); } if( strncmp(ext,exthdr,4) == 0 ) { memcpy(&(iname[strlen(iname)-strlen(ext)]),extimg,4); /* then convert hdr name to img */ } } /* otherwise, make one up */ else if( nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcat(iname, extnii); else if( nifti_type == NIFTI_FTYPE_ASCII ) strcat(iname, extnia); else strcat(iname, extimg); #ifdef HAVE_ZLIB /* if compression is requested, make sure of suffix */ if( comp && (!ext || !strstr(iname,extgz)) ) strcat(iname,extgz); #endif /* check for existence failure */ if( check && nifti_fileexists(iname) ){ fprintf(stderr,"** failure: image file '%s' already exists\n",iname); free(iname); return NULL; } if( g_opts.debug > 2 ) fprintf(stderr,"+d made image filename '%s'\n",iname); return iname; } /*----------------------------------------------------------------------*/ /*! create and set new filenames, based on prefix and image type \param nim pointer to nifti_image in which to set filenames \param prefix (required) prefix for output filenames \param check check for previous existence of filename (existence is an error condition) \param set_byte_order flag to set nim->byteorder here (this is probably a logical place to do so) \return 0 on successful update \warning this will free() any existing names and create new ones \sa nifti_makeimgname, nifti_makehdrname, nifti_type_and_names_match *//*--------------------------------------------------------------------*/ int nifti_set_filenames( nifti_image * nim, const char * prefix, int check, int set_byte_order ) { int comp = nifti_is_gzfile(prefix); if( !nim || !prefix ){ fprintf(stderr,"** nifti_set_filenames, bad params %p, %p\n", (void *)nim,prefix); return -1; } if( g_opts.debug > 1 ) fprintf(stderr,"+d modifying output filenames using prefix %s\n", prefix); if( nim->fname ) free(nim->fname); if( nim->iname ) free(nim->iname); nim->fname = nifti_makehdrname(prefix, nim->nifti_type, check, comp); nim->iname = nifti_makeimgname(prefix, nim->nifti_type, check, comp); if( !nim->fname || !nim->iname ){ LNI_FERR("nifti_set_filename","failed to set prefix for",prefix); return -1; } if( set_byte_order ) nim->byteorder = nifti_short_order() ; if( nifti_set_type_from_names(nim) < 0 ) return -1; if( g_opts.debug > 2 ) fprintf(stderr,"+d have new filenames %s and %s\n",nim->fname,nim->iname); return 0; } /*--------------------------------------------------------------------------*/ /*! check whether nifti_type matches fname and iname for the nifti_image - if type 0 or 2, expect .hdr/.img pair - if type 1, expect .nii (and names must match) \param nim given nifti_image \param show_warn if set, print a warning message for any mis-match \return - 1 if the values seem to match - 0 if there is a mis-match - -1 if there is not sufficient information to create file(s) \sa NIFTI_FTYPE_* codes in nifti1_io.h \sa nifti_set_type_from_names, is_valid_nifti_type *//*------------------------------------------------------------------------*/ int nifti_type_and_names_match( nifti_image * nim, int show_warn ) { char func[] = "nifti_type_and_names_match"; const char * ext_h; /* header filename extension */ const char * ext_i; /* image filename extension */ int errs = 0; /* error counter */ /* sanity checks */ if( !nim ){ if( show_warn ) fprintf(stderr,"** %s: missing nifti_image\n", func); return -1; } if( !nim->fname ){ if( show_warn ) fprintf(stderr,"** %s: missing header filename\n", func); errs++; } if( !nim->iname ){ if( show_warn ) fprintf(stderr,"** %s: missing image filename\n", func); errs++; } if( !is_valid_nifti_type(nim->nifti_type) ){ if( show_warn ) fprintf(stderr,"** %s: bad nifti_type %d\n", func, nim->nifti_type); errs++; } if( errs ) return -1; /* then do not proceed */ /* get pointers to extensions */ ext_h = nifti_find_file_extension( nim->fname ); ext_i = nifti_find_file_extension( nim->iname ); /* check for filename extensions */ if( !ext_h ){ if( show_warn ) fprintf(stderr,"-d missing NIFTI extension in header filename, %s\n", nim->fname); errs++; } if( !ext_i ){ if( show_warn ) fprintf(stderr,"-d missing NIFTI extension in image filename, %s\n", nim->iname); errs++; } if( errs ) return 0; /* do not proceed, but this is just a mis-match */ /* general tests */ if( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ){ /* .nii */ if( fileext_n_compare(ext_h,".nii",4) ) { if( show_warn ) fprintf(stderr, "-d NIFTI_FTYPE 1, but no .nii extension in header filename, %s\n", nim->fname); errs++; } if( fileext_n_compare(ext_i,".nii",4) ) { if( show_warn ) fprintf(stderr, "-d NIFTI_FTYPE 1, but no .nii extension in image filename, %s\n", nim->iname); errs++; } if( strcmp(nim->fname, nim->iname) != 0 ){ if( show_warn ) fprintf(stderr, "-d NIFTI_FTYPE 1, but header and image filenames differ: %s, %s\n", nim->fname, nim->iname); errs++; } } else if( (nim->nifti_type == NIFTI_FTYPE_NIFTI1_2) || /* .hdr/.img */ (nim->nifti_type == NIFTI_FTYPE_ANALYZE) ) { if( fileext_n_compare(ext_h,".hdr",4) != 0 ){ if( show_warn ) fprintf(stderr,"-d no '.hdr' extension, but NIFTI type is %d, %s\n", nim->nifti_type, nim->fname); errs++; } if( fileext_n_compare(ext_i,".img",4) != 0 ){ if( show_warn ) fprintf(stderr,"-d no '.img' extension, but NIFTI type is %d, %s\n", nim->nifti_type, nim->iname); errs++; } } /* ignore any other nifti_type */ if( errs ) return 0; /* types do not match */ return 1; } /* like strcmp, but also check against capitalization of known_ext * (test as local string, with max length 7) */ static int fileext_compare(const char * test_ext, const char * known_ext) { char caps[8] = ""; size_t c,len; /* if equal, don't need to check case (store to avoid multiple calls) */ const int cmp = strcmp(test_ext, known_ext); if( cmp == 0 ) return cmp; /* if anything odd, use default */ if( !test_ext || !known_ext ) return cmp; len = strlen(known_ext); if( len > 7 ) return cmp; /* if here, strings are different but need to check upper-case */ for(c = 0; c < len; c++ ) caps[c] = toupper((int) known_ext[c]); caps[c] = '\0'; return strcmp(test_ext, caps); } /* like strncmp, but also check against capitalization of known_ext * (test as local string, with max length 7) */ static int fileext_n_compare(const char * test_ext, const char * known_ext, size_t maxlen) { char caps[8] = ""; size_t c,len; /* if equal, don't need to check case (store to avoid multiple calls) */ const int cmp = strncmp(test_ext, known_ext, maxlen); if( cmp == 0 ) return cmp; /* if anything odd, use default */ if( !test_ext || !known_ext ) return cmp; len = strlen(known_ext); if( len > maxlen ) len = maxlen; /* ignore anything past maxlen */ if( len > 7 ) return cmp; /* if here, strings are different but need to check upper-case */ for(c = 0; c < len; c++ ) caps[c] = toupper((int) known_ext[c]); caps[c] = '\0'; return strncmp(test_ext, caps, maxlen); } /* return 1 if there are uppercase but no lowercase */ static int is_uppercase(const char * str) { size_t c; int hasupper = 0; if( !str || !*str ) return 0; for(c = 0; c < strlen(str); c++ ) { if( islower((int) str[c]) ) return 0; if( !hasupper && isupper((int) str[c]) ) hasupper = 1; } return hasupper; } /* return 1 if there are both uppercase and lowercase characters */ static int is_mixedcase(const char * str) { size_t c; int hasupper = 0, haslower = 0; if( !str || !*str ) return 0; for(c = 0; c < strlen(str); c++ ) { if( !haslower && islower((int) str[c]) ) haslower = 1; if( !hasupper && isupper((int) str[c]) ) hasupper = 1; if( haslower && hasupper ) return 1; } return 0; } /* convert any lowercase chars to uppercase */ static int make_uppercase(char * str) { size_t c; if( !str || !*str ) return 0; for(c = 0; c < strlen(str); c++ ) if( islower((int) str[c]) ) str[c] = toupper((int) str[c]); return 0; } /* convert any uppercase chars to lowercase */ static int make_lowercase(char * str) { size_t c; if( !str || !*str ) return 0; for(c = 0; c < strlen(str); c++ ) if( isupper((int) str[c]) ) str[c] = tolower((int) str[c]); return 0; } /* run strcmp against of list of strings * return index of equality, if found * else return -1 */ static int compare_strlist(const char * str, char ** strlist, int len) { int c; if( len <= 0 || !str || !strlist ) return -1; for( c = 0; c < len; c++ ) if( strlist[c] && !strcmp(str, strlist[c]) ) return c; return -1; } /*--------------------------------------------------------------------------*/ /*! check whether the given type is on the "approved" list The code is valid if it is non-negative, and does not exceed NIFTI_MAX_FTYPE. \return 1 if nifti_type is valid, 0 otherwise \sa NIFTI_FTYPE_* codes in nifti1_io.h *//*------------------------------------------------------------------------*/ int is_valid_nifti_type( int nifti_type ) { if( nifti_type >= NIFTI_FTYPE_ANALYZE && /* smallest type, 0 */ nifti_type <= NIFTI_MAX_FTYPE ) return 1; return 0; } /*--------------------------------------------------------------------------*/ /*! check whether the given type is on the "approved" list The type is explicitly checked against the NIFTI_TYPE_* list in nifti1.h. \return 1 if dtype is valid, 0 otherwise \sa NIFTI_TYPE_* codes in nifti1.h *//*------------------------------------------------------------------------*/ int nifti_is_valid_datatype( int dtype ) { if( dtype == NIFTI_TYPE_UINT8 || dtype == NIFTI_TYPE_INT16 || dtype == NIFTI_TYPE_INT32 || dtype == NIFTI_TYPE_FLOAT32 || dtype == NIFTI_TYPE_COMPLEX64 || dtype == NIFTI_TYPE_FLOAT64 || dtype == NIFTI_TYPE_RGB24 || dtype == NIFTI_TYPE_RGBA32 || dtype == NIFTI_TYPE_INT8 || dtype == NIFTI_TYPE_UINT16 || dtype == NIFTI_TYPE_UINT32 || dtype == NIFTI_TYPE_INT64 || dtype == NIFTI_TYPE_UINT64 || dtype == NIFTI_TYPE_FLOAT128 || dtype == NIFTI_TYPE_COMPLEX128 || dtype == NIFTI_TYPE_COMPLEX256 ) return 1; return 0; } /*--------------------------------------------------------------------------*/ /*! set the nifti_type field based on fname and iname Note that nifti_type is changed only when it does not match the filenames. \return 0 on success, -1 on error \sa is_valid_nifti_type, nifti_type_and_names_match *//*------------------------------------------------------------------------*/ int nifti_set_type_from_names( nifti_image * nim ) { /* error checking first */ if( !nim ){ fprintf(stderr,"** NSTFN: no nifti_image\n"); return -1; } if( !nim->fname || !nim->iname ){ fprintf(stderr,"** NSTFN: missing filename(s) fname @ %p, iname @ %p\n", nim->fname, nim->iname); return -1; } if( ! nifti_validfilename ( nim->fname ) || ! nifti_validfilename ( nim->iname ) || ! nifti_find_file_extension( nim->fname ) || ! nifti_find_file_extension( nim->iname ) ) { fprintf(stderr,"** NSTFN: invalid filename(s) fname='%s', iname='%s'\n", nim->fname, nim->iname); return -1; } if( g_opts.debug > 2 ) fprintf(stderr,"-d verify nifti_type from filenames: %d",nim->nifti_type); /* type should be NIFTI_FTYPE_ASCII if extension is .nia */ if( (fileext_compare(nifti_find_file_extension(nim->fname),".nia")==0)){ nim->nifti_type = NIFTI_FTYPE_ASCII; } else { /* not too picky here, do what must be done, and then verify */ if( strcmp(nim->fname, nim->iname) == 0 ) /* one file, type 1 */ nim->nifti_type = NIFTI_FTYPE_NIFTI1_1; else if( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ) /* cannot be type 1 */ nim->nifti_type = NIFTI_FTYPE_NIFTI1_2; } if( g_opts.debug > 2 ) fprintf(stderr," -> %d\n",nim->nifti_type); if( g_opts.debug > 1 ) /* warn user about anything strange */ nifti_type_and_names_match(nim, 1); if( is_valid_nifti_type(nim->nifti_type) ) return 0; /* success! */ fprintf(stderr,"** NSTFN: bad nifti_type %d, for '%s' and '%s'\n", nim->nifti_type, nim->fname, nim->iname); return -1; } /*--------------------------------------------------------------------------*/ /*! Determine if this is a NIFTI-formatted file.
   \return  0 if file looks like ANALYZE 7.5 [checks sizeof_hdr field == 348]
            1 if file marked as NIFTI (header+data in 1 file)
            2 if file marked as NIFTI (header+data in 2 files)
           -1 if it can't tell, file doesn't exist, etc.
   
*//*------------------------------------------------------------------------*/ int is_nifti_file( const char *hname ) { struct nifti_1_header nhdr ; znzFile fp ; int ii ; char *tmpname; /* bad input name? */ if( !nifti_validfilename(hname) ) return -1 ; /* open file */ tmpname = nifti_findhdrname(hname); if( tmpname == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** no header file found for '%s'\n",hname); return -1; } fp = znzopen( tmpname , "rb" , nifti_is_gzfile(tmpname) ) ; free(tmpname); if (znz_isnull(fp)) return -1 ; /* bad open? */ /* read header, close file */ ii = (int)znzread( &nhdr , 1 , sizeof(nhdr) , fp ) ; znzclose( fp ) ; if( ii < (int) sizeof(nhdr) ) return -1 ; /* bad read? */ /* check for NIFTI-ness */ if( NIFTI_VERSION(nhdr) != 0 ){ return ( NIFTI_ONEFILE(nhdr) ) ? 1 : 2 ; } /* check for ANALYZE-ness (sizeof_hdr field == 348) */ ii = nhdr.sizeof_hdr ; if( ii == (int)sizeof(nhdr) ) return 0 ; /* matches */ /* try byte-swapping header */ swap_4(ii) ; if( ii == (int)sizeof(nhdr) ) return 0 ; /* matches */ return -1 ; /* not good */ } static int print_hex_vals( const char * data, size_t nbytes, FILE * fp ) { size_t c; if ( !data || nbytes < 1 || !fp ) return -1; fputs("0x", fp); for ( c = 0; c < nbytes; c++ ) fprintf(fp, " %x", data[c]); return 0; } /*----------------------------------------------------------------------*/ /*! display the contents of the nifti_1_header (send to stdout) \param info if non-NULL, print this character string \param hp pointer to nifti_1_header *//*--------------------------------------------------------------------*/ int disp_nifti_1_header( const char * info, const nifti_1_header * hp ) { int c; fputs( "-------------------------------------------------------\n", stdout ); if ( info ) fputs( info, stdout ); if ( !hp ){ fputs(" ** no nifti_1_header to display!\n",stdout); return 1; } fprintf(stdout," nifti_1_header :\n" " sizeof_hdr = %d\n" " data_type[10] = ", hp->sizeof_hdr); print_hex_vals(hp->data_type, 10, stdout); fprintf(stdout, "\n" " db_name[18] = "); print_hex_vals(hp->db_name, 18, stdout); fprintf(stdout, "\n" " extents = %d\n" " session_error = %d\n" " regular = 0x%x\n" " dim_info = 0x%x\n", hp->extents, hp->session_error, hp->regular, hp->dim_info ); fprintf(stdout, " dim[8] ="); for ( c = 0; c < 8; c++ ) fprintf(stdout," %d", hp->dim[c]); fprintf(stdout, "\n" " intent_p1 = %f\n" " intent_p2 = %f\n" " intent_p3 = %f\n" " intent_code = %d\n" " datatype = %d\n" " bitpix = %d\n" " slice_start = %d\n" " pixdim[8] =", hp->intent_p1, hp->intent_p2, hp->intent_p3, hp->intent_code, hp->datatype, hp->bitpix, hp->slice_start); /* break pixdim over 2 lines */ for ( c = 0; c < 4; c++ ) fprintf(stdout," %f", hp->pixdim[c]); fprintf(stdout, "\n "); for ( c = 4; c < 8; c++ ) fprintf(stdout," %f", hp->pixdim[c]); fprintf(stdout, "\n" " vox_offset = %f\n" " scl_slope = %f\n" " scl_inter = %f\n" " slice_end = %d\n" " slice_code = %d\n" " xyzt_units = 0x%x\n" " cal_max = %f\n" " cal_min = %f\n" " slice_duration = %f\n" " toffset = %f\n" " glmax = %d\n" " glmin = %d\n", hp->vox_offset, hp->scl_slope, hp->scl_inter, hp->slice_end, hp->slice_code, hp->xyzt_units, hp->cal_max, hp->cal_min, hp->slice_duration, hp->toffset, hp->glmax, hp->glmin); fprintf(stdout, " descrip = '%.80s'\n" " aux_file = '%.24s'\n" " qform_code = %d\n" " sform_code = %d\n" " quatern_b = %f\n" " quatern_c = %f\n" " quatern_d = %f\n" " qoffset_x = %f\n" " qoffset_y = %f\n" " qoffset_z = %f\n" " srow_x[4] = %f, %f, %f, %f\n" " srow_y[4] = %f, %f, %f, %f\n" " srow_z[4] = %f, %f, %f, %f\n" " intent_name = '%-.16s'\n" " magic = '%-.4s'\n", hp->descrip, hp->aux_file, hp->qform_code, hp->sform_code, hp->quatern_b, hp->quatern_c, hp->quatern_d, hp->qoffset_x, hp->qoffset_y, hp->qoffset_z, hp->srow_x[0], hp->srow_x[1], hp->srow_x[2], hp->srow_x[3], hp->srow_y[0], hp->srow_y[1], hp->srow_y[2], hp->srow_y[3], hp->srow_z[0], hp->srow_z[1], hp->srow_z[2], hp->srow_z[3], hp->intent_name, hp->magic); fputs( "-------------------------------------------------------\n", stdout ); fflush(stdout); return 0; } #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_convert_nhdr2nim: %s\n", (msg) ) ; \ return NULL ; } while(0) /*----------------------------------------------------------------------*/ /*! convert a nifti_1_header into a nift1_image \return an allocated nifti_image, or NULL on failure *//*--------------------------------------------------------------------*/ nifti_image* nifti_convert_nhdr2nim(struct nifti_1_header nhdr, const char * fname) { int ii , doswap , ioff ; int is_nifti , is_onefile ; nifti_image *nim; nim = (nifti_image *)calloc( 1 , sizeof(nifti_image) ) ; if( !nim ) ERREX("failed to allocate nifti image"); /* be explicit with pointers */ nim->fname = NULL; nim->iname = NULL; nim->data = NULL; /**- check if we must swap bytes */ doswap = need_nhdr_swap(nhdr.dim[0], nhdr.sizeof_hdr); /* swap data flag */ if( doswap < 0 ){ free(nim); if( doswap == -1 ) ERREX("bad dim[0]") ; ERREX("bad sizeof_hdr") ; /* else */ } /**- determine if this is a NIFTI-1 compliant header */ is_nifti = NIFTI_VERSION(nhdr) ; /* * before swapping header, record the Analyze75 orient code */ if(!is_nifti) { /**- in analyze75, the orient code is at the same address as * qform_code, but it's just one byte * the qform_code will be zero, at which point you can check * analyze75_orient if you care to. */ unsigned char c = *((char *)(&nhdr.qform_code)); nim->analyze75_orient = (analyze_75_orient_code)c; } if( doswap ) { if ( g_opts.debug > 3 ) disp_nifti_1_header("-d ni1 pre-swap: ", &nhdr); swap_nifti_header( &nhdr , is_nifti ) ; } if ( g_opts.debug > 2 ) disp_nifti_1_header("-d nhdr2nim : ", &nhdr); if( nhdr.datatype == DT_BINARY || nhdr.datatype == DT_UNKNOWN ) { free(nim); ERREX("bad datatype") ; } if( nhdr.dim[1] <= 0 ) { free(nim); ERREX("bad dim[1]") ; } /* fix bad dim[] values in the defined dimension range */ for( ii=2 ; ii <= nhdr.dim[0] ; ii++ ) if( nhdr.dim[ii] <= 0 ) nhdr.dim[ii] = 1 ; /* fix any remaining bad dim[] values, so garbage does not propagate */ /* (only values 0 or 1 seem rational, otherwise set to arbirary 1) */ for( ii=nhdr.dim[0]+1 ; ii <= 7 ; ii++ ) if( nhdr.dim[ii] != 1 && nhdr.dim[ii] != 0) nhdr.dim[ii] = 1 ; #if 0 /* rely on dim[0], do not attempt to modify it 16 Nov 2005 [rickr] */ /**- get number of dimensions (ignoring dim[0] now) */ for( ii=7 ; ii >= 2 ; ii-- ) /* loop backwards until we */ if( nhdr.dim[ii] > 1 ) break ; /* find a dim bigger than 1 */ ndim = ii ; #endif /**- set bad grid spacings to 1.0 */ for( ii=1 ; ii <= nhdr.dim[0] ; ii++ ){ if( nhdr.pixdim[ii] == 0.0 || !IS_GOOD_FLOAT(nhdr.pixdim[ii]) ) nhdr.pixdim[ii] = 1.0f ; } is_onefile = is_nifti && NIFTI_ONEFILE(nhdr) ; if( is_nifti ) nim->nifti_type = (is_onefile) ? NIFTI_FTYPE_NIFTI1_1 : NIFTI_FTYPE_NIFTI1_2 ; else nim->nifti_type = NIFTI_FTYPE_ANALYZE ; ii = nifti_short_order() ; if( doswap ) nim->byteorder = REVERSE_ORDER(ii) ; else nim->byteorder = ii ; /**- set dimensions of data array */ nim->ndim = nim->dim[0] = nhdr.dim[0]; nim->nx = nim->dim[1] = nhdr.dim[1]; nim->ny = nim->dim[2] = nhdr.dim[2]; nim->nz = nim->dim[3] = nhdr.dim[3]; nim->nt = nim->dim[4] = nhdr.dim[4]; nim->nu = nim->dim[5] = nhdr.dim[5]; nim->nv = nim->dim[6] = nhdr.dim[6]; nim->nw = nim->dim[7] = nhdr.dim[7]; for( ii=1, nim->nvox=1; ii <= nhdr.dim[0]; ii++ ) nim->nvox *= nhdr.dim[ii]; /**- set the type of data in voxels and how many bytes per voxel */ nim->datatype = nhdr.datatype ; nifti_datatype_sizes( nim->datatype , &(nim->nbyper) , &(nim->swapsize) ) ; if( nim->nbyper == 0 ){ free(nim); ERREX("bad datatype"); } /**- set the grid spacings */ nim->dx = nim->pixdim[1] = nhdr.pixdim[1] ; nim->dy = nim->pixdim[2] = nhdr.pixdim[2] ; nim->dz = nim->pixdim[3] = nhdr.pixdim[3] ; nim->dt = nim->pixdim[4] = nhdr.pixdim[4] ; nim->du = nim->pixdim[5] = nhdr.pixdim[5] ; nim->dv = nim->pixdim[6] = nhdr.pixdim[6] ; nim->dw = nim->pixdim[7] = nhdr.pixdim[7] ; /**- compute qto_xyz transformation from pixel indexes (i,j,k) to (x,y,z) */ if( !is_nifti || nhdr.qform_code <= 0 ){ /**- if not nifti or qform_code <= 0, use grid spacing for qto_xyz */ nim->qto_xyz.m[0][0] = nim->dx ; /* grid spacings */ nim->qto_xyz.m[1][1] = nim->dy ; /* along diagonal */ nim->qto_xyz.m[2][2] = nim->dz ; /* off diagonal is zero */ nim->qto_xyz.m[0][1]=nim->qto_xyz.m[0][2]=nim->qto_xyz.m[0][3] = 0.0f; nim->qto_xyz.m[1][0]=nim->qto_xyz.m[1][2]=nim->qto_xyz.m[1][3] = 0.0f; nim->qto_xyz.m[2][0]=nim->qto_xyz.m[2][1]=nim->qto_xyz.m[2][3] = 0.0f; /* last row is always [ 0 0 0 1 ] */ nim->qto_xyz.m[3][0]=nim->qto_xyz.m[3][1]=nim->qto_xyz.m[3][2] = 0.0f; nim->qto_xyz.m[3][3]= 1.0f ; nim->qform_code = NIFTI_XFORM_UNKNOWN ; if( g_opts.debug > 1 ) fprintf(stderr,"-d no qform provided\n"); } else { /**- else NIFTI: use the quaternion-specified transformation */ nim->quatern_b = FIXED_FLOAT( nhdr.quatern_b ) ; nim->quatern_c = FIXED_FLOAT( nhdr.quatern_c ) ; nim->quatern_d = FIXED_FLOAT( nhdr.quatern_d ) ; nim->qoffset_x = FIXED_FLOAT(nhdr.qoffset_x) ; nim->qoffset_y = FIXED_FLOAT(nhdr.qoffset_y) ; nim->qoffset_z = FIXED_FLOAT(nhdr.qoffset_z) ; nim->qfac = (nhdr.pixdim[0] < 0.0) ? -1.0f : 1.0f ; /* left-handedness? */ nim->qto_xyz = nifti_quatern_to_mat44( nim->quatern_b, nim->quatern_c, nim->quatern_d, nim->qoffset_x, nim->qoffset_y, nim->qoffset_z, nim->dx , nim->dy , nim->dz , nim->qfac ) ; nim->qform_code = nhdr.qform_code ; if( g_opts.debug > 1 ) nifti_disp_matrix_orient("-d qform orientations:\n", nim->qto_xyz); } /**- load inverse transformation (x,y,z) -> (i,j,k) */ nim->qto_ijk = nifti_mat44_inverse( nim->qto_xyz ) ; /**- load sto_xyz affine transformation, if present */ if( !is_nifti || nhdr.sform_code <= 0 ){ /**- if not nifti or sform_code <= 0, then no sto transformation */ nim->sform_code = NIFTI_XFORM_UNKNOWN ; if( g_opts.debug > 1 ) fprintf(stderr,"-d no sform provided\n"); } else { /**- else set the sto transformation from srow_*[] */ nim->sto_xyz.m[0][0] = nhdr.srow_x[0] ; nim->sto_xyz.m[0][1] = nhdr.srow_x[1] ; nim->sto_xyz.m[0][2] = nhdr.srow_x[2] ; nim->sto_xyz.m[0][3] = nhdr.srow_x[3] ; nim->sto_xyz.m[1][0] = nhdr.srow_y[0] ; nim->sto_xyz.m[1][1] = nhdr.srow_y[1] ; nim->sto_xyz.m[1][2] = nhdr.srow_y[2] ; nim->sto_xyz.m[1][3] = nhdr.srow_y[3] ; nim->sto_xyz.m[2][0] = nhdr.srow_z[0] ; nim->sto_xyz.m[2][1] = nhdr.srow_z[1] ; nim->sto_xyz.m[2][2] = nhdr.srow_z[2] ; nim->sto_xyz.m[2][3] = nhdr.srow_z[3] ; /* last row is always [ 0 0 0 1 ] */ nim->sto_xyz.m[3][0]=nim->sto_xyz.m[3][1]=nim->sto_xyz.m[3][2] = 0.0f; nim->sto_xyz.m[3][3]= 1.0f ; nim->sto_ijk = nifti_mat44_inverse( nim->sto_xyz ) ; nim->sform_code = nhdr.sform_code ; if( g_opts.debug > 1 ) nifti_disp_matrix_orient("-d sform orientations:\n", nim->sto_xyz); } /**- set miscellaneous NIFTI stuff */ if( is_nifti ){ nim->scl_slope = FIXED_FLOAT( nhdr.scl_slope ) ; nim->scl_inter = FIXED_FLOAT( nhdr.scl_inter ) ; nim->intent_code = nhdr.intent_code ; nim->intent_p1 = FIXED_FLOAT( nhdr.intent_p1 ) ; nim->intent_p2 = FIXED_FLOAT( nhdr.intent_p2 ) ; nim->intent_p3 = FIXED_FLOAT( nhdr.intent_p3 ) ; nim->toffset = FIXED_FLOAT( nhdr.toffset ) ; memcpy(nim->intent_name,nhdr.intent_name,15); nim->intent_name[15] = '\0'; nim->xyz_units = XYZT_TO_SPACE(nhdr.xyzt_units) ; nim->time_units = XYZT_TO_TIME (nhdr.xyzt_units) ; nim->freq_dim = DIM_INFO_TO_FREQ_DIM ( nhdr.dim_info ) ; nim->phase_dim = DIM_INFO_TO_PHASE_DIM( nhdr.dim_info ) ; nim->slice_dim = DIM_INFO_TO_SLICE_DIM( nhdr.dim_info ) ; nim->slice_code = nhdr.slice_code ; nim->slice_start = nhdr.slice_start ; nim->slice_end = nhdr.slice_end ; nim->slice_duration = FIXED_FLOAT(nhdr.slice_duration) ; } /**- set Miscellaneous ANALYZE stuff */ nim->cal_min = FIXED_FLOAT(nhdr.cal_min) ; nim->cal_max = FIXED_FLOAT(nhdr.cal_max) ; memcpy(nim->descrip ,nhdr.descrip ,79) ; nim->descrip [79] = '\0' ; memcpy(nim->aux_file,nhdr.aux_file,23) ; nim->aux_file[23] = '\0' ; /**- set ioff from vox_offset (but at least sizeof(header)) */ is_onefile = is_nifti && NIFTI_ONEFILE(nhdr) ; if( is_onefile ){ ioff = (int)nhdr.vox_offset ; if( ioff < (int) sizeof(nhdr) ) ioff = (int) sizeof(nhdr) ; } else { ioff = (int)nhdr.vox_offset ; } nim->iname_offset = ioff ; /**- deal with file names if set */ if (fname!=NULL) { nifti_set_filenames(nim,fname,0,0); if (nim->iname==NULL) { ERREX("bad filename"); } } else { nim->fname = NULL; nim->iname = NULL; } /* clear extension fields */ nim->num_ext = 0; nim->ext_list = NULL; return nim; } #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_image_open(%s): %s\n", \ (hname != NULL) ? hname : "(null)" , (msg) ) ; \ return fptr ; } while(0) /*************************************************************** * nifti_image_open ***************************************************************/ /*! znzFile nifti_image_open( char *hname, char *opts , nifti_image **nim) \brief Read in NIFTI-1 or ANALYZE-7.5 file (pair) header information into a nifti_image struct. - The image data is not read from disk (it may be read later using nifti_image_load(), for example). - The image data will be stored in whatever data format the input data is; no scaling will be applied. - DT_BINARY data is not supported. - nifti_image_free() can be used to delete the returned struct, when you are done with it. \param hname filename of dataset .hdr or .nii file \param opts options string for opening the header file \param nim pointer to pointer to nifti_image struct (this routine allocates the nifti_image struct) \return file pointer (gzippable) to the file with the image data, ready for reading.
NULL if something fails badly. \sa nifti_image_load, nifti_image_free */ znzFile nifti_image_open(const char * hname, const char * opts, nifti_image ** nim) { znzFile fptr=NULL; /* open the hdr and reading it in, but do not load the data */ *nim = nifti_image_read(hname,0); /* open the image file, ready for reading (compressed works for all reads) */ if( ((*nim) == NULL) || ((*nim)->iname == NULL) || ((*nim)->nbyper <= 0) || ((*nim)->nvox <= 0) ) ERREX("bad header info") ; /* open image data file */ fptr = znzopen( (*nim)->iname, opts, nifti_is_gzfile((*nim)->iname) ); if( znz_isnull(fptr) ) ERREX("Can't open data file") ; return fptr; } /*----------------------------------------------------------------------*/ /*! return an allocated and filled nifti_1_header struct Read the binary header from disk, and swap bytes if necessary. \return an allocated nifti_1_header struct, or NULL on failure \param hname name of file containing header \param swapped if not NULL, return whether header bytes were swapped \param check flag to check for invalid nifti_1_header \warning ASCII header type is not supported \sa nifti_image_read, nifti_image_free, nifti_image_read_bricks *//*--------------------------------------------------------------------*/ nifti_1_header * nifti_read_header(const char * hname, int * swapped, int check) { nifti_1_header nhdr, * hptr; znzFile fp; int bytes, lswap; char * hfile; char fname[] = { "nifti_read_header" }; /* determine file name to use for header */ hfile = nifti_findhdrname(hname); if( hfile == NULL ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to find header file for", hname); return NULL; } else if( g_opts.debug > 1 ) fprintf(stderr,"-d %s: found header filename '%s'\n",fname,hfile); fp = znzopen( hfile, "rb", nifti_is_gzfile(hfile) ); if( znz_isnull(fp) ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open header file",hfile); free(hfile); return NULL; } free(hfile); /* done with filename */ if( has_ascii_header(fp) == 1 ){ znzclose( fp ); if( g_opts.debug > 0 ) LNI_FERR(fname,"ASCII header type not supported",hname); return NULL; } /* read the binary header */ bytes = (int)znzread( &nhdr, 1, sizeof(nhdr), fp ); znzclose( fp ); /* we are done with the file now */ if( bytes < (int)sizeof(nhdr) ){ if( g_opts.debug > 0 ){ LNI_FERR(fname,"bad binary header read for file", hname); fprintf(stderr," - read %d of %d bytes\n",bytes, (int)sizeof(nhdr)); } return NULL; } /* now just decide on byte swapping */ lswap = need_nhdr_swap(nhdr.dim[0], nhdr.sizeof_hdr); /* swap data flag */ if( check && lswap < 0 ){ LNI_FERR(fname,"bad nifti_1_header for file", hname); return NULL; } else if ( lswap < 0 ) { lswap = 0; /* if swapping does not help, don't do it */ if(g_opts.debug > 1) fprintf(stderr,"-- swap failure, none applied\n"); } if( lswap ) { if ( g_opts.debug > 3 ) disp_nifti_1_header("-d nhdr pre-swap: ", &nhdr); swap_nifti_header( &nhdr , NIFTI_VERSION(nhdr) ) ; } if ( g_opts.debug > 2 ) disp_nifti_1_header("-d nhdr post-swap: ", &nhdr); if ( check && ! nifti_hdr_looks_good(&nhdr) ){ LNI_FERR(fname,"nifti_1_header looks bad for file", hname); return NULL; } /* all looks good, so allocate memory for and return the header */ hptr = (nifti_1_header *)malloc(sizeof(nifti_1_header)); if( ! hptr ){ fprintf(stderr,"** nifti_read_hdr: failed to alloc nifti_1_header\n"); return NULL; } if( swapped ) *swapped = lswap; /* only if they care */ memcpy(hptr, &nhdr, sizeof(nifti_1_header)); return hptr; } /*----------------------------------------------------------------------*/ /*! decide if this nifti_1_header structure looks reasonable Check dim[0], dim[1], sizeof_hdr, and datatype. Check magic string for "n+1". Maybe more tests will follow. \return 1 if the header seems valid, 0 otherwise \sa nifti_nim_is_valid, valid_nifti_extensions *//*--------------------------------------------------------------------*/ int nifti_hdr_looks_good(const nifti_1_header * hdr) { int is_nifti, c, errs = 0; /* check dim[0] and sizeof_hdr */ if( need_nhdr_swap(hdr->dim[0], hdr->sizeof_hdr) < 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"** bad nhdr fields: dim0, sizeof_hdr = %d, %d\n", hdr->dim[0], hdr->sizeof_hdr); errs++; } /* check the valid dimension sizes (maybe dim[0] is bad) */ for( c = 1; c <= hdr->dim[0] && c <= 7; c++ ) if( hdr->dim[c] <= 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"** bad nhdr field: dim[%d] = %d\n",c,hdr->dim[c]); errs++; } is_nifti = NIFTI_VERSION(*hdr); /* determine header type */ if( is_nifti ){ /* NIFTI */ if( ! nifti_datatype_is_valid(hdr->datatype, 1) ){ if( g_opts.debug > 0 ) fprintf(stderr,"** bad NIFTI datatype in hdr, %d\n",hdr->datatype); errs++; } } else { /* ANALYZE 7.5 */ if( g_opts.debug > 1 ) /* maybe tell user it's an ANALYZE hdr */ fprintf(stderr, "-- nhdr magic field implies ANALYZE: magic = '%.4s'\n",hdr->magic); if( ! nifti_datatype_is_valid(hdr->datatype, 0) ){ if( g_opts.debug > 0 ) fprintf(stderr,"** bad ANALYZE datatype in hdr, %d\n",hdr->datatype); errs++; } } if( errs ) return 0; /* problems */ if( g_opts.debug > 2 ) fprintf(stderr,"-d nifti header looks good\n"); return 1; /* looks good */ } /*---------------------------------------------------------------------- * check whether byte swapping is needed * * dim[0] should be in [0,7], and sizeof_hdr should be accurate * * \returns > 0 : needs swap * 0 : does not need swap * < 0 : error condition *----------------------------------------------------------------------*/ static int need_nhdr_swap( short dim0, int hdrsize ) { short d0 = dim0; /* so we won't have to swap them on the stack */ int hsize = hdrsize; if( d0 != 0 ){ /* then use it for the check */ if( d0 > 0 && d0 <= 7 ) return 0; nifti_swap_2bytes(1, &d0); /* swap? */ if( d0 > 0 && d0 <= 7 ) return 1; if( g_opts.debug > 1 ){ fprintf(stderr,"** NIFTI: bad swapped d0 = %d, unswapped = ", d0); nifti_swap_2bytes(1, &d0); /* swap? */ fprintf(stderr,"%d\n", d0); } return -1; /* bad, naughty d0 */ } /* dim[0] == 0 should not happen, but could, so try hdrsize */ if( hsize == sizeof(nifti_1_header) ) return 0; nifti_swap_4bytes(1, &hsize); /* swap? */ if( hsize == sizeof(nifti_1_header) ) return 1; if( g_opts.debug > 1 ){ fprintf(stderr,"** NIFTI: bad swapped hsize = %d, unswapped = ", hsize); nifti_swap_4bytes(1, &hsize); /* swap? */ fprintf(stderr,"%d\n", hsize); } return -2; /* bad, naughty hsize */ } /* use macro LNI_FILE_ERROR instead of ERREX() #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_image_read(%s): %s\n", \ (hname != NULL) ? hname : "(null)" , (msg) ) ; \ return NULL ; } while(0) */ /*************************************************************** * nifti_image_read ***************************************************************/ /*! \brief Read a nifti header and optionally the data, creating a nifti_image. - The data buffer will be byteswapped if necessary. - The data buffer will not be scaled. - The data buffer is allocated with calloc(). \param hname filename of the nifti dataset \param read_data Flag, true=read data blob, false=don't read blob. \return A pointer to the nifti_image data structure. \sa nifti_image_free, nifti_free_extensions, nifti_image_read_bricks */ nifti_image *nifti_image_read( const char *hname , int read_data ) { struct nifti_1_header nhdr ; nifti_image *nim ; znzFile fp ; int rv, ii , filesize, remaining; char fname[] = { "nifti_image_read" }; char *hfile=NULL; if( g_opts.debug > 1 ){ fprintf(stderr,"-d image_read from '%s', read_data = %d",hname,read_data); #ifdef HAVE_ZLIB fprintf(stderr,", HAVE_ZLIB = 1\n"); #else fprintf(stderr,", HAVE_ZLIB = 0\n"); #endif } /**- determine filename to use for header */ hfile = nifti_findhdrname(hname); if( hfile == NULL ){ if(g_opts.debug > 0) LNI_FERR(fname,"failed to find header file for", hname); return NULL; /* check return */ } else if( g_opts.debug > 1 ) fprintf(stderr,"-d %s: found header filename '%s'\n",fname,hfile); if( nifti_is_gzfile(hfile) ) filesize = -1; /* unknown */ else filesize = nifti_get_filesize(hfile); fp = znzopen(hfile, "rb", nifti_is_gzfile(hfile)); if( znz_isnull(fp) ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"failed to open header file",hfile); free(hfile); return NULL; } rv = has_ascii_header( fp ); if( rv < 0 ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"short header read",hfile); znzclose( fp ); free(hfile); return NULL; } else if ( rv == 1 ){ /* process special file type */ nim = nifti_read_ascii_image( fp, hfile, filesize, read_data ); znzclose(fp); free(hfile); return nim; } /* else, just process normally */ /**- read binary header */ ii = (int)znzread( &nhdr , 1 , sizeof(nhdr) , fp ) ; /* read the thing */ /* keep file open so we can check for exts. after nifti_convert_nhdr2nim() */ if( ii < (int) sizeof(nhdr) ){ if( g_opts.debug > 0 ){ LNI_FERR(fname,"bad binary header read for file", hfile); fprintf(stderr," - read %d of %d bytes\n",ii, (int)sizeof(nhdr)); } znzclose(fp) ; free(hfile); return NULL; } /* create output image struct and set it up */ /**- convert all nhdr fields to nifti_image fields */ nim = nifti_convert_nhdr2nim(nhdr,hfile); if( nim == NULL ){ znzclose( fp ) ; /* close the file */ if( g_opts.debug > 0 ) LNI_FERR(fname,"cannot create nifti image from header",hfile); free(hfile); /* had to save this for debug message */ return NULL; } if( g_opts.debug > 3 ){ fprintf(stderr,"+d nifti_image_read(), have nifti image:\n"); if( g_opts.debug > 2 ) nifti_image_infodump(nim); } /**- check for extensions (any errors here means no extensions) */ if( NIFTI_ONEFILE(nhdr) ) remaining = nim->iname_offset - sizeof(nhdr); else remaining = filesize - sizeof(nhdr); (void)nifti_read_extensions(nim, fp, remaining); znzclose( fp ) ; /* close the file */ free(hfile); /**- read the data if desired, then bug out */ if( read_data ){ if( nifti_image_load( nim ) < 0 ){ nifti_image_free(nim); /* take ball, go home. */ return NULL; } } else nim->data = NULL ; return nim ; } /*---------------------------------------------------------------------- * has_ascii_header - see if the NIFTI header is an ASCII format * * If the file starts with the ASCII string " 1 ) fprintf(stderr,"-d %s: have ASCII NIFTI file of size %d\n",fname,slen); if( slen > 65530 ) slen = 65530 ; sbuf = (char *)calloc(sizeof(char),slen+1) ; if( !sbuf ){ fprintf(stderr,"** %s: failed to alloc %d bytes for sbuf",lfunc,65530); return NULL; } znzread( sbuf , 1 , slen , fp ) ; nim = nifti_image_from_ascii( sbuf, &txt_size ) ; free( sbuf ) ; if( nim == NULL ){ LNI_FERR(lfunc,"failed nifti_image_from_ascii()",fname); return NULL; } nim->nifti_type = NIFTI_FTYPE_ASCII ; /* compute remaining space for extensions */ remain = flen - txt_size - (int)nifti_get_volsize(nim); if( remain > 4 ){ /* read extensions (reposition file pointer, first) */ znzseek(fp, txt_size, SEEK_SET); (void) nifti_read_extensions(nim, fp, remain); } nim->iname_offset = -1 ; /* check from the end of the file */ if( read_data ) rv = nifti_image_load( nim ) ; else nim->data = NULL ; /* check for nifti_image_load() failure, maybe bail out */ if( read_data && rv != 0 ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d failed image_load, free nifti image struct\n"); free(nim); return NULL; } return nim ; } /*---------------------------------------------------------------------- * Read the extensions into the nifti_image struct 08 Dec 2004 [rickr] * * This function is called just after the header struct is read in, and * it is assumed the file pointer has not moved. The value in remain * is assumed to be accurate, reflecting the bytes of space for potential * extensions. * * return the number of extensions read in, or < 0 on error *----------------------------------------------------------------------*/ static int nifti_read_extensions( nifti_image *nim, znzFile fp, int remain ) { nifti1_extender extdr; /* defines extension existence */ nifti1_extension extn; /* single extension to process */ nifti1_extension * Elist; /* list of processed extensions */ int posn, count; if( !nim || znz_isnull(fp) ) { if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_read_extensions: bad inputs (%p,%p)\n", (void *)nim, (void *)fp); return -1; } posn = znztell(fp); if( (posn != sizeof(nifti_1_header)) && (nim->nifti_type != NIFTI_FTYPE_ASCII) ) fprintf(stderr,"** WARNING: posn not header size (%d, %d)\n", posn, (int)sizeof(nifti_1_header)); if( g_opts.debug > 2 ) fprintf(stderr,"-d nre: posn = %d, offset = %d, type = %d, remain = %d\n", posn, nim->iname_offset, nim->nifti_type, remain); if( remain < 16 ){ if( g_opts.debug > 2 ){ if( g_opts.skip_blank_ext ) fprintf(stderr,"-d no extender in '%s' is okay, as " "skip_blank_ext is set\n",nim->fname); else fprintf(stderr,"-d remain=%d, no space for extensions\n",remain); } return 0; } count = (int)znzread( extdr.extension, 1, 4, fp ); /* get extender */ if( count < 4 ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d file '%s' is too short for an extender\n", nim->fname); return 0; } if( extdr.extension[0] != 1 ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d extender[0] (%d) shows no extensions for '%s'\n", extdr.extension[0], nim->fname); return 0; } remain -= 4; if( g_opts.debug > 2 ) fprintf(stderr,"-d found valid 4-byte extender, remain = %d\n", remain); /* so we expect extensions, but have no idea of how many there may be */ count = 0; Elist = NULL; while (nifti_read_next_extension(&extn, nim, remain, fp) > 0) { if( nifti_add_exten_to_list(&extn, &Elist, count+1) < 0 ){ free(Elist); if( g_opts.debug > 0 ) fprintf(stderr,"** failed adding ext %d to list\n", count); return -1; } /* we have a new extension */ if( g_opts.debug > 1 ){ fprintf(stderr,"+d found extension #%d, code = 0x%x, size = %d\n", count, extn.ecode, extn.esize); if( extn.ecode == NIFTI_ECODE_AFNI && g_opts.debug > 2 ) /* ~XML */ fprintf(stderr," AFNI extension: %.*s\n", extn.esize-8,extn.edata); else if( extn.ecode == NIFTI_ECODE_COMMENT && g_opts.debug > 2 ) fprintf(stderr," COMMENT extension: %.*s\n", /* TEXT */ extn.esize-8,extn.edata); } remain -= extn.esize; count++; } if( g_opts.debug > 2 ) fprintf(stderr,"+d found %d extension(s)\n", count); nim->num_ext = count; nim->ext_list = Elist; return count; } /*----------------------------------------------------------------------*/ /*! nifti_add_extension - add an extension, with a copy of the data Add an extension to the nim->ext_list array. Fill this extension with a copy of the data, noting the length and extension code. \param nim - nifti_image to add extension to \param data - raw extension data \param length - length of raw extension data \param ecode - extension code \sa extension codes NIFTI_ECODE_* in nifti1_io.h \sa nifti_free_extensions, valid_nifti_extensions, nifti_copy_extensions \return 0 on success, -1 on error (and free the entire list) *//*--------------------------------------------------------------------*/ int nifti_add_extension(nifti_image *nim, const char * data, int len, int ecode) { nifti1_extension ext; /* error are printed in functions */ if( nifti_fill_extension(&ext, data, len, ecode) ) {free(ext.edata); return -1;} if( nifti_add_exten_to_list(&ext, &nim->ext_list, nim->num_ext+1)) {free(ext.edata); return -1;} nim->num_ext++; /* success, so increment */ return 0; } /*----------------------------------------------------------------------*/ /* nifti_add_exten_to_list - add a new nifti1_extension to the list We will append via "malloc, copy and free", because on an error, the list will revert to the previous one (sorry realloc(), only quality dolphins get to become part of St@rk!st brand tunafish). return 0 on success, -1 on error (and free the entire list) *//*--------------------------------------------------------------------*/ static int nifti_add_exten_to_list( nifti1_extension * new_ext, nifti1_extension ** list, int new_length ) { nifti1_extension * tmplist; tmplist = *list; *list = (nifti1_extension *)malloc(new_length * sizeof(nifti1_extension)); /* check for failure first */ if( ! *list ){ fprintf(stderr,"** failed to alloc %d extension structs (%d bytes)\n", new_length, new_length*(int)sizeof(nifti1_extension)); if( !tmplist ) return -1; /* no old list to lose */ *list = tmplist; /* reset list to old one */ return -1; } /* if an old list exists, copy the pointers and free the list */ if( tmplist ){ memcpy(*list, tmplist, (new_length-1)*sizeof(nifti1_extension)); free(tmplist); } /* for some reason, I just don't like struct copy... */ (*list)[new_length-1].esize = new_ext->esize; (*list)[new_length-1].ecode = new_ext->ecode; (*list)[new_length-1].edata = new_ext->edata; if( g_opts.debug > 2 ) fprintf(stderr,"+d allocated and appended extension #%d to list\n", new_length); return 0; } /*----------------------------------------------------------------------*/ /* nifti_fill_extension - given data and length, fill an extension struct Allocate memory for data, copy data, set the size and code. return 0 on success, -1 on error (and free the entire list) *//*--------------------------------------------------------------------*/ static int nifti_fill_extension( nifti1_extension *ext, const char * data, int len, int ecode) { int esize; if( !ext || !data || len < 0 ){ fprintf(stderr,"** fill_ext: bad params (%p,%p,%d)\n", (void *)ext, data, len); return -1; } else if( ! nifti_is_valid_ecode(ecode) ){ fprintf(stderr,"** warning: writing unknown ecode %d\n", ecode); /* should not be fatal 29 Apr 2015 [rickr] */ } /* compute esize, first : len+8, and take ceiling up to a mult of 16 */ esize = len+8; if( esize & 0xf ) esize = (esize + 0xf) & ~0xf; ext->esize = esize; /* allocate esize-8 (maybe more than len), using calloc for fill */ ext->edata = (char *)calloc(esize-8, sizeof(char)); if( !ext->edata ){ fprintf(stderr,"** NFE: failed to alloc %d bytes for extension\n",len); return -1; } memcpy(ext->edata, data, len); /* copy the data, using len */ ext->ecode = ecode; /* set the ecode */ if( g_opts.debug > 2 ) fprintf(stderr,"+d alloc %d bytes for ext len %d, ecode %d, esize %d\n", esize-8, len, ecode, esize); return 0; } /*---------------------------------------------------------------------- * nifti_read_next_extension - read a single extension from the file * * return (>= 0 is okay): * * success : esize * no extension : 0 * error : -1 *----------------------------------------------------------------------*/ static int nifti_read_next_extension( nifti1_extension * nex, nifti_image *nim, int remain, znzFile fp ) { int swap = nim->byteorder != nifti_short_order(); int count, size, code = NIFTI_ECODE_IGNORE; /* first clear nex */ nex->esize = nex->ecode = 0; nex->edata = NULL; if( remain < 16 ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d only %d bytes remain, so no extension\n", remain); return 0; } /* must start with 4-byte size and code */ count = (int)znzread( &size, 4, 1, fp ); if( count == 1 ) count += (int)znzread( &code, 4, 1, fp ); if( count != 2 ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d current extension read failed\n"); znzseek(fp, -4*count, SEEK_CUR); /* back up past any read */ return 0; /* no extension, no error condition */ } if( swap ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d pre-swap exts: code %d, size %d\n", code, size); nifti_swap_4bytes(1, &size); nifti_swap_4bytes(1, &code); } if( g_opts.debug > 2 ) fprintf(stderr,"-d potential extension: code %d, size %d\n", code, size); if( !nifti_check_extension(nim, size, code, remain) ){ if( znzseek(fp, -8, SEEK_CUR) < 0 ){ /* back up past any read */ fprintf(stderr,"** failure to back out of extension read!\n"); return -1; } return 0; } /* now get the actual data */ nex->esize = size; nex->ecode = code; size -= 8; /* subtract space for size and code in extension */ nex->edata = (char *)malloc(size * sizeof(char)); if( !nex->edata ){ fprintf(stderr,"** failed to allocate %d bytes for extension\n",size); return -1; } count = (int)znzread(nex->edata, 1, size, fp); if( count < size ){ if( g_opts.debug > 0 ) fprintf(stderr,"-d read only %d (of %d) bytes for extension\n", count, size); free(nex->edata); nex->edata = NULL; return -1; } /* success! */ if( g_opts.debug > 2 ) fprintf(stderr,"+d successfully read extension, code %d, size %d\n", nex->ecode, nex->esize); return nex->esize; } /*----------------------------------------------------------------------*/ /*! for each extension, check code, size and data pointer *//*--------------------------------------------------------------------*/ int valid_nifti_extensions(const nifti_image * nim) { nifti1_extension * ext; int c, errs; if( nim->num_ext <= 0 || nim->ext_list == NULL ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d empty extension list\n"); return 0; } /* for each extension, check code, size and data pointer */ ext = nim->ext_list; errs = 0; for ( c = 0; c < nim->num_ext; c++ ){ if( ! nifti_is_valid_ecode(ext->ecode) ) { if( g_opts.debug > 1 ) fprintf(stderr,"-d ext %d, unknown code %d\n", c, ext->ecode); /* should not be fatal 29 Apr 2015 [rickr] */ } if( ext->esize <= 0 ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d ext %d, bad size = %d\n", c, ext->esize); errs++; } else if( ext->esize & 0xf ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d ext %d, size %d not multiple of 16\n", c, ext->esize); errs++; } if( ext->edata == NULL ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d ext %d, missing data\n", c); errs++; } ext++; } if( errs > 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"-d had %d extension errors, none will be written\n", errs); return 0; } /* if we're here, we're good */ return 1; } /*----------------------------------------------------------------------*/ /*! check whether the extension code is valid \return 1 if valid, 0 otherwise *//*--------------------------------------------------------------------*/ int nifti_is_valid_ecode( int ecode ) { if( ecode < NIFTI_ECODE_IGNORE || /* minimum code number (0) */ ecode > NIFTI_MAX_ECODE || /* maximum code number */ ecode & 1 ) /* cannot be odd */ return 0; return 1; } /*---------------------------------------------------------------------- * check for valid size and code, as well as can be done *----------------------------------------------------------------------*/ static int nifti_check_extension(nifti_image *nim, int size, int code, int rem) { /* check for bad code before bad size */ if( ! nifti_is_valid_ecode(code) ) { if( g_opts.debug > 2 ) fprintf(stderr,"-d invalid extension code %d\n",code); /* should not be fatal 29 Apr 2015 [rickr] */ } if( size < 16 ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d ext size %d, no extension\n",size); return 0; } if( size > rem ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d ext size %d, space %d, no extension\n", size, rem); return 0; } if( size & 0xf ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d nifti extension size %d not multiple of 16\n",size); return 0; } if( nim->nifti_type == NIFTI_FTYPE_ASCII && size > LNI_MAX_NIA_EXT_LEN ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d NVE, bad nifti_type 3 size %d\n", size); return 0; } return 1; } /*---------------------------------------------------------------------- * nifti_image_load_prep - prepare to read data * * Check nifti_image fields, open the file and seek to the appropriate * offset for reading. * * return NULL on failure *----------------------------------------------------------------------*/ static znzFile nifti_image_load_prep( nifti_image *nim ) { /* set up data space, open data file and seek, then call nifti_read_buffer */ size_t ntot , ii , ioff; znzFile fp; char *tmpimgname; char fname[] = { "nifti_image_load_prep" }; /**- perform sanity checks */ if( nim == NULL || nim->iname == NULL || nim->nbyper <= 0 || nim->nvox <= 0 ) { if ( g_opts.debug > 0 ){ if( !nim ) fprintf(stderr,"** ERROR: N_image_load: no nifti image\n"); else fprintf(stderr,"** ERROR: N_image_load: bad params (%p,%d,%u)\n", nim->iname, nim->nbyper, (unsigned)nim->nvox); } return NULL; } ntot = nifti_get_volsize(nim) ; /* total bytes to read */ /**- open image data file */ tmpimgname = nifti_findimgname(nim->iname , nim->nifti_type); if( tmpimgname == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** no image file found for '%s'\n",nim->iname); return NULL; } fp = znzopen(tmpimgname, "rb", nifti_is_gzfile(tmpimgname)); if (znz_isnull(fp)){ if(g_opts.debug > 0) LNI_FERR(fname,"cannot open data file",tmpimgname); free(tmpimgname); return NULL; /* bad open? */ } free(tmpimgname); /**- get image offset: a negative offset means to figure from end of file */ if( nim->iname_offset < 0 ){ if( nifti_is_gzfile(nim->iname) ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"negative offset for compressed file",nim->iname); znzclose(fp); return NULL; } ii = nifti_get_filesize( nim->iname ) ; if( ii <= 0 ){ if( g_opts.debug > 0 ) LNI_FERR(fname,"empty data file",nim->iname); znzclose(fp); return NULL; } ioff = (ii > ntot) ? ii-ntot : 0 ; } else { /* non-negative offset */ ioff = nim->iname_offset ; /* means use it directly */ } /**- seek to the appropriate read position */ if( znzseek(fp , (long)ioff , SEEK_SET) < 0 ){ fprintf(stderr,"** could not seek to offset %u in file '%s'\n", (unsigned)ioff, nim->iname); znzclose(fp); return NULL; } /**- and return the File pointer */ return fp; } /*---------------------------------------------------------------------- * nifti_image_load *----------------------------------------------------------------------*/ /*! \fn int nifti_image_load( nifti_image *nim ) \brief Load the image blob into a previously initialized nifti_image. - If not yet set, the data buffer is allocated with calloc(). - The data buffer will be byteswapped if necessary. - The data buffer will not be scaled. This function is used to read the image from disk. It should be used after a function such as nifti_image_read(), so that the nifti_image structure is already initialized. \param nim pointer to a nifti_image (previously initialized) \return 0 on success, -1 on failure \sa nifti_image_read, nifti_image_free, nifti_image_unload */ int nifti_image_load( nifti_image *nim ) { /* set up data space, open data file and seek, then call nifti_read_buffer */ size_t ntot , ii ; znzFile fp ; /**- open the file and position the FILE pointer */ fp = nifti_image_load_prep( nim ); if( fp == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_image_load, failed load_prep\n"); return -1; } ntot = nifti_get_volsize(nim); /**- if the data pointer is not yet set, get memory space for the image */ if( nim->data == NULL ) { nim->data = (void *)calloc(1,ntot) ; /* create image memory */ if( nim->data == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** failed to alloc %d bytes for image data\n", (int)ntot); znzclose(fp); return -1; } } /**- now that everything is set up, do the reading */ ii = nifti_read_buffer(fp,nim->data,ntot,nim); if( ii < ntot ){ znzclose(fp) ; free(nim->data) ; nim->data = NULL ; return -1 ; /* errors were printed in nifti_read_buffer() */ } /**- close the file */ znzclose( fp ) ; return 0 ; } /* 30 Nov 2004 [rickr] #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_read_buffer: %s\n",(msg)) ; \ return 0; } while(0) */ /*----------------------------------------------------------------------*/ /*! read ntot bytes of data from an open file and byte swaps if necessary note that nifti_image is required for information on datatype, bsize (for any needed byte swapping), etc. This function does not allocate memory, so dataptr must be valid. *//*--------------------------------------------------------------------*/ size_t nifti_read_buffer(znzFile fp, void* dataptr, size_t ntot, nifti_image *nim) { size_t ii; if( dataptr == NULL ){ if( g_opts.debug > 0 ) fprintf(stderr,"** ERROR: nifti_read_buffer: NULL dataptr\n"); return -1; } ii = znzread( dataptr , 1 , ntot , fp ) ; /* data input */ /* if read was short, fail */ if( ii < ntot ){ if( g_opts.debug > 0 ) fprintf(stderr,"++ WARNING: nifti_read_buffer(%s):\n" " data bytes needed = %u\n" " data bytes input = %u\n" " number missing = %u (set to 0)\n", nim->iname , (unsigned int)ntot , (unsigned int)ii , (unsigned int)(ntot-ii) ) ; /* memset( (char *)(dataptr)+ii , 0 , ntot-ii ) ; now failure [rickr] */ return -1 ; } if( g_opts.debug > 2 ) fprintf(stderr,"+d nifti_read_buffer: read %u bytes\n", (unsigned)ii); /* byte swap array if needed */ /* ntot/swapsize might not fit as int, use size_t 6 Jul 2010 [rickr] */ if( nim->swapsize > 1 && nim->byteorder != nifti_short_order() ) { if( g_opts.debug > 1 ) fprintf(stderr,"+d nifti_read_buffer: swapping data bytes...\n"); nifti_swap_Nbytes( (int)(ntot / nim->swapsize), nim->swapsize , dataptr ) ; } #ifdef isfinite { /* check input float arrays for goodness, and fix bad floats */ int fix_count = 0 ; switch( nim->datatype ){ case NIFTI_TYPE_FLOAT32: case NIFTI_TYPE_COMPLEX64:{ float *far = (float *)dataptr ; size_t jj,nj ; nj = ntot / sizeof(float) ; for( jj=0 ; jj < nj ; jj++ ) /* count fixes 30 Nov 2004 [rickr] */ if( !IS_GOOD_FLOAT(far[jj]) ){ far[jj] = 0 ; fix_count++ ; } } break ; case NIFTI_TYPE_FLOAT64: case NIFTI_TYPE_COMPLEX128:{ double *far = (double *)dataptr ; size_t jj,nj ; nj = ntot / sizeof(double) ; for( jj=0 ; jj < nj ; jj++ ) /* count fixes 30 Nov 2004 [rickr] */ if( !IS_GOOD_FLOAT(far[jj]) ){ far[jj] = 0 ; fix_count++ ; } } break ; } if( g_opts.debug > 1 ) fprintf(stderr,"+d in image, %d bad floats were set to 0\n", fix_count); } #endif return ii; } /*--------------------------------------------------------------------------*/ /*! Unload the data in a nifti_image struct, but keep the metadata. *//*------------------------------------------------------------------------*/ void nifti_image_unload( nifti_image *nim ) { if( nim != NULL && nim->data != NULL ){ free(nim->data) ; nim->data = NULL ; } } /*--------------------------------------------------------------------------*/ /*! free 'everything' about a nifti_image struct (including the passed struct) free (only fields which are not NULL): - fname and iname - data - any ext_list[i].edata - ext_list - nim *//*------------------------------------------------------------------------*/ void nifti_image_free( nifti_image *nim ) { if( nim == NULL ) return ; if( nim->fname != NULL ) free(nim->fname) ; if( nim->iname != NULL ) free(nim->iname) ; if( nim->data != NULL ) free(nim->data ) ; (void)nifti_free_extensions( nim ) ; free(nim) ; } /*--------------------------------------------------------------------------*/ /*! free the nifti extensions - If any edata pointer is set in the extension list, free() it. - Free ext_list, if it is set. - Clear num_ext and ext_list from nim. \return 0 on success, -1 on error \sa nifti_add_extension, nifti_copy_extensions *//*------------------------------------------------------------------------*/ int nifti_free_extensions( nifti_image *nim ) { int c ; if( nim == NULL ) return -1; if( nim->num_ext > 0 && nim->ext_list ){ for( c = 0; c < nim->num_ext; c++ ) if ( nim->ext_list[c].edata ) free(nim->ext_list[c].edata); free(nim->ext_list); } /* or if it is inconsistent, warn the user (if we are not in quiet mode) */ else if ( (nim->num_ext > 0 || nim->ext_list != NULL) && (g_opts.debug > 0) ) fprintf(stderr,"** warning: nifti extension num/ptr mismatch (%d,%p)\n", nim->num_ext, (void *)nim->ext_list); if( g_opts.debug > 2 ) fprintf(stderr,"+d free'd %d extension(s)\n", nim->num_ext); nim->num_ext = 0; nim->ext_list = NULL; return 0; } /*--------------------------------------------------------------------------*/ /*! Print to stdout some info about a nifti_image struct. *//*------------------------------------------------------------------------*/ void nifti_image_infodump( const nifti_image *nim ) { char *str = nifti_image_to_ascii( nim ) ; /* stdout -> stderr 2 Dec 2004 [rickr] */ if( str != NULL ){ fputs(str,stderr) ; free(str) ; } } /*-------------------------------------------------------------------------- * nifti_write_buffer just check for a null znzFile and call znzwrite *--------------------------------------------------------------------------*/ /*! \fn size_t nifti_write_buffer(znzFile fp, void *buffer, size_t numbytes) \brief write numbytes of buffer to file, fp \param fp File pointer (from znzopen) to gzippable nifti datafile \param buffer data buffer to be written \param numbytes number of bytes in buffer to write \return number of bytes successfully written */ size_t nifti_write_buffer(znzFile fp, const void *buffer, size_t numbytes) { /* Write all the image data at once (no swapping here) */ size_t ss; if (znz_isnull(fp)){ fprintf(stderr,"** ERROR: nifti_write_buffer: null file pointer\n"); return 0; } ss = znzwrite( (const void*)buffer , 1 , numbytes , fp ) ; return ss; } /*----------------------------------------------------------------------*/ /*! write the nifti_image data to file (from nim->data or from NBL) If NBL is not NULL, write the data from that structure. Otherwise, write it out from nim->data. No swapping is done here. \param fp : File pointer \param nim : nifti_image corresponding to the data \param NBL : optional source of write data (if NULL use nim->data) \return 0 on success, -1 on failure Note: the nifti_image byte_order is set as that of the current CPU. This is because such a conversion was made to the data upon reading, while byte_order was not set (so the programs would know what format the data was on disk). Effectively, since byte_order should match what is on disk, it should bet set to that of the current CPU whenever new filenames are assigned. *//*--------------------------------------------------------------------*/ int nifti_write_all_data(znzFile fp, nifti_image * nim, const nifti_brick_list * NBL) { size_t ss; int bnum; if( !NBL ){ /* just write one buffer and get out of here */ if( nim->data == NULL ){ fprintf(stderr,"** NWAD: no image data to write\n"); return -1; } ss = nifti_write_buffer(fp,nim->data,nim->nbyper * nim->nvox); if (ss < nim->nbyper * nim->nvox){ fprintf(stderr, "** ERROR: NWAD: wrote only %u of %u bytes to file\n", (unsigned)ss, (unsigned)(nim->nbyper * nim->nvox)); return -1; } if( g_opts.debug > 1 ) fprintf(stderr,"+d wrote single image of %u bytes\n", (unsigned)ss); } else { if( ! NBL->bricks || NBL->nbricks <= 0 || NBL->bsize <= 0 ){ fprintf(stderr,"** NWAD: no brick data to write (%p,%d,%u)\n", (void *)NBL->bricks, NBL->nbricks, (unsigned)NBL->bsize); return -1; } for( bnum = 0; bnum < NBL->nbricks; bnum++ ){ ss = nifti_write_buffer(fp, NBL->bricks[bnum], NBL->bsize); if( ss < NBL->bsize ){ fprintf(stderr, "** NWAD ERROR: wrote %u of %u bytes of brick %d of %d to file", (unsigned)ss, (unsigned)NBL->bsize, bnum+1, NBL->nbricks); return -1; } } if( g_opts.debug > 1 ) fprintf(stderr,"+d wrote image of %d brick(s), each of %u bytes\n", NBL->nbricks, (unsigned int)NBL->bsize); } /* mark as being in this CPU byte order */ nim->byteorder = nifti_short_order() ; return 0; } /* return number of extensions written, or -1 on error */ static int nifti_write_extensions(znzFile fp, nifti_image *nim) { nifti1_extension * list; char extdr[4] = { 0, 0, 0, 0 }; int c, size, ok = 1; if( znz_isnull(fp) || !nim || nim->num_ext < 0 ){ if( g_opts.debug > 0 ) fprintf(stderr,"** nifti_write_extensions, bad params\n"); return -1; } /* if no extensions and user requests it, skip extender */ if( g_opts.skip_blank_ext && (nim->num_ext == 0 || ! nim->ext_list ) ){ if( g_opts.debug > 1 ) fprintf(stderr,"-d no exts and skip_blank_ext set, " "so skipping 4-byte extender\n"); return 0; } /* if invalid extension list, clear num_ext */ if( ! valid_nifti_extensions(nim) ) nim->num_ext = 0; /* write out extender block */ if( nim->num_ext > 0 ) extdr[0] = 1; if( nifti_write_buffer(fp, extdr, 4) != 4 ){ fprintf(stderr,"** failed to write extender\n"); return -1; } list = nim->ext_list; for ( c = 0; c < nim->num_ext; c++ ){ size = (int)nifti_write_buffer(fp, &list->esize, sizeof(int)); ok = (size == (int)sizeof(int)); if( ok ){ size = (int)nifti_write_buffer(fp, &list->ecode, sizeof(int)); ok = (size == (int)sizeof(int)); } if( ok ){ size = (int)nifti_write_buffer(fp, list->edata, list->esize - 8); ok = (size == list->esize - 8); } if( !ok ){ fprintf(stderr,"** failed while writing extension #%d\n",c); return -1; } else if ( g_opts.debug > 2 ) fprintf(stderr,"+d wrote extension %d of %d bytes\n", c, size); list++; } if( g_opts.debug > 1 ) fprintf(stderr,"+d wrote out %d extension(s)\n", nim->num_ext); return nim->num_ext; } /*----------------------------------------------------------------------*/ /*! basic initialization of a nifti_image struct (to a 1x1x1 image) *//*--------------------------------------------------------------------*/ nifti_image* nifti_simple_init_nim(void) { nifti_image *nim; struct nifti_1_header nhdr; int nbyper, swapsize; memset(&nhdr,0,sizeof(nhdr)) ; /* zero out header, to be safe */ nhdr.sizeof_hdr = sizeof(nhdr) ; nhdr.regular = 'r' ; /* for some stupid reason */ nhdr.dim[0] = 3 ; nhdr.dim[1] = 1 ; nhdr.dim[2] = 1 ; nhdr.dim[3] = 1 ; nhdr.dim[4] = 0 ; nhdr.pixdim[0] = 0.0f ; nhdr.pixdim[1] = 1.0f ; nhdr.pixdim[2] = 1.0f ; nhdr.pixdim[3] = 1.0f ; nhdr.datatype = DT_FLOAT32 ; nifti_datatype_sizes( nhdr.datatype , &nbyper, &swapsize ); nhdr.bitpix = 8 * nbyper ; strcpy(nhdr.magic, "n+1"); /* init to single file */ nim = nifti_convert_nhdr2nim(nhdr,NULL); nim->fname = NULL; nim->iname = NULL; return nim; } /*----------------------------------------------------------------------*/ /*! basic initialization of a nifti_1_header struct (with given dimensions) Return an allocated nifti_1_header struct, based on the given dimensions and datatype. \param arg_dims : optional dim[8] array (default {3,1,1,1,0,0,0,0}) \param arg_dtype : optional datatype (default DT_FLOAT32) \return pointer to allocated nifti_1_header struct *//*--------------------------------------------------------------------*/ nifti_1_header * nifti_make_new_header(const int arg_dims[], int arg_dtype) { nifti_1_header * nhdr; const int default_dims[8] = { 3, 1, 1, 1, 0, 0, 0, 0 }; const int * dim; /* either passed or default dims */ int dtype; /* either passed or default dtype */ int c, nbyper, swapsize; /* if arg_dims is passed, apply it */ if( arg_dims ) dim = arg_dims; else dim = default_dims; /* validate dim: if there is any problem, apply default_dims */ if( dim[0] < 1 || dim[0] > 7 ) { fprintf(stderr,"** nifti_simple_hdr_with_dims: bad dim[0]=%d\n",dim[0]); dim = default_dims; } else { for( c = 1; c <= dim[0]; c++ ) if( dim[c] < 1 ) { fprintf(stderr, "** nifti_simple_hdr_with_dims: bad dim[%d]=%d\n",c,dim[c]); dim = default_dims; break; } } /* validate dtype, too */ dtype = arg_dtype; if( ! nifti_is_valid_datatype(dtype) ) { fprintf(stderr,"** nifti_simple_hdr_with_dims: bad dtype %d\n",dtype); dtype = DT_FLOAT32; } /* now populate the header struct */ if( g_opts.debug > 1 ) fprintf(stderr,"+d nifti_make_new_header, dim[0] = %d, datatype = %d\n", dim[0], dtype); nhdr = (nifti_1_header *)calloc(1,sizeof(nifti_1_header)); if( !nhdr ){ fprintf(stderr,"** nifti_make_new_header: failed to alloc hdr\n"); return NULL; } nhdr->sizeof_hdr = sizeof(nifti_1_header) ; nhdr->regular = 'r' ; /* for some stupid reason */ /* init dim and pixdim */ nhdr->dim[0] = dim[0] ; nhdr->pixdim[0] = 0.0f; for( c = 1; c <= dim[0]; c++ ) { nhdr->dim[c] = dim[c]; nhdr->pixdim[c] = 1.0f; } nhdr->datatype = dtype ; nifti_datatype_sizes( nhdr->datatype , &nbyper, &swapsize ); nhdr->bitpix = 8 * nbyper ; strcpy(nhdr->magic, "n+1"); /* init to single file */ return nhdr; } /*----------------------------------------------------------------------*/ /*! basic creation of a nifti_image struct Create a nifti_image from the given dimensions and data type. Optinally, allocate zero-filled data. \param dims : optional dim[8] (default {3,1,1,1,0,0,0,0}) \param datatype : optional datatype (default DT_FLOAT32) \param data_fill : if flag is set, allocate zero-filled data for image \return pointer to allocated nifti_image struct *//*--------------------------------------------------------------------*/ nifti_image * nifti_make_new_nim(const int dims[], int datatype, int data_fill) { nifti_image * nim; nifti_1_header * nhdr; nhdr = nifti_make_new_header(dims, datatype); if( !nhdr ) return NULL; /* error already printed */ nim = nifti_convert_nhdr2nim(*nhdr,NULL); free(nhdr); /* in any case, we are done with this */ if( !nim ){ fprintf(stderr,"** NMNN: nifti_convert_nhdr2nim failure\n"); return NULL; } if( g_opts.debug > 1 ) fprintf(stderr,"+d nifti_make_new_nim, data_fill = %d\n",data_fill); if( data_fill ) { nim->data = calloc(nim->nvox, nim->nbyper); /* if we cannot allocate data, take ball and go home */ if( !nim->data ) { fprintf(stderr,"** NMNN: failed to alloc %u bytes for data\n", (unsigned)(nim->nvox*nim->nbyper)); nifti_image_free(nim); nim = NULL; } } return nim; } /*----------------------------------------------------------------------*/ /*! convert a nifti_image structure to a nifti_1_header struct No allocation is done, this should be used via structure copy. As in:
    nifti_1_header my_header;
    my_header = nifti_convert_nim2nhdr(my_nim_pointer);
    
*//*--------------------------------------------------------------------*/ struct nifti_1_header nifti_convert_nim2nhdr(const nifti_image * nim) { struct nifti_1_header nhdr; memset(&nhdr,0,sizeof(nhdr)) ; /* zero out header, to be safe */ /**- load the ANALYZE-7.5 generic parts of the header struct */ nhdr.sizeof_hdr = sizeof(nhdr) ; nhdr.regular = 'r' ; /* for some stupid reason */ nhdr.dim[0] = nim->ndim ; nhdr.dim[1] = nim->nx ; nhdr.dim[2] = nim->ny ; nhdr.dim[3] = nim->nz ; nhdr.dim[4] = nim->nt ; nhdr.dim[5] = nim->nu ; nhdr.dim[6] = nim->nv ; nhdr.dim[7] = nim->nw ; nhdr.pixdim[0] = 0.0f ; nhdr.pixdim[1] = nim->dx ; nhdr.pixdim[2] = nim->dy ; nhdr.pixdim[3] = nim->dz ; nhdr.pixdim[4] = nim->dt ; nhdr.pixdim[5] = nim->du ; nhdr.pixdim[6] = nim->dv ; nhdr.pixdim[7] = nim->dw ; nhdr.datatype = nim->datatype ; nhdr.bitpix = 8 * nim->nbyper ; if( nim->cal_max > nim->cal_min ){ nhdr.cal_max = nim->cal_max ; nhdr.cal_min = nim->cal_min ; } if( nim->scl_slope != 0.0 ){ nhdr.scl_slope = nim->scl_slope ; nhdr.scl_inter = nim->scl_inter ; } if( nim->descrip[0] != '\0' ){ memcpy(nhdr.descrip ,nim->descrip ,79) ; nhdr.descrip[79] = '\0' ; } if( nim->aux_file[0] != '\0' ){ memcpy(nhdr.aux_file ,nim->aux_file ,23) ; nhdr.aux_file[23] = '\0' ; } /**- Load NIFTI specific stuff into the header */ if( nim->nifti_type > NIFTI_FTYPE_ANALYZE ){ /* then not ANALYZE */ if( nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ) strcpy(nhdr.magic,"n+1") ; else strcpy(nhdr.magic,"ni1") ; nhdr.pixdim[1] = (float)fabs(nhdr.pixdim[1]) ; nhdr.pixdim[2] = (float)fabs(nhdr.pixdim[2]) ; nhdr.pixdim[3] = (float)fabs(nhdr.pixdim[3]) ; nhdr.pixdim[4] = (float)fabs(nhdr.pixdim[4]) ; nhdr.pixdim[5] = (float)fabs(nhdr.pixdim[5]) ; nhdr.pixdim[6] = (float)fabs(nhdr.pixdim[6]) ; nhdr.pixdim[7] = (float)fabs(nhdr.pixdim[7]) ; nhdr.intent_code = nim->intent_code ; nhdr.intent_p1 = nim->intent_p1 ; nhdr.intent_p2 = nim->intent_p2 ; nhdr.intent_p3 = nim->intent_p3 ; if( nim->intent_name[0] != '\0' ){ memcpy(nhdr.intent_name,nim->intent_name,15) ; nhdr.intent_name[15] = '\0' ; } nhdr.vox_offset = (float) nim->iname_offset ; nhdr.xyzt_units = SPACE_TIME_TO_XYZT( nim->xyz_units, nim->time_units ) ; nhdr.toffset = nim->toffset ; if( nim->qform_code > 0 ){ nhdr.qform_code = nim->qform_code ; nhdr.quatern_b = nim->quatern_b ; nhdr.quatern_c = nim->quatern_c ; nhdr.quatern_d = nim->quatern_d ; nhdr.qoffset_x = nim->qoffset_x ; nhdr.qoffset_y = nim->qoffset_y ; nhdr.qoffset_z = nim->qoffset_z ; nhdr.pixdim[0] = (nim->qfac >= 0.0) ? 1.0f : -1.0f ; } if( nim->sform_code > 0 ){ nhdr.sform_code = nim->sform_code ; nhdr.srow_x[0] = nim->sto_xyz.m[0][0] ; nhdr.srow_x[1] = nim->sto_xyz.m[0][1] ; nhdr.srow_x[2] = nim->sto_xyz.m[0][2] ; nhdr.srow_x[3] = nim->sto_xyz.m[0][3] ; nhdr.srow_y[0] = nim->sto_xyz.m[1][0] ; nhdr.srow_y[1] = nim->sto_xyz.m[1][1] ; nhdr.srow_y[2] = nim->sto_xyz.m[1][2] ; nhdr.srow_y[3] = nim->sto_xyz.m[1][3] ; nhdr.srow_z[0] = nim->sto_xyz.m[2][0] ; nhdr.srow_z[1] = nim->sto_xyz.m[2][1] ; nhdr.srow_z[2] = nim->sto_xyz.m[2][2] ; nhdr.srow_z[3] = nim->sto_xyz.m[2][3] ; } nhdr.dim_info = FPS_INTO_DIM_INFO( nim->freq_dim , nim->phase_dim , nim->slice_dim ) ; nhdr.slice_code = nim->slice_code ; nhdr.slice_start = nim->slice_start ; nhdr.slice_end = nim->slice_end ; nhdr.slice_duration = nim->slice_duration ; } return nhdr; } /*----------------------------------------------------------------------*/ /*! \fn int nifti_copy_extensions(nifti_image * nim_dest, nifti_image * nim_src) \brief copy the nifti1_extension list from src to dest Duplicate the list of nifti1_extensions. The dest structure must be clear of extensions. \return 0 on success, -1 on failure \sa nifti_add_extension, nifti_free_extensions */ int nifti_copy_extensions(nifti_image * nim_dest, const nifti_image * nim_src) { char * data; size_t bytes; int c, size, old_size; if( nim_dest->num_ext > 0 || nim_dest->ext_list != NULL ){ fprintf(stderr,"** will not copy extensions over existing ones\n"); return -1; } if( g_opts.debug > 1 ) fprintf(stderr,"+d duplicating %d extension(s)\n", nim_src->num_ext); if( nim_src->num_ext <= 0 ) return 0; bytes = nim_src->num_ext * sizeof(nifti1_extension); /* I'm lazy */ nim_dest->ext_list = (nifti1_extension *)malloc(bytes); if( !nim_dest->ext_list ){ fprintf(stderr,"** failed to allocate %d nifti1_extension structs\n", nim_src->num_ext); return -1; } /* copy the extension data */ nim_dest->num_ext = 0; for( c = 0; c < nim_src->num_ext; c++ ){ size = old_size = nim_src->ext_list[c].esize; if( size & 0xf ) size = (size + 0xf) & ~0xf; /* make multiple of 16 */ if( g_opts.debug > 2 ) fprintf(stderr,"+d dup'ing ext #%d of size %d (from size %d)\n", c, size, old_size); /* data length is size-8, as esize includes space for esize and ecode */ data = (char *)calloc(size-8,sizeof(char)); /* maybe size > old */ if( !data ){ fprintf(stderr,"** failed to alloc %d bytes for extention\n", size); if( c == 0 ) { free(nim_dest->ext_list); nim_dest->ext_list = NULL; } /* otherwise, keep what we have (a.o.t. deleting them all) */ return -1; } /* finally, fill the new structure */ nim_dest->ext_list[c].esize = size; nim_dest->ext_list[c].ecode = nim_src->ext_list[c].ecode; nim_dest->ext_list[c].edata = data; memcpy(data, nim_src->ext_list[c].edata, old_size-8); nim_dest->num_ext++; } return 0; } /*----------------------------------------------------------------------*/ /*! compute the total size of all extensions \return the total of all esize fields Note that each esize includes 4 bytes for ecode, 4 bytes for esize, and the bytes used for the data. Each esize also needs to be a multiple of 16, so it may be greater than the sum of its 3 parts. *//*--------------------------------------------------------------------*/ int nifti_extension_size(nifti_image *nim) { int c, size = 0; if( !nim || nim->num_ext <= 0 ) return 0; if( g_opts.debug > 2 ) fprintf(stderr,"-d ext sizes:"); for ( c = 0; c < nim->num_ext; c++ ){ size += nim->ext_list[c].esize; if( g_opts.debug > 2 ) fprintf(stderr," %d",nim->ext_list[c].esize); } if( g_opts.debug > 2 ) fprintf(stderr," (total = %d)\n",size); return size; } /*----------------------------------------------------------------------*/ /*! set the nifti_image iname_offset field, based on nifti_type - if writing to 2 files, set offset to 0 - if writing to a single NIFTI-1 file, set the offset to 352 + total extension size, then align to 16-byte boundary - if writing an ASCII header, set offset to -1 *//*--------------------------------------------------------------------*/ void nifti_set_iname_offset(nifti_image *nim) { int offset; switch( nim->nifti_type ){ default: /* writing into 2 files */ /* we only write files with 0 offset in the 2 file format */ nim->iname_offset = 0 ; break ; /* NIFTI-1 single binary file - always update */ case NIFTI_FTYPE_NIFTI1_1: offset = nifti_extension_size(nim)+sizeof(struct nifti_1_header)+4; /* be sure offset is aligned to a 16 byte boundary */ if ( ( offset % 16 ) != 0 ) offset = ((offset + 0xf) & ~0xf); if( nim->iname_offset != offset ){ if( g_opts.debug > 1 ) fprintf(stderr,"+d changing offset from %d to %d\n", nim->iname_offset, offset); nim->iname_offset = offset; } break ; /* non-standard case: NIFTI-1 ASCII header + binary data (single file) */ case NIFTI_FTYPE_ASCII: nim->iname_offset = -1 ; /* compute offset from filesize */ break ; } } /*----------------------------------------------------------------------*/ /*! write the nifti_image dataset to disk, optionally including data This is just a front-end for nifti_image_write_hdr_img2. \param nim nifti_image to write to disk \param write_data write options (see nifti_image_write_hdr_img2) \param opts file open options ("wb" from nifti_image_write) \sa nifti_image_write, nifti_image_write_hdr_img2, nifti_image_free, nifti_set_filenames *//*--------------------------------------------------------------------*/ znzFile nifti_image_write_hdr_img( nifti_image *nim , int write_data , const char* opts ) { return nifti_image_write_hdr_img2(nim,write_data,opts,NULL,NULL); } #undef ERREX #define ERREX(msg) \ do{ fprintf(stderr,"** ERROR: nifti_image_write_hdr_img: %s\n",(msg)) ; \ return fp ; } while(0) /* ----------------------------------------------------------------------*/ /*! This writes the header (and optionally the image data) to file * * If the image data file is left open it returns a valid znzFile handle. * It also uses imgfile as the open image file is not null, and modifies * it inside. * * \param nim nifti_image to write to disk * \param write_opts flags whether to write data and/or close file (see below) * \param opts file-open options, probably "wb" from nifti_image_write() * \param imgfile optional open znzFile struct, for writing image data (may be NULL) * \param NBL optional nifti_brick_list, containing the image data (may be NULL) * * Values for write_opts mode are based on two binary flags * ( 0/1 for no-write/write data, and 0/2 for close/leave-open files ) : * - 0 = do not write data and close (do not open data file) * - 1 = write data and close * - 2 = do not write data and leave data file open * - 3 = write data and leave data file open * * \sa nifti_image_write, nifti_image_write_hdr_img, nifti_image_free, * nifti_set_filenames *//*---------------------------------------------------------------------*/ znzFile nifti_image_write_hdr_img2(nifti_image *nim, int write_opts, const char * opts, znzFile imgfile, const nifti_brick_list * NBL) { struct nifti_1_header nhdr ; znzFile fp=NULL; size_t ss ; int write_data, leave_open; char func[] = { "nifti_image_write_hdr_img2" }; write_data = write_opts & 1; /* just separate the bits now */ leave_open = write_opts & 2; if( ! nim ) ERREX("NULL input") ; if( ! nifti_validfilename(nim->fname) ) ERREX("bad fname input") ; if( write_data && ! nim->data && ! NBL ) ERREX("no image data") ; if( write_data && NBL && ! nifti_NBL_matches_nim(nim, NBL) ) ERREX("NBL does not match nim"); nifti_set_iname_offset(nim); if( g_opts.debug > 1 ){ fprintf(stderr,"-d writing nifti file '%s'...\n", nim->fname); if( g_opts.debug > 2 ) fprintf(stderr,"-d nifti type %d, offset %d\n", nim->nifti_type, nim->iname_offset); } if( nim->nifti_type == NIFTI_FTYPE_ASCII ) /* non-standard case */ return nifti_write_ascii_image(nim,NBL,opts,write_data,leave_open); nhdr = nifti_convert_nim2nhdr(nim); /* create the nifti1_header struct */ /* if writing to 2 files, make sure iname is set and different from fname */ if( nim->nifti_type != NIFTI_FTYPE_NIFTI1_1 ){ if( nim->iname && strcmp(nim->iname,nim->fname) == 0 ){ free(nim->iname) ; nim->iname = NULL ; } if( nim->iname == NULL ){ /* then make a new one */ nim->iname = nifti_makeimgname(nim->fname,nim->nifti_type,0,0); if( nim->iname == NULL ) return NULL; } } /* if we have an imgfile and will write the header there, use it */ if( ! znz_isnull(imgfile) && nim->nifti_type == NIFTI_FTYPE_NIFTI1_1 ){ if( g_opts.debug > 2 ) fprintf(stderr,"+d using passed file for hdr\n"); fp = imgfile; } else { if( g_opts.debug > 2 ) fprintf(stderr,"+d opening output file %s [%s]\n",nim->fname,opts); fp = znzopen( nim->fname , opts , nifti_is_gzfile(nim->fname) ) ; if( znz_isnull(fp) ){ LNI_FERR(func,"cannot open output file",nim->fname); return fp; } } /* write the header and extensions */ ss = znzwrite(&nhdr , 1 , sizeof(nhdr) , fp); /* write header */ if( ss < sizeof(nhdr) ){ LNI_FERR(func,"bad header write to output file",nim->fname); znzclose(fp); return fp; } /* partial file exists, and errors have been printed, so ignore return */ if( nim->nifti_type != NIFTI_FTYPE_ANALYZE ) (void)nifti_write_extensions(fp,nim); /* if the header is all we want, we are done */ if( ! write_data && ! leave_open ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d header is all we want: done\n"); znzclose(fp); return(fp); } if( nim->nifti_type != NIFTI_FTYPE_NIFTI1_1 ){ /* get a new file pointer */ znzclose(fp); /* first, close header file */ if( ! znz_isnull(imgfile) ){ if(g_opts.debug > 2) fprintf(stderr,"+d using passed file for img\n"); fp = imgfile; } else { if( g_opts.debug > 2 ) fprintf(stderr,"+d opening img file '%s'\n", nim->iname); fp = znzopen( nim->iname , opts , nifti_is_gzfile(nim->iname) ) ; if( znz_isnull(fp) ) ERREX("cannot open image file") ; } } znzseek(fp, nim->iname_offset, SEEK_SET); /* in any case, seek to offset */ if( write_data ) nifti_write_all_data(fp,nim,NBL); if( ! leave_open ) znzclose(fp); return fp; } /*----------------------------------------------------------------------*/ /*! write a nifti_image to disk in ASCII format *//*--------------------------------------------------------------------*/ znzFile nifti_write_ascii_image(nifti_image *nim, const nifti_brick_list * NBL, const char *opts, int write_data, int leave_open) { znzFile fp; char * hstr; hstr = nifti_image_to_ascii( nim ) ; /* get header in ASCII form */ if( ! hstr ){ fprintf(stderr,"** failed image_to_ascii()\n"); return NULL; } fp = znzopen( nim->fname , opts , nifti_is_gzfile(nim->fname) ) ; if( znz_isnull(fp) ){ free(hstr); fprintf(stderr,"** failed to open '%s' for ascii write\n",nim->fname); return fp; } znzputs(hstr,fp); /* header */ nifti_write_extensions(fp,nim); /* extensions */ if ( write_data ) { nifti_write_all_data(fp,nim,NBL); } /* data */ if ( ! leave_open ) { znzclose(fp); } free(hstr); return fp; /* returned but may be closed */ } /*--------------------------------------------------------------------------*/ /*! Write a nifti_image to disk. Since data is properly byte-swapped upon reading, it is assumed to be in the byte-order of the current CPU at write time. Thus, nim->byte_order should match that of the current CPU. Note that the nifti_set_filenames() function takes the flag, set_byte_order. The following fields of nim affect how the output appears: - nifti_type = 0 ==> ANALYZE-7.5 format file pair will be written - nifti_type = 1 ==> NIFTI-1 format single file will be written (data offset will be 352+extensions) - nifti_type = 2 ==> NIFTI_1 format file pair will be written - nifti_type = 3 ==> NIFTI_1 ASCII single file will be written - fname is the name of the output file (header or header+data) - if a file pair is being written, iname is the name of the data file - existing files WILL be overwritten with extreme prejudice - if qform_code > 0, the quatern_*, qoffset_*, and qfac fields determine the qform output, NOT the qto_xyz matrix; if you want to compute these fields from the qto_xyz matrix, you can use the utility function nifti_mat44_to_quatern() \sa nifti_image_write_bricks, nifti_image_free, nifti_set_filenames, nifti_image_write_hdr_img *//*------------------------------------------------------------------------*/ void nifti_image_write( nifti_image *nim ) { znzFile fp = nifti_image_write_hdr_img(nim,1,"wb"); if( fp ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d niw: done with znzFile\n"); free(fp); } if( g_opts.debug > 1 ) fprintf(stderr,"-d nifti_image_write: done\n"); } /*----------------------------------------------------------------------*/ /*! similar to nifti_image_write, but data is in NBL struct, not nim->data \sa nifti_image_write, nifti_image_free, nifti_set_filenames, nifti_free_NBL *//*--------------------------------------------------------------------*/ void nifti_image_write_bricks( nifti_image *nim, const nifti_brick_list * NBL ) { znzFile fp = nifti_image_write_hdr_img2(nim,1,"wb",NULL,NBL); if( fp ){ if( g_opts.debug > 2 ) fprintf(stderr,"-d niwb: done with znzFile\n"); free(fp); } if( g_opts.debug > 1 ) fprintf(stderr,"-d niwb: done writing bricks\n"); } /*----------------------------------------------------------------------*/ /*! copy the nifti_image structure, without data Duplicate the structure, including fname, iname and extensions. Leave the data pointer as NULL. *//*--------------------------------------------------------------------*/ nifti_image * nifti_copy_nim_info(const nifti_image * src) { nifti_image *dest; dest = (nifti_image *)calloc(1,sizeof(nifti_image)); if( !dest ){ fprintf(stderr,"** NCNI: failed to alloc nifti_image\n"); return NULL; } memcpy(dest, src, sizeof(nifti_image)); if( src->fname ) dest->fname = nifti_strdup(src->fname); if( src->iname ) dest->iname = nifti_strdup(src->iname); dest->num_ext = 0; dest->ext_list = NULL; /* errors will be printed in NCE(), continue in either case */ (void)nifti_copy_extensions(dest, src); dest->data = NULL; return dest; } /*------------------------------------------------------------------------*/ /* Un-escape a C string in place -- that is, convert XML escape sequences back into their characters. (This can be done in place since the replacement is always smaller than the input.) Escapes recognized are: - < -> < - > -> > - " -> " - ' -> ' - & -> & Also replace CR LF pair (Microsoft), or CR alone (Macintosh) with LF (Unix), per the XML standard. Return value is number of replacements made (if you care). --------------------------------------------------------------------------*/ #undef CR #undef LF #define CR 0x0D #define LF 0x0A static int unescape_string( char *str ) { int ii,jj , nn,ll ; if( str == NULL ) return 0 ; /* no string? */ ll = (int)strlen(str) ; if( ll == 0 ) return 0 ; /* scan for escapes: &something; */ for( ii=jj=nn=0 ; ii': lout += 4 ; break ; /* replace '<' with "<" */ case '"' : case '\'': lout += 6 ; break ; /* replace '"' with """ */ case CR: case LF: lout += 6 ; break ; /* replace CR with " " LF with " " */ default: lout++ ; break ; /* copy all other chars */ } } out = (char *)calloc(1,lout) ; /* allocate output string */ if( !out ){ fprintf(stderr,"** escapize_string: failed to alloc %d bytes\n",lout); return NULL; } out[0] = '\'' ; /* opening quote mark */ for( ii=0,jj=1 ; ii < lstr ; ii++ ){ switch( str[ii] ){ default: out[jj++] = str[ii] ; break ; /* normal characters */ case '&': memcpy(out+jj,"&",5) ; jj+=5 ; break ; case '<': memcpy(out+jj,"<",4) ; jj+=4 ; break ; case '>': memcpy(out+jj,">",4) ; jj+=4 ; break ; case '"' : memcpy(out+jj,""",6) ; jj+=6 ; break ; case '\'': memcpy(out+jj,"'",6) ; jj+=6 ; break ; case CR: memcpy(out+jj," ",6) ; jj+=6 ; break ; case LF: memcpy(out+jj," ",6) ; jj+=6 ; break ; } } out[jj++] = '\'' ; /* closing quote mark */ out[jj] = '\0' ; /* terminate the string */ return out ; } /*---------------------------------------------------------------------------*/ /*! Dump the information in a NIFTI image header to an XML-ish ASCII string that can later be converted back into a NIFTI header in nifti_image_from_ascii(). The resulting string can be free()-ed when you are done with it. *//*-------------------------------------------------------------------------*/ char *nifti_image_to_ascii( const nifti_image *nim ) { char *buf , *ebuf ; int nbuf ; if( nim == NULL ) return NULL ; /* stupid caller */ buf = (char *)calloc(1,65534); /* longer than needed, to be safe */ if( !buf ){ fprintf(stderr,"** NITA: failed to alloc %d bytes\n",65534); return NULL; } sprintf( buf , "nifti_type == NIFTI_FTYPE_NIFTI1_1) ? "NIFTI-1+" :(nim->nifti_type == NIFTI_FTYPE_NIFTI1_2) ? "NIFTI-1" :(nim->nifti_type == NIFTI_FTYPE_ASCII ) ? "NIFTI-1A" : "ANALYZE-7.5" ) ; /** Strings that we don't control (filenames, etc.) that might contain "weird" characters (like quotes) are "escaped": - A few special characters are replaced by XML-style escapes, using the function escapize_string(). - On input, function unescape_string() reverses this process. - The result is that the NIFTI ASCII-format header is XML-compliant. */ ebuf = escapize_string(nim->fname) ; sprintf( buf+strlen(buf) , " header_filename = %s\n",ebuf); free(ebuf); ebuf = escapize_string(nim->iname) ; sprintf( buf+strlen(buf) , " image_filename = %s\n", ebuf); free(ebuf); sprintf( buf+strlen(buf) , " image_offset = '%d'\n" , nim->iname_offset ); sprintf(buf + strlen(buf), " ndim = '%d'\n", nim->ndim); sprintf(buf + strlen(buf), " nx = '%d'\n", nim->nx); if (nim->ndim > 1) sprintf(buf + strlen(buf), " ny = '%d'\n", nim->ny); if (nim->ndim > 2) sprintf(buf + strlen(buf), " nz = '%d'\n", nim->nz); if (nim->ndim > 3) sprintf(buf + strlen(buf), " nt = '%d'\n", nim->nt); if (nim->ndim > 4) sprintf(buf + strlen(buf), " nu = '%d'\n", nim->nu); if (nim->ndim > 5) sprintf(buf + strlen(buf), " nv = '%d'\n", nim->nv); if (nim->ndim > 6) sprintf(buf + strlen(buf), " nw = '%d'\n", nim->nw); sprintf(buf + strlen(buf), " dx = '%g'\n", nim->dx); if (nim->ndim > 1) sprintf(buf + strlen(buf), " dy = '%g'\n", nim->dy); if (nim->ndim > 2) sprintf(buf + strlen(buf), " dz = '%g'\n", nim->dz); if (nim->ndim > 3) sprintf(buf + strlen(buf), " dt = '%g'\n", nim->dt); if (nim->ndim > 4) sprintf(buf + strlen(buf), " du = '%g'\n", nim->du); if (nim->ndim > 5) sprintf(buf + strlen(buf), " dv = '%g'\n", nim->dv); if (nim->ndim > 6) sprintf(buf + strlen(buf), " dw = '%g'\n", nim->dw); sprintf( buf+strlen(buf) , " datatype = '%d'\n" , nim->datatype ) ; sprintf( buf+strlen(buf) , " datatype_name = '%s'\n" , nifti_datatype_string(nim->datatype) ) ; sprintf( buf+strlen(buf) , " nvox = '%u'\n" , (unsigned)nim->nvox ) ; sprintf( buf+strlen(buf) , " nbyper = '%d'\n" , nim->nbyper ) ; sprintf( buf+strlen(buf) , " byteorder = '%s'\n" , (nim->byteorder==MSB_FIRST) ? "MSB_FIRST" : "LSB_FIRST" ) ; if( nim->cal_min < nim->cal_max ){ sprintf( buf+strlen(buf) , " cal_min = '%g'\n", nim->cal_min ) ; sprintf( buf+strlen(buf) , " cal_max = '%g'\n", nim->cal_max ) ; } if( nim->scl_slope != 0.0 ){ sprintf( buf+strlen(buf) , " scl_slope = '%g'\n" , nim->scl_slope ) ; sprintf( buf+strlen(buf) , " scl_inter = '%g'\n" , nim->scl_inter ) ; } if( nim->intent_code > 0 ){ sprintf( buf+strlen(buf) , " intent_code = '%d'\n", nim->intent_code ) ; sprintf( buf+strlen(buf) , " intent_code_name = '%s'\n" , nifti_intent_string(nim->intent_code) ) ; sprintf( buf+strlen(buf) , " intent_p1 = '%g'\n" , nim->intent_p1 ) ; sprintf( buf+strlen(buf) , " intent_p2 = '%g'\n" , nim->intent_p2 ) ; sprintf( buf+strlen(buf) , " intent_p3 = '%g'\n" , nim->intent_p3 ) ; if( nim->intent_name[0] != '\0' ){ ebuf = escapize_string(nim->intent_name) ; sprintf( buf+strlen(buf) , " intent_name = %s\n",ebuf) ; free(ebuf) ; } } if( nim->toffset != 0.0 ) sprintf( buf+strlen(buf) , " toffset = '%g'\n",nim->toffset ) ; if( nim->xyz_units > 0 ) sprintf( buf+strlen(buf) , " xyz_units = '%d'\n" " xyz_units_name = '%s'\n" , nim->xyz_units , nifti_units_string(nim->xyz_units) ) ; if( nim->time_units > 0 ) sprintf( buf+strlen(buf) , " time_units = '%d'\n" " time_units_name = '%s'\n" , nim->time_units , nifti_units_string(nim->time_units) ) ; if( nim->freq_dim > 0 ) sprintf( buf+strlen(buf) , " freq_dim = '%d'\n",nim->freq_dim ) ; if( nim->phase_dim > 0 ) sprintf( buf+strlen(buf) , " phase_dim = '%d'\n",nim->phase_dim ) ; if( nim->slice_dim > 0 ) sprintf( buf+strlen(buf) , " slice_dim = '%d'\n",nim->slice_dim ) ; if( nim->slice_code > 0 ) sprintf( buf+strlen(buf) , " slice_code = '%d'\n" " slice_code_name = '%s'\n" , nim->slice_code , nifti_slice_string(nim->slice_code) ) ; if( nim->slice_start >= 0 && nim->slice_end > nim->slice_start ) sprintf( buf+strlen(buf) , " slice_start = '%d'\n" " slice_end = '%d'\n" , nim->slice_start , nim->slice_end ) ; if( nim->slice_duration != 0.0 ) sprintf( buf+strlen(buf) , " slice_duration = '%g'\n", nim->slice_duration ) ; if( nim->descrip[0] != '\0' ){ ebuf = escapize_string(nim->descrip) ; sprintf( buf+strlen(buf) , " descrip = %s\n",ebuf) ; free(ebuf) ; } if( nim->aux_file[0] != '\0' ){ ebuf = escapize_string(nim->aux_file) ; sprintf( buf+strlen(buf) , " aux_file = %s\n",ebuf) ; free(ebuf) ; } if( nim->qform_code > 0 ){ int i,j,k ; sprintf( buf+strlen(buf) , " qform_code = '%d'\n" " qform_code_name = '%s'\n" " qto_xyz_matrix = '%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g'\n" , nim->qform_code , nifti_xform_string(nim->qform_code) , nim->qto_xyz.m[0][0] , nim->qto_xyz.m[0][1] , nim->qto_xyz.m[0][2] , nim->qto_xyz.m[0][3] , nim->qto_xyz.m[1][0] , nim->qto_xyz.m[1][1] , nim->qto_xyz.m[1][2] , nim->qto_xyz.m[1][3] , nim->qto_xyz.m[2][0] , nim->qto_xyz.m[2][1] , nim->qto_xyz.m[2][2] , nim->qto_xyz.m[2][3] , nim->qto_xyz.m[3][0] , nim->qto_xyz.m[3][1] , nim->qto_xyz.m[3][2] , nim->qto_xyz.m[3][3] ) ; sprintf( buf+strlen(buf) , " qto_ijk_matrix = '%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g'\n" , nim->qto_ijk.m[0][0] , nim->qto_ijk.m[0][1] , nim->qto_ijk.m[0][2] , nim->qto_ijk.m[0][3] , nim->qto_ijk.m[1][0] , nim->qto_ijk.m[1][1] , nim->qto_ijk.m[1][2] , nim->qto_ijk.m[1][3] , nim->qto_ijk.m[2][0] , nim->qto_ijk.m[2][1] , nim->qto_ijk.m[2][2] , nim->qto_ijk.m[2][3] , nim->qto_ijk.m[3][0] , nim->qto_ijk.m[3][1] , nim->qto_ijk.m[3][2] , nim->qto_ijk.m[3][3] ) ; sprintf( buf+strlen(buf) , " quatern_b = '%g'\n" " quatern_c = '%g'\n" " quatern_d = '%g'\n" " qoffset_x = '%g'\n" " qoffset_y = '%g'\n" " qoffset_z = '%g'\n" " qfac = '%g'\n" , nim->quatern_b , nim->quatern_c , nim->quatern_d , nim->qoffset_x , nim->qoffset_y , nim->qoffset_z , nim->qfac ) ; nifti_mat44_to_orientation( nim->qto_xyz , &i,&j,&k ) ; if( i > 0 && j > 0 && k > 0 ) sprintf( buf+strlen(buf) , " qform_i_orientation = '%s'\n" " qform_j_orientation = '%s'\n" " qform_k_orientation = '%s'\n" , nifti_orientation_string(i) , nifti_orientation_string(j) , nifti_orientation_string(k) ) ; } if( nim->sform_code > 0 ){ int i,j,k ; sprintf( buf+strlen(buf) , " sform_code = '%d'\n" " sform_code_name = '%s'\n" " sto_xyz_matrix = '%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g'\n" , nim->sform_code , nifti_xform_string(nim->sform_code) , nim->sto_xyz.m[0][0] , nim->sto_xyz.m[0][1] , nim->sto_xyz.m[0][2] , nim->sto_xyz.m[0][3] , nim->sto_xyz.m[1][0] , nim->sto_xyz.m[1][1] , nim->sto_xyz.m[1][2] , nim->sto_xyz.m[1][3] , nim->sto_xyz.m[2][0] , nim->sto_xyz.m[2][1] , nim->sto_xyz.m[2][2] , nim->sto_xyz.m[2][3] , nim->sto_xyz.m[3][0] , nim->sto_xyz.m[3][1] , nim->sto_xyz.m[3][2] , nim->sto_xyz.m[3][3] ) ; sprintf( buf+strlen(buf) , " sto_ijk matrix = '%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g'\n" , nim->sto_ijk.m[0][0] , nim->sto_ijk.m[0][1] , nim->sto_ijk.m[0][2] , nim->sto_ijk.m[0][3] , nim->sto_ijk.m[1][0] , nim->sto_ijk.m[1][1] , nim->sto_ijk.m[1][2] , nim->sto_ijk.m[1][3] , nim->sto_ijk.m[2][0] , nim->sto_ijk.m[2][1] , nim->sto_ijk.m[2][2] , nim->sto_ijk.m[2][3] , nim->sto_ijk.m[3][0] , nim->sto_ijk.m[3][1] , nim->sto_ijk.m[3][2] , nim->sto_ijk.m[3][3] ) ; nifti_mat44_to_orientation( nim->sto_xyz , &i,&j,&k ) ; if( i > 0 && j > 0 && k > 0 ) sprintf( buf+strlen(buf) , " sform_i_orientation = '%s'\n" " sform_j_orientation = '%s'\n" " sform_k_orientation = '%s'\n" , nifti_orientation_string(i) , nifti_orientation_string(j) , nifti_orientation_string(k) ) ; } sprintf( buf+strlen(buf) , " num_ext = '%d'\n", nim->num_ext ) ; sprintf( buf+strlen(buf) , "/>\n" ) ; /* XML-ish closer */ nbuf = (int)strlen(buf) ; buf = (char *)realloc((void *)buf, nbuf+1); /* cut back to proper length */ if( !buf ) fprintf(stderr,"** NITA: failed to realloc %d bytes\n",nbuf+1); return buf ; } /*---------------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/ /*! get the byte order for this CPU - LSB_FIRST means least significant byte, first (little endian) - MSB_FIRST means most significant byte, first (big endian) *//*--------------------------------------------------------------------*/ int nifti_short_order(void) /* determine this CPU's byte order */ { union { unsigned char bb[2] ; short ss ; } fred ; fred.bb[0] = 1 ; fred.bb[1] = 0 ; return (fred.ss == 1) ? LSB_FIRST : MSB_FIRST ; } /*---------------------------------------------------------------------------*/ #undef QQNUM #undef QNUM #undef QSTR /* macro to check lhs string against "n1"; if it matches, interpret rhs string as a number, and put it into nim->"n2" */ #define QQNUM(n1,n2,tt) if( strcmp(lhs,#n1)==0 ) nim->n2=(tt)strtod(rhs,NULL) /* same, but where "n1" == "n2" */ #define QNUM(nam,tt) QQNUM(nam,nam,tt) /* macro to check lhs string against "nam"; if it matches, put rhs string into nim->"nam" string, with max length = "ml" */ #define QSTR(nam,ml) if( strcmp(lhs,#nam) == 0 ) \ strncpy(nim->nam,rhs,ml), nim->nam[ml]='\0' /*---------------------------------------------------------------------------*/ /*! Take an XML-ish ASCII string and create a NIFTI image header to match. NULL is returned if enough information isn't present in the input string. - The image data can later be loaded with nifti_image_load(). - The struct returned here can be liberated with nifti_image_free(). - Not a lot of error checking is done here to make sure that the input values are reasonable! *//*-------------------------------------------------------------------------*/ nifti_image *nifti_image_from_ascii( const char *str, int * bytes_read ) { char lhs[1024] , rhs[1024] ; int ii , spos, nn ; nifti_image *nim ; /* will be output */ if( str == NULL || *str == '\0' ) return NULL ; /* bad input!? */ /* scan for opening string */ spos = 0 ; ii = sscanf( str+spos , "%1023s%n" , lhs , &nn ) ; spos += nn ; if( ii == 0 || strcmp(lhs,"nx = nim->ny = nim->nz = nim->nt = nim->nu = nim->nv = nim->nw = 1 ; nim->dx = nim->dy = nim->dz = nim->dt = nim->du = nim->dv = nim->dw = 0 ; nim->qfac = 1.0f ; nim->byteorder = nifti_short_order() ; /* starting at str[spos], scan for "equations" of the form lhs = 'rhs' and assign rhs values into the struct component named by lhs */ while(1){ while( isspace((int) str[spos]) ) spos++ ; /* skip whitespace */ if( str[spos] == '\0' ) break ; /* end of string? */ /* get lhs string */ ii = sscanf( str+spos , "%1023s%n" , lhs , &nn ) ; spos += nn ; if( ii == 0 || strcmp(lhs,"/>") == 0 ) break ; /* end of input? */ /* skip whitespace and the '=' marker */ while( isspace((int) str[spos]) || str[spos] == '=' ) spos++ ; if( str[spos] == '\0' ) break ; /* end of string? */ /* if next character is a quote ', copy everything up to next ' otherwise, copy everything up to next nonblank */ if( str[spos] == '\'' ){ ii = spos+1 ; while( str[ii] != '\0' && str[ii] != '\'' ) ii++ ; nn = ii-spos-1 ; if( nn > 1023 ) nn = 1023 ; memcpy(rhs,str+spos+1,nn) ; rhs[nn] = '\0' ; spos = (str[ii] == '\'') ? ii+1 : ii ; } else { ii = sscanf( str+spos , "%1023s%n" , rhs , &nn ) ; spos += nn ; if( ii == 0 ) break ; /* nothing found? */ } unescape_string(rhs) ; /* remove any XML escape sequences */ /* Now can do the assignment, based on lhs string. Start with special cases that don't fit the QNUM/QSTR macros. */ if( strcmp(lhs,"nifti_type") == 0 ){ if( strcmp(rhs,"ANALYZE-7.5") == 0 ) nim->nifti_type = NIFTI_FTYPE_ANALYZE ; else if( strcmp(rhs,"NIFTI-1+") == 0 ) nim->nifti_type = NIFTI_FTYPE_NIFTI1_1 ; else if( strcmp(rhs,"NIFTI-1") == 0 ) nim->nifti_type = NIFTI_FTYPE_NIFTI1_2 ; else if( strcmp(rhs,"NIFTI-1A") == 0 ) nim->nifti_type = NIFTI_FTYPE_ASCII ; } else if( strcmp(lhs,"header_filename") == 0 ){ nim->fname = nifti_strdup(rhs) ; } else if( strcmp(lhs,"image_filename") == 0 ){ nim->iname = nifti_strdup(rhs) ; } else if( strcmp(lhs,"sto_xyz_matrix") == 0 ){ sscanf( rhs , "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f" , &(nim->sto_xyz.m[0][0]) , &(nim->sto_xyz.m[0][1]) , &(nim->sto_xyz.m[0][2]) , &(nim->sto_xyz.m[0][3]) , &(nim->sto_xyz.m[1][0]) , &(nim->sto_xyz.m[1][1]) , &(nim->sto_xyz.m[1][2]) , &(nim->sto_xyz.m[1][3]) , &(nim->sto_xyz.m[2][0]) , &(nim->sto_xyz.m[2][1]) , &(nim->sto_xyz.m[2][2]) , &(nim->sto_xyz.m[2][3]) , &(nim->sto_xyz.m[3][0]) , &(nim->sto_xyz.m[3][1]) , &(nim->sto_xyz.m[3][2]) , &(nim->sto_xyz.m[3][3]) ) ; } else if( strcmp(lhs,"byteorder") == 0 ){ if( strcmp(rhs,"MSB_FIRST") == 0 ) nim->byteorder = MSB_FIRST ; if( strcmp(rhs,"LSB_FIRST") == 0 ) nim->byteorder = LSB_FIRST ; } else QQNUM(image_offset,iname_offset,int) ; else QNUM(datatype,short int) ; else QNUM(ndim,int) ; else QNUM(nx,int) ; else QNUM(ny,int) ; else QNUM(nz,int) ; else QNUM(nt,int) ; else QNUM(nu,int) ; else QNUM(nv,int) ; else QNUM(nw,int) ; else QNUM(dx,float) ; else QNUM(dy,float) ; else QNUM(dz,float) ; else QNUM(dt,float) ; else QNUM(du,float) ; else QNUM(dv,float) ; else QNUM(dw,float) ; else QNUM(cal_min,float) ; else QNUM(cal_max,float) ; else QNUM(scl_slope,float) ; else QNUM(scl_inter,float) ; else QNUM(intent_code,short) ; else QNUM(intent_p1,float) ; else QNUM(intent_p2,float) ; else QNUM(intent_p3,float) ; else QSTR(intent_name,15) ; else QNUM(toffset,float) ; else QNUM(xyz_units,int) ; else QNUM(time_units,int) ; else QSTR(descrip,79) ; else QSTR(aux_file,23) ; else QNUM(qform_code,int) ; else QNUM(quatern_b,float) ; else QNUM(quatern_c,float) ; else QNUM(quatern_d,float) ; else QNUM(qoffset_x,float) ; else QNUM(qoffset_y,float) ; else QNUM(qoffset_z,float) ; else QNUM(qfac,float) ; else QNUM(sform_code,int) ; else QNUM(freq_dim,int) ; else QNUM(phase_dim,int) ; else QNUM(slice_dim,int) ; else QNUM(slice_code,int) ; else QNUM(slice_start,int) ; else QNUM(slice_end,int) ; else QNUM(slice_duration,float) ; else QNUM(num_ext,int) ; } /* end of while loop */ if( bytes_read ) *bytes_read = spos+1; /* "process" last '\n' */ /* do miscellaneous checking and cleanup */ if( nim->ndim <= 0 ){ nifti_image_free(nim); return NULL; } /* bad! */ nifti_datatype_sizes( nim->datatype, &(nim->nbyper), &(nim->swapsize) ); if( nim->nbyper == 0 ){ nifti_image_free(nim); return NULL; } /* bad! */ nim->dim[0] = nim->ndim ; nim->dim[1] = nim->nx ; nim->pixdim[1] = nim->dx ; nim->dim[2] = nim->ny ; nim->pixdim[2] = nim->dy ; nim->dim[3] = nim->nz ; nim->pixdim[3] = nim->dz ; nim->dim[4] = nim->nt ; nim->pixdim[4] = nim->dt ; nim->dim[5] = nim->nu ; nim->pixdim[5] = nim->du ; nim->dim[6] = nim->nv ; nim->pixdim[6] = nim->dv ; nim->dim[7] = nim->nw ; nim->pixdim[7] = nim->dw ; nim->nvox = (size_t)nim->nx * nim->ny * nim->nz * nim->nt * nim->nu * nim->nv * nim->nw ; if( nim->qform_code > 0 ) nim->qto_xyz = nifti_quatern_to_mat44( nim->quatern_b, nim->quatern_c, nim->quatern_d, nim->qoffset_x, nim->qoffset_y, nim->qoffset_z, nim->dx , nim->dy , nim->dz , nim->qfac ) ; else nim->qto_xyz = nifti_quatern_to_mat44( 0.0f , 0.0f , 0.0f , 0.0f , 0.0f , 0.0f , nim->dx , nim->dy , nim->dz , 0.0f ) ; nim->qto_ijk = nifti_mat44_inverse( nim->qto_xyz ) ; if( nim->sform_code > 0 ) nim->sto_ijk = nifti_mat44_inverse( nim->sto_xyz ) ; return nim ; } /*---------------------------------------------------------------------------*/ /*! validate the nifti_image \return 1 if the structure seems valid, otherwise 0 \sa nifti_nim_has_valid_dims, nifti_hdr_looks_good *//*-------------------------------------------------------------------------*/ int nifti_nim_is_valid(nifti_image * nim, int complain) { int errs = 0; if( !nim ){ fprintf(stderr,"** is_valid_nim: nim is NULL\n"); return 0; } if( g_opts.debug > 2 ) fprintf(stderr,"-d nim_is_valid check...\n"); /**- check that dim[] matches the individual values ndim, nx, ny, ... */ if( ! nifti_nim_has_valid_dims(nim,complain) ){ if( !complain ) return 0; errs++; } /* might check nbyper, pixdim, q/sforms, swapsize, nifti_type, ... */ /**- be explicit in return of 0 or 1 */ if( errs > 0 ) return 0; else return 1; } /*---------------------------------------------------------------------------*/ /*! validate nifti dimensions \return 1 if valid, 0 if not \sa nifti_nim_is_valid, nifti_hdr_looks_good rely on dim[] as the master *//*-------------------------------------------------------------------------*/ int nifti_nim_has_valid_dims(nifti_image * nim, int complain) { size_t prod; int c, errs = 0; /**- start with dim[0]: failure here is considered terminal */ if( nim->dim[0] <= 0 || nim->dim[0] > 7 ){ errs++; if( complain ) fprintf(stderr,"** NVd: dim[0] (%d) out of range [1,7]\n",nim->dim[0]); return 0; } /**- check whether ndim equals dim[0] */ if( nim->ndim != nim->dim[0] ){ errs++; if( ! complain ) return 0; fprintf(stderr,"** NVd: ndim != dim[0] (%d,%d)\n",nim->ndim,nim->dim[0]); } /**- compare each dim[i] to the proper nx, ny, ... */ if( ( (nim->dim[0] >= 1) && (nim->dim[1] != nim->nx) ) || ( (nim->dim[0] >= 2) && (nim->dim[2] != nim->ny) ) || ( (nim->dim[0] >= 3) && (nim->dim[3] != nim->nz) ) || ( (nim->dim[0] >= 4) && (nim->dim[4] != nim->nt) ) || ( (nim->dim[0] >= 5) && (nim->dim[5] != nim->nu) ) || ( (nim->dim[0] >= 6) && (nim->dim[6] != nim->nv) ) || ( (nim->dim[0] >= 7) && (nim->dim[7] != nim->nw) ) ){ errs++; if( !complain ) return 0; fprintf(stderr,"** NVd mismatch: dims = %d,%d,%d,%d,%d,%d,%d\n" " nxyz... = %d,%d,%d,%d,%d,%d,%d\n", nim->dim[1], nim->dim[2], nim->dim[3], nim->dim[4], nim->dim[5], nim->dim[6], nim->dim[7], nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->nv, nim->nw ); } if( g_opts.debug > 2 ){ fprintf(stderr,"-d check dim[%d] =", nim->dim[0]); for( c = 0; c < 7; c++ ) fprintf(stderr," %d", nim->dim[c]); fputc('\n', stderr); } /**- check the dimensions, and that their product matches nvox */ prod = 1; for( c = 1; c <= nim->dim[0]; c++ ){ if( nim->dim[c] > 0) prod *= nim->dim[c]; else if( nim->dim[c] <= 0 ){ if( !complain ) return 0; fprintf(stderr,"** NVd: dim[%d] (=%d) <= 0\n",c, nim->dim[c]); errs++; } } if( prod != nim->nvox ){ if( ! complain ) return 0; fprintf(stderr,"** NVd: nvox does not match %d-dim product (%u, %u)\n", nim->dim[0], (unsigned)nim->nvox, (unsigned)prod); errs++; } /**- if debug, warn about any remaining dim that is neither 0, nor 1 */ /* (values in dims above dim[0] are undefined, as reminded by Cinly Ooi and Alle Meije Wink) 16 Nov 2005 [rickr] */ if( g_opts.debug > 1 ) for( c = nim->dim[0]+1; c <= 7; c++ ) if( nim->dim[c] != 0 && nim->dim[c] != 1 ) fprintf(stderr,"** NVd warning: dim[%d] = %d, but ndim = %d\n", c, nim->dim[c], nim->dim[0]); if( g_opts.debug > 2 ) fprintf(stderr,"-d nim_has_valid_dims check, errs = %d\n", errs); /**- return invalid or valid */ if( errs > 0 ) return 0; else return 1; } /*---------------------------------------------------------------------------*/ /*! read a nifti image, collapsed across dimensions according to dims[8]

    This function may be used to read parts of a nifti dataset, such as
    the time series for a single voxel, or perhaps a slice.  It is similar
    to nifti_image_load(), though the passed 'data' parameter is used for
    returning the image, not nim->data.

    \param nim  given nifti_image struct, corresponding to the data file
    \param dims given list of dimensions (see below)
    \param data pointer to data pointer (if *data is NULL, data will be
                allocated, otherwise not)

    Here, dims is an array of 8 ints, similar to nim->dim[8].  While dims[0]
    is unused at this point, the other indices specify which dimensions to
    collapse (and at which index), and which not to collapse.  If dims[i] is
    set to -1, then that entire dimension will be read in, from index 0 to
    index (nim->dim[i] - 1).  If dims[i] >= 0, then only that index will be
    read in (so dims[i] must also be < nim->dim[i]).

    Example: given  nim->dim[8] = { 4, 64, 64, 21, 80, 1, 1, 1 } (4-D dataset)

      if dims[8] = { 0,  5,  4, 17, -1, -1, -1, -1 }
         -> read time series for voxel i,j,k = 5,4,17

      if dims[8] = { 0, -1, -1, -1, 17, -1, -1, -1 }
         -> read single volume at time point 17

    Example: given  nim->dim[8] = { 6, 64, 64, 21, 80, 4, 3, 1 } (6-D dataset)

      if dims[8] = { 0, 5, 4, 17, -1, 2, 1, 0 }
         -> read time series for the voxel i,j,k = 5,4,17, and dim 5,6 = 2,1

      if dims[8] = { 0, 5, 4, -1, -1, 0, 0, 0 }
         -> read time series for slice at i,j = 5,4, and dim 5,6,7 = 0,0,0
            (note that dims[7] is not relevant, but must be 0 or -1)

    If *data is NULL, then *data will be set as a pointer to new memory,
    allocated here for the resulting collapsed image data.

      e.g. { int    dims[8] = { 0,  5,  4, 17, -1, -1, -1, -1 };
             void * data    = NULL;
             ret_val = nifti_read_collapsed_image(nim, dims, &data);
             if( ret_val > 0 ){
                process_time_series(data);
                if( data != NULL ) free(data);
             }
           }

    NOTE: If *data is not NULL, then it will be assumed that it points to
          valid memory, sufficient to hold the results.  This is done for
          speed and possibly repeated calls to this function.

      e.g. { int    dims[8] = { 0,  -1, -1, -1, -1, -1, -1, -1 };
             void * data    = NULL;
             for( zslice = 0; zslice < nzslices; zslice++ ){
                dims[3] = zslice;
                ret_val = nifti_read_collapsed_image(nim, dims, &data);
                if( ret_val > 0 ) process_slice(zslice, data);
             }
             if( data != NULL ) free(data);
           }

    \return
        -  the total number of bytes read, or < 0 on failure
        -  the read and byte-swapped data, in 'data'            
\sa nifti_image_read, nifti_image_free, nifti_image_read_bricks nifti_image_load *//*-------------------------------------------------------------------------*/ int nifti_read_collapsed_image( nifti_image * nim, const int dims [8], void ** data ) { znzFile fp; int pivots[8], prods[8], nprods; /* sizes are bounded by dims[], so 8 */ int c, bytes; /** - check pointers for sanity */ if( !nim || !dims || !data ){ fprintf(stderr,"** nifti_RCI: bad params %p, %p, %p\n", (void *)nim, (const void *)dims, (void *)data); return -1; } if( g_opts.debug > 2 ){ fprintf(stderr,"-d read_collapsed_image:\n dims ="); for(c = 0; c < 8; c++) fprintf(stderr," %3d", dims[c]); fprintf(stderr,"\n nim->dims ="); for(c = 0; c < 8; c++) fprintf(stderr," %3d", nim->dim[c]); fputc('\n', stderr); } /** - verify that dim[] makes sense */ if( ! nifti_nim_is_valid(nim, g_opts.debug > 0) ){ fprintf(stderr,"** invalid nim (file is '%s')\n", nim->fname ); return -1; } /** - verify that dims[] makes sense for this dataset */ for( c = 1; c <= nim->dim[0]; c++ ){ if( dims[c] >= nim->dim[c] ){ fprintf(stderr,"** nifti_RCI: dims[%d] >= nim->dim[%d] (%d,%d)\n", c, c, dims[c], nim->dim[c]); return -1; } } /** - prepare pivot list - pivots are fixed indices */ if( make_pivot_list(nim, dims, pivots, prods, &nprods) < 0 ) return -1; bytes = rci_alloc_mem(data, prods, nprods, nim->nbyper); if( bytes < 0 ) return -1; /** - open the image file for reading at the appropriate offset */ fp = nifti_image_load_prep( nim ); if( ! fp ){ free(*data); *data = NULL; return -1; } /* failure */ /** - call the recursive reading function, passing nim, the pivot info, location to store memory, and file pointer and position */ c = rci_read_data(nim, pivots,prods,nprods,dims, (char *)*data, fp, znztell(fp)); znzclose(fp); /* in any case, close the file */ if( c < 0 ){ free(*data); *data = NULL; return -1; } /* failure */ if( g_opts.debug > 1 ) fprintf(stderr,"+d read %d bytes of collapsed image from %s\n", bytes, nim->fname); return bytes; } /* local function to find strides per dimension. assumes 7D size and ** stride array. */ static void compute_strides(int *strides,const int *size,int nbyper) { int i; strides[0] = nbyper; for(i = 1; i < 7; i++) { strides[i] = size[i-1] * strides[i-1]; } } /*---------------------------------------------------------------------------*/ /*! read an arbitrary subregion from a nifti image This function may be used to read a single arbitary subregion of any rectangular size from a nifti dataset, such as a small 5x5x5 subregion around the center of a 3D image. \param nim given nifti_image struct, corresponding to the data file \param start_index the index location of the first voxel that will be returned \param region_size the size of the subregion to be returned \param data pointer to data pointer (if *data is NULL, data will be allocated, otherwise not) Example: given nim->dim[8] = {3, 64, 64, 64, 1, 1, 1, 1 } (3-D dataset) if start_index[7] = { 29, 29, 29, 0, 0, 0, 0 } and region_size[7] = { 5, 5, 5, 1, 1, 1, 1 } -> read 5x5x5 region starting with the first voxel location at (29,29,29) NOTE: If *data is not NULL, then it will be assumed that it points to valid memory, sufficient to hold the results. This is done for speed and possibly repeated calls to this function. \return - the total number of bytes read, or < 0 on failure - the read and byte-swapped data, in 'data' \sa nifti_image_read, nifti_image_free, nifti_image_read_bricks nifti_image_load, nifti_read_collapsed_image *//*-------------------------------------------------------------------------*/ int nifti_read_subregion_image( nifti_image * nim, const int *start_index, const int *region_size, void ** data ) { znzFile fp; /* file to read */ int i,j,k,l,m,n; /* indices for dims */ long int bytes = 0; /* total # bytes read */ int total_alloc_size; /* size of buffer allocation */ char *readptr; /* where in *data to read next */ int strides[7]; /* strides between dimensions */ int collapsed_dims[8]; /* for read_collapsed_image */ int *image_size; /* pointer to dimensions in header */ long int initial_offset; long int offset; /* seek offset for reading current row */ /* probably ignored, but set to ndim for consistency*/ collapsed_dims[0] = nim->ndim; /* build a dims array for collapsed image read */ for(i = 0; i < nim->ndim; i++) { /* if you take the whole extent in this dimension */ if(start_index[i] == 0 && region_size[i] == nim->dim[i+1]) { collapsed_dims[i+1] = -1; } /* if you specify a single element in this dimension */ else if(region_size[i] == 1) { collapsed_dims[i+1] = start_index[i]; } else { collapsed_dims[i+1] = -2; /* sentinel value */ } } /* fill out end of collapsed_dims */ for(i = nim->ndim ; i < 7; i++) { collapsed_dims[i+1] = -1; } /* check to see whether collapsed read is possible */ for(i = 1; i <= nim->ndim; i++) { if(collapsed_dims[i] == -2) { break; } } /* if you get through all the dimensions without hitting ** a subrange of size > 1, a collapsed read is possible */ if(i > nim->ndim) { return nifti_read_collapsed_image(nim, collapsed_dims, data); } /* point past first element of dim, which holds nim->ndim */ image_size = &(nim->dim[1]); /* check region sizes for sanity */ for(i = 0; i < nim->ndim; i++) { if(start_index[i] + region_size[i] > image_size[i]) { if(g_opts.debug > 1) { fprintf(stderr,"region doesn't fit within image size\n"); } return -1; } } /* get the file open */ fp = nifti_image_load_prep( nim ); /* the current offset is just past the nifti header, save * location so that SEEK_SET can be used below */ initial_offset = znztell(fp); /* get strides*/ compute_strides(strides,image_size,nim->nbyper); total_alloc_size = nim->nbyper; /* size of pixel */ /* find alloc size */ for(i = 0; i < nim->ndim; i++) { total_alloc_size *= region_size[i]; } /* allocate buffer, if necessary */ if(*data == 0) { *data = (void *)malloc(total_alloc_size); } if(*data == 0) { if(g_opts.debug > 1) { fprintf(stderr,"allocation of %d bytes failed\n",total_alloc_size); return -1; } } /* point to start of data buffer as char * */ readptr = *((char **)data); { /* can't assume that start_index and region_size have any more than ** nim->ndim elements so make local copies, filled out to seven elements */ int si[7], rs[7]; for(i = 0; i < nim->ndim; i++) { si[i] = start_index[i]; rs[i] = region_size[i]; } for(i = nim->ndim; i < 7; i++) { si[i] = 0; rs[i] = 1; } /* loop through subregion and read a row at a time */ for(i = si[6]; i < (si[6] + rs[6]); i++) { for(j = si[5]; j < (si[5] + rs[5]); j++) { for(k = si[4]; k < (si[4] + rs[4]); k++) { for(l = si[3]; l < (si[3] + rs[3]); l++) { for(m = si[2]; m < (si[2] + rs[2]); m++) { for(n = si[1]; n < (si[1] + rs[1]); n++) { int nread,read_amount; offset = initial_offset + (i * strides[6]) + (j * strides[5]) + (k * strides[4]) + (l * strides[3]) + (m * strides[2]) + (n * strides[1]) + (si[0] * strides[0]); znzseek(fp, offset, SEEK_SET); /* seek to current row */ read_amount = rs[0] * nim->nbyper; /* read a row of the subregion*/ nread = (int)nifti_read_buffer(fp, readptr, read_amount, nim); if(nread != read_amount) { if(g_opts.debug > 1) { fprintf(stderr,"read of %d bytes failed\n",read_amount); return -1; } } bytes += nread; readptr += read_amount; } } } } } } } return bytes; } /* read the data from the file pointed to by fp - this a recursive function, so start with the base case - data is now (char *) for easy incrementing return 0 on success, < 0 on failure */ static int rci_read_data(nifti_image * nim, int * pivots, int * prods, int nprods, const int dims[], char * data, znzFile fp, size_t base_offset) { size_t sublen, offset, read_size; int c; /* bad check first - base_offset may not have been checked */ if( nprods <= 0 ){ fprintf(stderr,"** rci_read_data, bad prods, %d\n", nprods); return -1; } /* base case: actually read the data */ if( nprods == 1 ){ size_t nread, bytes; /* make sure things look good here */ if( *pivots != 0 ){ fprintf(stderr,"** rciRD: final pivot == %d!\n", *pivots); return -1; } /* so just seek and read (prods[0] * nbyper) bytes from the file */ znzseek(fp, (long)base_offset, SEEK_SET); bytes = (size_t)prods[0] * nim->nbyper; nread = nifti_read_buffer(fp, data, bytes, nim); if( nread != bytes ){ fprintf(stderr,"** rciRD: read only %u of %u bytes from '%s'\n", (unsigned)nread, (unsigned)bytes, nim->fname); return -1; } else if( g_opts.debug > 3 ) fprintf(stderr,"+d successful read of %u bytes at offset %u\n", (unsigned)bytes, (unsigned)base_offset); return 0; /* done with base case - return success */ } /* not the base case, so do a set of reduced reads */ /* compute size of sub-brick: all dimensions below pivot */ for( c = 1, sublen = 1; c < *pivots; c++ ) sublen *= nim->dim[c]; /* compute number of values to read, i.e. remaining prods */ for( c = 1, read_size = 1; c < nprods; c++ ) read_size *= prods[c]; read_size *= nim->nbyper; /* and multiply by bytes per voxel */ /* now repeatedly compute offsets, and recursively read */ for( c = 0; c < prods[0]; c++ ){ /* offset is (c * sub-block size (including pivot dim)) */ /* + (dims[] index into pivot sub-block) */ /* the unneeded multiplication is to make this more clear */ offset = (size_t)c * sublen * nim->dim[*pivots] + (size_t)sublen * dims[*pivots]; offset *= nim->nbyper; if( g_opts.debug > 3 ) fprintf(stderr,"-d reading %u bytes, foff %u + %u, doff %u\n", (unsigned)read_size, (unsigned)base_offset, (unsigned)offset, (unsigned)(c*read_size)); /* now read the next level down, adding this offset */ if( rci_read_data(nim, pivots+1, prods+1, nprods-1, dims, data + c * read_size, fp, base_offset + offset) < 0 ) return -1; } return 0; } /* allocate memory for all collapsed image data If *data is already set, do not allocate, but still calculate size for debug report. return total size on success, and < 0 on failure */ static int rci_alloc_mem(void ** data, const int prods[8], int nprods, int nbyper ) { int size, memindex; if( nbyper < 0 || nprods < 1 || nprods > 8 ){ fprintf(stderr,"** rci_am: bad params, %d, %d\n", nbyper, nprods); return -1; } for( memindex = 0, size = 1; memindex < nprods; memindex++ ) size *= prods[memindex]; size *= nbyper; if( ! *data ){ /* then allocate what is needed */ if( g_opts.debug > 1 ) fprintf(stderr,"+d alloc %d (= %d x %d) bytes for collapsed image\n", size, size/nbyper, nbyper); *data = malloc(size); /* actually allocate the memory */ if( ! *data ){ fprintf(stderr,"** rci_am: failed to alloc %d bytes for data\n", size); return -1; } } else if( g_opts.debug > 1 ) fprintf(stderr,"-d rci_am: *data already set, need %d (%d x %d) bytes\n", size, size/nbyper, nbyper); return size; } /* prepare a pivot list for reading The pivot points are the indices into dims where the calling function wants to collapse a dimension. The last pivot should always be zero (note that we have space for that in the lists). */ static int make_pivot_list(nifti_image * nim, const int dims[], int pivots[], int prods[], int * nprods ) { int len, dim_index; len = 0; dim_index = nim->dim[0]; while( dim_index > 0 ){ prods[len] = 1; while( dim_index > 0 && (nim->dim[dim_index] == 1 || dims[dim_index] == -1) ){ prods[len] *= nim->dim[dim_index]; dim_index--; } pivots[len] = dim_index; len++; dim_index--; /* fine, let it drop out at -1 */ } /* make sure to include 0 as a pivot (instead of just 1, if it is) */ /* (check len, though we have already validated nifti_image) */ if( len > 0 && pivots[len-1] != 0 ){ pivots[len] = 0; prods[len] = 1; len++; } *nprods = len; if( g_opts.debug > 2 ){ fprintf(stderr,"+d pivot list created, pivots :"); for(dim_index = 0; dim_index < len; dim_index++) fprintf(stderr," %d", pivots[dim_index]); fprintf(stderr,", prods :"); for(dim_index = 0; dim_index < len; dim_index++) fprintf(stderr," %d", prods[dim_index]); fputc('\n',stderr); } return 0; } #undef ISEND #define ISEND(c) ( (c)==']' || (c)=='}' || (c)=='\0' ) /*---------------------------------------------------------------------*/ /*! Get an integer list in the range 0..(nvals-1), from the character string str. If we call the output pointer fred, then fred[0] = number of integers in the list (> 0), and fred[i] = i-th integer in the list for i=1..fred[0]. If on return, fred == NULL or fred[0] == 0, then something is wrong, and the caller must deal with that. Syntax of input string: - initial '{' or '[' is skipped, if present - ends when '}' or ']' or end of string is found - contains entries separated by commas - entries have one of these forms: - a single number - a dollar sign '$', which means nvals-1 - a sequence of consecutive numbers in the form "a..b" or "a-b", where "a" and "b" are single numbers (or '$') - a sequence of evenly spaced numbers in the form "a..b(c)" or "a-b(c)", where "c" encodes the step - Example: "[2,7..4,3..9(2)]" decodes to the list 2 7 6 5 4 3 5 7 9 - entries should be in the range 0..nvals-1 (borrowed, with permission, from thd_intlist.c) *//*-------------------------------------------------------------------*/ int * nifti_get_intlist( int nvals , const char * str ) { int *subv = NULL ; int *subv_realloc = NULL; int ii , ipos , nout , slen ; int ibot,itop,istep , nused ; char *cpt ; /* Meaningless input? */ if( nvals < 1 ) return NULL ; /* No selection list? */ if( str == NULL || str[0] == '\0' ) return NULL ; /* skip initial '[' or '{' */ subv = (int *)malloc( sizeof(int) * 2 ) ; if( !subv ) { fprintf(stderr,"** nifti_get_intlist: failed alloc of 2 ints\n"); return NULL; } subv[0] = nout = 0 ; ipos = 0 ; if( str[ipos] == '[' || str[ipos] == '{' ) ipos++ ; if( g_opts.debug > 1 ) fprintf(stderr,"-d making int_list (vals = %d) from '%s'\n", nvals, str); /**- for each sub-selector until end of input... */ slen = (int)strlen(str) ; while( ipos < slen && !ISEND(str[ipos]) ){ while( isspace((int) str[ipos]) ) ipos++ ; /* skip blanks */ if( ISEND(str[ipos]) ) break ; /* done */ /**- get starting value */ if( str[ipos] == '$' ){ /* special case */ ibot = nvals-1 ; ipos++ ; } else { /* decode an integer */ ibot = strtol( str+ipos , &cpt , 10 ) ; if( ibot < 0 ){ fprintf(stderr,"** ERROR: list index %d is out of range 0..%d\n", ibot,nvals-1) ; free(subv) ; return NULL ; } if( ibot >= nvals ){ fprintf(stderr,"** ERROR: list index %d is out of range 0..%d\n", ibot,nvals-1) ; free(subv) ; return NULL ; } nused = (cpt-(str+ipos)) ; if( ibot == 0 && nused == 0 ){ fprintf(stderr,"** ERROR: list syntax error '%s'\n",str+ipos) ; free(subv) ; return NULL ; } ipos += nused ; } while( isspace((int) str[ipos]) ) ipos++ ; /* skip blanks */ /**- if that's it for this sub-selector, add one value to list */ if( str[ipos] == ',' || ISEND(str[ipos]) ){ nout++ ; subv_realloc = (int *)realloc( (char *)subv , sizeof(int) * (nout+1) ) ; if( !subv_realloc ) { free(subv); fprintf(stderr,"** nifti_get_intlist: failed realloc of %d ints\n", nout+1); return NULL; } subv=subv_realloc; subv[0] = nout ; subv[nout] = ibot ; if( ISEND(str[ipos]) ) break ; /* done */ ipos++ ; continue ; /* re-start loop at next sub-selector */ } /**- otherwise, must have '..' or '-' as next inputs */ if( str[ipos] == '-' ){ ipos++ ; } else if( str[ipos] == '.' && str[ipos+1] == '.' ){ ipos++ ; ipos++ ; } else { fprintf(stderr,"** ERROR: index list syntax is bad: '%s'\n", str+ipos) ; free(subv) ; return NULL ; } /**- get ending value for loop now */ if( str[ipos] == '$' ){ /* special case */ itop = nvals-1 ; ipos++ ; } else { /* decode an integer */ itop = strtol( str+ipos , &cpt , 10 ) ; if( itop < 0 ){ fprintf(stderr,"** ERROR: index %d is out of range 0..%d\n", itop,nvals-1) ; free(subv) ; return NULL ; } if( itop >= nvals ){ fprintf(stderr,"** ERROR: index %d is out of range 0..%d\n", itop,nvals-1) ; free(subv) ; return NULL ; } nused = (cpt-(str+ipos)) ; if( itop == 0 && nused == 0 ){ fprintf(stderr,"** ERROR: index list syntax error '%s'\n",str+ipos) ; free(subv) ; return NULL ; } ipos += nused ; } /**- set default loop step */ istep = (ibot <= itop) ? 1 : -1 ; while( isspace((int) str[ipos]) ) ipos++ ; /* skip blanks */ /**- check if we have a non-default loop step */ if( str[ipos] == '(' ){ /* decode an integer */ ipos++ ; istep = strtol( str+ipos , &cpt , 10 ) ; if( istep == 0 ){ fprintf(stderr,"** ERROR: index loop step is 0!\n") ; free(subv) ; return NULL ; } nused = (cpt-(str+ipos)) ; ipos += nused ; if( str[ipos] == ')' ) ipos++ ; if( (ibot-itop)*istep > 0 ){ fprintf(stderr,"** WARNING: index list '%d..%d(%d)' means nothing\n", ibot,itop,istep ) ; } } /**- add values to output */ for( ii=ibot ; (ii-itop)*istep <= 0 ; ii += istep ){ nout++ ; subv_realloc = (int *)realloc( (char *)subv , sizeof(int) * (nout+1) ) ; if( !subv_realloc ) { free(subv); fprintf(stderr,"** nifti_get_intlist: failed realloc of %d ints\n", nout+1); return NULL; } subv=subv_realloc; subv[0] = nout ; subv[nout] = ii ; } /**- check if we have a comma to skip over */ while( isspace((int) str[ipos]) ) ipos++ ; /* skip blanks */ if( str[ipos] == ',' ) ipos++ ; /* skip commas */ } /* end of loop through selector string */ if( g_opts.debug > 1 ) { fprintf(stderr,"+d int_list (vals = %d): ", subv[0]); for( ii = 1; ii <= subv[0]; ii++ ) fprintf(stderr,"%d ", subv[ii]); fputc('\n',stderr); } if( subv[0] == 0 ){ free(subv); subv = NULL; } return subv ; } /*---------------------------------------------------------------------*/ /*! Given a NIFTI_TYPE string, such as "NIFTI_TYPE_INT16", return the * corresponding integral type code. The type code is the macro * value defined in nifti1.h. *//*-------------------------------------------------------------------*/ int nifti_datatype_from_string( const char * name ) { int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int c; if( !name ) return DT_UNKNOWN; for( c = tablen-1; c > 0; c-- ) if( !strcmp(name, nifti_type_list[c].name) ) break; return nifti_type_list[c].type; } /*---------------------------------------------------------------------*/ /*! Given a NIFTI_TYPE value, such as NIFTI_TYPE_INT16, return the * corresponding macro label as a string. The dtype code is the * macro value defined in nifti1.h. *//*-------------------------------------------------------------------*/ const char * nifti_datatype_to_string( int dtype ) { int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int c; for( c = tablen-1; c > 0; c-- ) if( nifti_type_list[c].type == dtype ) break; return nifti_type_list[c].name; } /*---------------------------------------------------------------------*/ /*! Determine whether dtype is a valid NIFTI_TYPE. * * DT_UNKNOWN is considered invalid * * The only difference 'for_nifti' makes is that DT_BINARY * should be invalid for a NIfTI dataset. *//*-------------------------------------------------------------------*/ int nifti_datatype_is_valid( int dtype, int for_nifti ) { int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int c; /* special case */ if( for_nifti && dtype == DT_BINARY ) return 0; for( c = tablen-1; c > 0; c-- ) if( nifti_type_list[c].type == dtype ) return 1; return 0; } /*---------------------------------------------------------------------*/ /*! Only as a test, verify that the new nifti_type_list table matches * the the usage of nifti_datatype_sizes (which could be changed to * use the table, if there were interest). * * return the number of errors (so 0 is success, as usual) *//*-------------------------------------------------------------------*/ int nifti_test_datatype_sizes(int verb) { int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int nbyper, ssize; int c, errs = 0; for( c = 0; c < tablen; c++ ) { nbyper = ssize = -1; nifti_datatype_sizes(nifti_type_list[c].type, &nbyper, &ssize); if( nbyper < 0 || ssize < 0 || nbyper != nifti_type_list[c].nbyper || ssize != nifti_type_list[c].swapsize ) { if( verb || g_opts.debug > 2 ) fprintf(stderr, "** type mismatch: %s, %d, %d, %d : %d, %d\n", nifti_type_list[c].name, nifti_type_list[c].type, nifti_type_list[c].nbyper, nifti_type_list[c].swapsize, nbyper, ssize); errs++; } } if( errs ) fprintf(stderr,"** nifti_test_datatype_sizes: found %d errors\n",errs); else if( verb || g_opts.debug > 1 ) fprintf(stderr,"-- nifti_test_datatype_sizes: all OK\n"); return errs; } /*---------------------------------------------------------------------*/ /*! Display the nifti_type_list table. * * if which == 1 : display DT_* * if which == 2 : display NIFTI_TYPE* * else : display all *//*-------------------------------------------------------------------*/ int nifti_disp_type_list( int which ) { const char * style; int tablen = sizeof(nifti_type_list)/sizeof(nifti_type_ele); int lwhich, c; if ( which == 1 ){ lwhich = 1; style = "DT_"; } else if( which == 2 ){ lwhich = 2; style = "NIFTI_TYPE_"; } else { lwhich = 3; style = "ALL"; } printf("nifti_type_list entries (%s) :\n" " name type nbyper swapsize\n" " --------------------- ---- ------ --------\n", style); for( c = 0; c < tablen; c++ ) if( (lwhich & 1 && nifti_type_list[c].name[0] == 'D') || (lwhich & 2 && nifti_type_list[c].name[0] == 'N') ) printf(" %-22s %5d %3d %5d\n", nifti_type_list[c].name, nifti_type_list[c].type, nifti_type_list[c].nbyper, nifti_type_list[c].swapsize); return 0; } nifti_clib-3.0.1/niftilib/nifti1_io.h000066400000000000000000000634521371325713600174710ustar00rootroot00000000000000/** \file nifti1_io.h \brief Data structures for using nifti1_io API. - Written by Bob Cox, SSCC NIMH - Revisions by Rick Reynolds, SSCC NIMH */ #ifndef _NIFTI_IO_HEADER_ #define _NIFTI_IO_HEADER_ #include #include #include #include #include #ifndef DONT_INCLUDE_ANALYZE_STRUCT #define DONT_INCLUDE_ANALYZE_STRUCT /*** not needed herein ***/ #endif #include "nifti1.h" /*** NIFTI-1 header specification ***/ #include /*=================*/ #ifdef __cplusplus extern "C" { #endif /*=================*/ /*****===================================================================*****/ /***** File nifti1_io.h == Declarations for nifti1_io.c *****/ /*****...................................................................*****/ /***** This code is released to the public domain. *****/ /*****...................................................................*****/ /***** Author: Robert W Cox, SSCC/DIRP/NIMH/NIH/DHHS/USA/EARTH *****/ /***** Date: August 2003 *****/ /*****...................................................................*****/ /***** Neither the National Institutes of Health (NIH), nor any of its *****/ /***** employees imply any warranty of usefulness of this software for *****/ /***** any purpose, and do not assume any liability for damages, *****/ /***** incidental or otherwise, caused by any use of this document. *****/ /*****===================================================================*****/ /* Modified by: Mark Jenkinson (FMRIB Centre, University of Oxford, UK) Date: July/August 2004 Mainly adding low-level IO and changing things to allow gzipped files to be read and written Full backwards compatability should have been maintained Modified by: Rick Reynolds (SSCC/DIRP/NIMH, National Institutes of Health) Date: December 2004 Modified and added many routines for I/O. */ /********************** Some sample data structures **************************/ typedef struct { /** 4x4 matrix struct **/ float m[4][4] ; } mat44 ; typedef struct { /** 3x3 matrix struct **/ float m[3][3] ; } mat33 ; /*...........................................................................*/ /*! \enum analyze_75_orient_code * \brief Old-style analyze75 orientation * codes. */ typedef enum _analyze75_orient_code { a75_transverse_unflipped = 0, a75_coronal_unflipped = 1, a75_sagittal_unflipped = 2, a75_transverse_flipped = 3, a75_coronal_flipped = 4, a75_sagittal_flipped = 5, a75_orient_unknown = 6 } analyze_75_orient_code; /*! \struct nifti_image \brief High level data structure for open nifti datasets in the nifti1_io API. Note that this structure is not part of the nifti1 format definition; it is used to implement one API for reading/writing formats in the nifti1 format. */ typedef struct { /*!< Image storage struct **/ int ndim ; /*!< last dimension greater than 1 (1..7) */ int nx ; /*!< dimensions of grid array */ int ny ; /*!< dimensions of grid array */ int nz ; /*!< dimensions of grid array */ int nt ; /*!< dimensions of grid array */ int nu ; /*!< dimensions of grid array */ int nv ; /*!< dimensions of grid array */ int nw ; /*!< dimensions of grid array */ int dim[8] ; /*!< dim[0]=ndim, dim[1]=nx, etc. */ size_t nvox ; /*!< number of voxels = nx*ny*nz*...*nw */ int nbyper ; /*!< bytes per voxel, matches datatype */ int datatype ; /*!< type of data in voxels: DT_* code */ float dx ; /*!< grid spacings */ float dy ; /*!< grid spacings */ float dz ; /*!< grid spacings */ float dt ; /*!< grid spacings */ float du ; /*!< grid spacings */ float dv ; /*!< grid spacings */ float dw ; /*!< grid spacings */ float pixdim[8] ; /*!< pixdim[1]=dx, etc. */ float scl_slope ; /*!< scaling parameter - slope */ float scl_inter ; /*!< scaling parameter - intercept */ float cal_min ; /*!< calibration parameter, minimum */ float cal_max ; /*!< calibration parameter, maximum */ int qform_code ; /*!< codes for (x,y,z) space meaning */ int sform_code ; /*!< codes for (x,y,z) space meaning */ int freq_dim ; /*!< indexes (1,2,3, or 0) for MRI */ int phase_dim ; /*!< directions in dim[]/pixdim[] */ int slice_dim ; /*!< directions in dim[]/pixdim[] */ int slice_code ; /*!< code for slice timing pattern */ int slice_start ; /*!< index for start of slices */ int slice_end ; /*!< index for end of slices */ float slice_duration ; /*!< time between individual slices */ /*! quaternion transform parameters [when writing a dataset, these are used for qform, NOT qto_xyz] */ float quatern_b , quatern_c , quatern_d , qoffset_x , qoffset_y , qoffset_z , qfac ; mat44 qto_xyz ; /*!< qform: transform (i,j,k) to (x,y,z) */ mat44 qto_ijk ; /*!< qform: transform (x,y,z) to (i,j,k) */ mat44 sto_xyz ; /*!< sform: transform (i,j,k) to (x,y,z) */ mat44 sto_ijk ; /*!< sform: transform (x,y,z) to (i,j,k) */ float toffset ; /*!< time coordinate offset */ int xyz_units ; /*!< dx,dy,dz units: NIFTI_UNITS_* code */ int time_units ; /*!< dt units: NIFTI_UNITS_* code */ int nifti_type ; /*!< 0==ANALYZE, 1==NIFTI-1 (1 file), 2==NIFTI-1 (2 files), 3==NIFTI-ASCII (1 file) */ int intent_code ; /*!< statistic type (or something) */ float intent_p1 ; /*!< intent parameters */ float intent_p2 ; /*!< intent parameters */ float intent_p3 ; /*!< intent parameters */ char intent_name[16] ; /*!< optional description of intent data */ char descrip[80] ; /*!< optional text to describe dataset */ char aux_file[24] ; /*!< auxiliary filename */ char *fname ; /*!< header filename (.hdr or .nii) */ char *iname ; /*!< image filename (.img or .nii) */ int iname_offset ; /*!< offset into iname where data starts */ int swapsize ; /*!< swap unit in image data (might be 0) */ int byteorder ; /*!< byte order on disk (MSB_ or LSB_FIRST) */ void *data ; /*!< pointer to data: nbyper*nvox bytes */ int num_ext ; /*!< number of extensions in ext_list */ nifti1_extension * ext_list ; /*!< array of extension structs (with data) */ analyze_75_orient_code analyze75_orient; /*!< for old analyze files, orient */ } nifti_image ; /* struct for return from nifti_image_read_bricks() */ typedef struct { int nbricks; /* the number of allocated pointers in 'bricks' */ size_t bsize; /* the length of each data block, in bytes */ void ** bricks; /* array of pointers to data blocks */ } nifti_brick_list; /*****************************************************************************/ /*------------------ NIfTI version of ANALYZE 7.5 structure -----------------*/ /* (based on fsliolib/dbh.h, but updated for version 7.5) */ typedef struct { /* header info fields - describes the header overlap with NIfTI */ /* ------------------ */ int sizeof_hdr; /* 0 + 4 same */ char data_type[10]; /* 4 + 10 same */ char db_name[18]; /* 14 + 18 same */ int extents; /* 32 + 4 same */ short int session_error; /* 36 + 2 same */ char regular; /* 38 + 1 same */ char hkey_un0; /* 39 + 1 40 bytes */ /* image dimension fields - describes image sizes */ short int dim[8]; /* 0 + 16 same */ short int unused8; /* 16 + 2 intent_p1... */ short int unused9; /* 18 + 2 ... */ short int unused10; /* 20 + 2 intent_p2... */ short int unused11; /* 22 + 2 ... */ short int unused12; /* 24 + 2 intent_p3... */ short int unused13; /* 26 + 2 ... */ short int unused14; /* 28 + 2 intent_code */ short int datatype; /* 30 + 2 same */ short int bitpix; /* 32 + 2 same */ short int dim_un0; /* 34 + 2 slice_start */ float pixdim[8]; /* 36 + 32 same */ float vox_offset; /* 68 + 4 same */ float funused1; /* 72 + 4 scl_slope */ float funused2; /* 76 + 4 scl_inter */ float funused3; /* 80 + 4 slice_end, */ /* slice_code, */ /* xyzt_units */ float cal_max; /* 84 + 4 same */ float cal_min; /* 88 + 4 same */ float compressed; /* 92 + 4 slice_duration */ float verified; /* 96 + 4 toffset */ int glmax,glmin; /* 100 + 8 108 bytes */ /* data history fields - optional */ char descrip[80]; /* 0 + 80 same */ char aux_file[24]; /* 80 + 24 same */ char orient; /* 104 + 1 NO GOOD OVERLAP */ char originator[10]; /* 105 + 10 FROM HERE DOWN... */ char generated[10]; /* 115 + 10 */ char scannum[10]; /* 125 + 10 */ char patient_id[10]; /* 135 + 10 */ char exp_date[10]; /* 145 + 10 */ char exp_time[10]; /* 155 + 10 */ char hist_un0[3]; /* 165 + 3 */ int views; /* 168 + 4 */ int vols_added; /* 172 + 4 */ int start_field; /* 176 + 4 */ int field_skip; /* 180 + 4 */ int omax, omin; /* 184 + 8 */ int smax, smin; /* 192 + 8 200 bytes */ } nifti_analyze75; /* total: 348 bytes */ /*****************************************************************************/ /*--------------- Prototypes of functions defined in this file --------------*/ char const * nifti_datatype_string ( int dt ) ; char const *nifti_units_string ( int uu ) ; char const *nifti_intent_string ( int ii ) ; char const *nifti_xform_string ( int xx ) ; char const *nifti_slice_string ( int ss ) ; char const *nifti_orientation_string( int ii ) ; int nifti_is_inttype( int dt ) ; mat44 nifti_mat44_inverse( mat44 R ) ; mat33 nifti_mat33_inverse( mat33 R ) ; mat33 nifti_mat33_polar ( mat33 A ) ; float nifti_mat33_rownorm( mat33 A ) ; float nifti_mat33_colnorm( mat33 A ) ; float nifti_mat33_determ ( mat33 R ) ; mat33 nifti_mat33_mul ( mat33 A , mat33 B ) ; void nifti_swap_2bytes ( size_t n , void *ar ) ; void nifti_swap_4bytes ( size_t n , void *ar ) ; void nifti_swap_8bytes ( size_t n , void *ar ) ; void nifti_swap_16bytes( size_t n , void *ar ) ; void nifti_swap_Nbytes ( size_t n , int siz , void *ar ) ; int nifti_datatype_is_valid (int dtype, int for_nifti); int nifti_datatype_from_string(const char * name); const char * nifti_datatype_to_string (int dtype); int nifti_get_filesize( const char *pathname ) ; void swap_nifti_header ( struct nifti_1_header *h , int is_nifti ) ; void old_swap_nifti_header( struct nifti_1_header *h , int is_nifti ); int nifti_swap_as_analyze( nifti_analyze75 *h ); /* main read/write routines */ nifti_image *nifti_image_read_bricks(const char *hname , int nbricks, const int *blist, nifti_brick_list * NBL); int nifti_image_load_bricks(nifti_image *nim , int nbricks, const int *blist, nifti_brick_list * NBL); void nifti_free_NBL( nifti_brick_list * NBL ); nifti_image *nifti_image_read ( const char *hname , int read_data ) ; int nifti_image_load ( nifti_image *nim ) ; void nifti_image_unload ( nifti_image *nim ) ; void nifti_image_free ( nifti_image *nim ) ; int nifti_read_collapsed_image( nifti_image * nim, const int dims [8], void ** data ); int nifti_read_subregion_image( nifti_image * nim, const int *start_index, const int *region_size, void ** data ); void nifti_image_write ( nifti_image * nim ) ; void nifti_image_write_bricks(nifti_image * nim, const nifti_brick_list * NBL); void nifti_image_infodump( const nifti_image * nim ) ; void nifti_disp_lib_hist( void ) ; /* to display library history */ void nifti_disp_lib_version( void ) ; /* to display library version */ int nifti_disp_matrix_orient( const char * mesg, mat44 mat ); int nifti_disp_type_list( int which ); char * nifti_image_to_ascii ( const nifti_image * nim ) ; nifti_image *nifti_image_from_ascii( const char * str, int * bytes_read ) ; size_t nifti_get_volsize(const nifti_image *nim) ; /* basic file operations */ int nifti_set_filenames(nifti_image * nim, const char * prefix, int check, int set_byte_order); char * nifti_makehdrname (const char * prefix, int nifti_type, int check, int comp); char * nifti_makeimgname (const char * prefix, int nifti_type, int check, int comp); int is_nifti_file (const char *hname); char * nifti_find_file_extension(const char * name); int nifti_is_complete_filename(const char* fname); int nifti_validfilename(const char* fname); int disp_nifti_1_header(const char * info, const nifti_1_header * hp ) ; void nifti_set_debug_level( int level ) ; void nifti_set_skip_blank_ext( int skip ) ; void nifti_set_allow_upper_fext( int allow ) ; int valid_nifti_brick_list(nifti_image * nim , int nbricks, const int * blist, int disp_error); /* znzFile operations */ znzFile nifti_image_open(const char * hname, const char * opts, nifti_image ** nim); znzFile nifti_image_write_hdr_img(nifti_image *nim, int write_data, const char* opts); znzFile nifti_image_write_hdr_img2( nifti_image *nim , int write_opts , const char* opts, znzFile imgfile, const nifti_brick_list * NBL); size_t nifti_read_buffer(znzFile fp, void* dataptr, size_t ntot, nifti_image *nim); int nifti_write_all_data(znzFile fp, nifti_image * nim, const nifti_brick_list * NBL); size_t nifti_write_buffer(znzFile fp, const void * buffer, size_t numbytes); nifti_image *nifti_read_ascii_image(znzFile fp, char *fname, int flen, int read_data); znzFile nifti_write_ascii_image(nifti_image *nim, const nifti_brick_list * NBL, const char * opts, int write_data, int leave_open); void nifti_datatype_sizes( int datatype , int *nbyper, int *swapsize ) ; void nifti_mat44_to_quatern( mat44 R , float *qb, float *qc, float *qd, float *qx, float *qy, float *qz, float *dx, float *dy, float *dz, float *qfac ) ; mat44 nifti_quatern_to_mat44( float qb, float qc, float qd, float qx, float qy, float qz, float dx, float dy, float dz, float qfac ); mat44 nifti_make_orthog_mat44( float r11, float r12, float r13 , float r21, float r22, float r23 , float r31, float r32, float r33 ) ; int nifti_short_order(void) ; /* CPU byte order */ /* Orientation codes that might be returned from nifti_mat44_to_orientation().*/ #define NIFTI_L2R 1 /* Left to Right */ #define NIFTI_R2L 2 /* Right to Left */ #define NIFTI_P2A 3 /* Posterior to Anterior */ #define NIFTI_A2P 4 /* Anterior to Posterior */ #define NIFTI_I2S 5 /* Inferior to Superior */ #define NIFTI_S2I 6 /* Superior to Inferior */ void nifti_mat44_to_orientation( mat44 R , int *icod, int *jcod, int *kcod ) ; /*--------------------- Low level IO routines ------------------------------*/ char * nifti_findhdrname (const char* fname); char * nifti_findimgname (const char* fname , int nifti_type); int nifti_is_gzfile (const char* fname); char * nifti_makebasename(const char* fname); /* other routines */ struct nifti_1_header nifti_convert_nim2nhdr(const nifti_image* nim); nifti_1_header * nifti_make_new_header(const int arg_dims[], int arg_dtype); nifti_1_header * nifti_read_header(const char *hname, int *swapped, int check); nifti_image * nifti_copy_nim_info(const nifti_image * src); nifti_image * nifti_make_new_nim(const int dims[], int datatype, int data_fill); nifti_image * nifti_simple_init_nim(void); nifti_image * nifti_convert_nhdr2nim(struct nifti_1_header nhdr, const char * fname); int nifti_hdr_looks_good (const nifti_1_header * hdr); int nifti_is_valid_datatype (int dtype); int nifti_is_valid_ecode (int ecode); int nifti_nim_is_valid (nifti_image * nim, int complain); int nifti_nim_has_valid_dims (nifti_image * nim, int complain); int is_valid_nifti_type (int nifti_type); int nifti_test_datatype_sizes (int verb); int nifti_type_and_names_match (nifti_image * nim, int show_warn); int nifti_update_dims_from_array(nifti_image * nim); void nifti_set_iname_offset (nifti_image *nim); int nifti_set_type_from_names (nifti_image * nim); int nifti_add_extension(nifti_image * nim, const char * data, int len, int ecode ); int nifti_compiled_with_zlib (void); int nifti_copy_extensions (nifti_image *nim_dest,const nifti_image *nim_src); int nifti_free_extensions (nifti_image *nim); int * nifti_get_intlist (int nvals , const char *str); char * nifti_strdup (const char *str); int valid_nifti_extensions(const nifti_image *nim); /*-------------------- Some C convenience macros ----------------------------*/ /* NIfTI-1.1 extension codes: see http://nifti.nimh.nih.gov/nifti-1/documentation/faq#Q21 */ #define NIFTI_ECODE_IGNORE 0 /* changed from UNKNOWN, 29 June 2005 */ #define NIFTI_ECODE_DICOM 2 /* intended for raw DICOM attributes */ #define NIFTI_ECODE_AFNI 4 /* Robert W Cox: rwcox@nih.gov https://afni.nimh.nih.gov/afni */ #define NIFTI_ECODE_COMMENT 6 /* plain ASCII text only */ #define NIFTI_ECODE_XCEDE 8 /* David B Keator: dbkeator@uci.edu http://www.nbirn.net/Resources /Users/Applications/ /xcede/index.htm */ #define NIFTI_ECODE_JIMDIMINFO 10 /* Mark A Horsfield: mah5@leicester.ac.uk http://someplace/something */ #define NIFTI_ECODE_WORKFLOW_FWDS 12 /* Kate Fissell: fissell@pitt.edu http://kraepelin.wpic.pitt.edu /~fissell/NIFTI_ECODE_WORKFLOW_FWDS /NIFTI_ECODE_WORKFLOW_FWDS.html */ #define NIFTI_ECODE_FREESURFER 14 /* http://surfer.nmr.mgh.harvard.edu */ #define NIFTI_ECODE_PYPICKLE 16 /* embedded Python objects http://niftilib.sourceforge.net /pynifti */ /* LONI MiND codes: http://www.loni.ucla.edu/twiki/bin/view/Main/MiND */ #define NIFTI_ECODE_MIND_IDENT 18 /* Vishal Patel: vishal.patel@ucla.edu*/ #define NIFTI_ECODE_B_VALUE 20 #define NIFTI_ECODE_SPHERICAL_DIRECTION 22 #define NIFTI_ECODE_DT_COMPONENT 24 #define NIFTI_ECODE_SHC_DEGREEORDER 26 /* end LONI MiND codes */ #define NIFTI_ECODE_VOXBO 28 /* Dan Kimberg: www.voxbo.org */ #define NIFTI_ECODE_CARET 30 /* John Harwell: john@brainvis.wustl.edu http://brainvis.wustl.edu/wiki /index.php/Caret:Documentation :CaretNiftiExtension */ #define NIFTI_ECODE_CIFTI 32 /* CIFTI-2_Main_FINAL_1March2014.pdf */ #define NIFTI_ECODE_VARIABLE_FRAME_TIMING 34 /* 36 is currently unassigned, waiting on NIFTI_ECODE_AGILENT_PROCPAR */ #define NIFTI_ECODE_EVAL 38 /* Munster University Hospital */ /* http://www.mathworks.com/matlabcentral/fileexchange/42997-dicom-to-nifti-converter */ #define NIFTI_ECODE_MATLAB 40 /* MATLAB extension */ /* Quantiphyse extension https://quantiphyse.readthedocs.io/en/latest/advanced/nifti_extension.html*/ #define NIFTI_ECODE_QUANTIPHYSE 42 /* Quantiphyse extension */ /* Magnetic Resonance Spectroscopy (MRS) link to come... */ #define NIFTI_ECODE_MRS 44 /* MRS extension */ #define NIFTI_MAX_ECODE 44 /******* maximum extension code *******/ /* nifti_type file codes */ #define NIFTI_FTYPE_ANALYZE 0 #define NIFTI_FTYPE_NIFTI1_1 1 #define NIFTI_FTYPE_NIFTI1_2 2 #define NIFTI_FTYPE_ASCII 3 #define NIFTI_MAX_FTYPE 3 /* this should match the maximum code */ /*------------------------------------------------------------------------*/ /*-- the rest of these apply only to nifti1_io.c, check for _NIFTI1_IO_C_ */ /* Feb 9, 2005 [rickr] */ #ifdef _NIFTI1_IO_C_ typedef struct { int debug; /*!< debug level for status reports */ int skip_blank_ext; /*!< skip extender if no extensions */ int allow_upper_fext; /*!< allow uppercase file extensions */ } nifti_global_options; typedef struct { int type; /* should match the NIFTI_TYPE_ #define */ int nbyper; /* bytes per value, matches nifti_image */ int swapsize; /* bytes per swap piece, matches nifti_image */ char const * const name; /* text string to match #define */ } nifti_type_ele; #undef LNI_FERR /* local nifti file error, to be compact and repetative */ #define LNI_FERR(func,msg,file) \ fprintf(stderr,"** ERROR (%s): %s '%s'\n",func,msg,file) #undef swap_2 #undef swap_4 #define swap_2(s) nifti_swap_2bytes(1,&(s)) /* s: 2-byte short; swap in place */ #define swap_4(v) nifti_swap_4bytes(1,&(v)) /* v: 4-byte value; swap in place */ /***** isfinite() is a C99 macro, which is present in many C implementations already *****/ #undef IS_GOOD_FLOAT #undef FIXED_FLOAT #ifdef isfinite /* use isfinite() to check floats/doubles for goodness */ # define IS_GOOD_FLOAT(x) isfinite(x) /* check if x is a "good" float */ # define FIXED_FLOAT(x) (isfinite(x) ? (x) : 0) /* fixed if bad */ #else # define IS_GOOD_FLOAT(x) 1 /* don't check it */ # define FIXED_FLOAT(x) (x) /* don't fix it */ #endif #undef ASSIF /* assign v to *p, if possible */ #define ASSIF(p,v) if( (p)!=NULL ) *(p) = (v) #undef MSB_FIRST #undef LSB_FIRST #undef REVERSE_ORDER #define LSB_FIRST 1 #define MSB_FIRST 2 #define REVERSE_ORDER(x) (3-(x)) /* convert MSB_FIRST <--> LSB_FIRST */ #define LNI_MAX_NIA_EXT_LEN 100000 /* consider a longer extension invalid */ #endif /* _NIFTI1_IO_C_ section */ /*------------------------------------------------------------------------*/ /*=================*/ #ifdef __cplusplus } #endif /*=================*/ #endif /* _NIFTI_IO_HEADER_ */ nifti_clib-3.0.1/niftilib/nifti1_io_version.h000066400000000000000000000013611371325713600212250ustar00rootroot00000000000000/* NOTE: When changing version consider the impact on versions in nifti2_io_version.h nifti1_io_version.h nifticdf_version.h and znzlib.h */ #define NIFTI1_IO_VERSION_MAJOR 2 #define NIFTI1_IO_VERSION_MINOR 1 #define NIFTI1_IO_VERSION_PATCH 0 /* main string macros: NIFTI1_IO_VERSION and NIFTI1_IO_SOURCE_VERSION */ #define NIFTI1_IO_VERSION_TO_STRING(x) NIFTI1_IO_VERSION_TO_STRING0(x) #define NIFTI1_IO_VERSION_TO_STRING0(x) #x #define NIFTI1_IO_VERSION \ NIFTI1_IO_VERSION_TO_STRING(NIFTI1_IO_VERSION_MAJOR) \ "." NIFTI1_IO_VERSION_TO_STRING(NIFTI1_IO_VERSION_MINOR) \ "." NIFTI1_IO_VERSION_TO_STRING(NIFTI1_IO_VERSION_PATCH) #define NIFTI1_IO_SOURCE_VERSION "NIFTI1_IO version " NIFTI1_IO_VERSION nifti_clib-3.0.1/niftilib/nifti1_test.c000066400000000000000000000067041371325713600200310ustar00rootroot00000000000000#include /* directly include I/O library functions */ static int local_fileexists(const char* fname) { znzFile fp = znzopen( fname , "rb" , 1 ) ; if( !znz_isnull(fp) ) { znzclose(fp); return 1; } return 0; /* fp is NULL */ } /*-----------------------------------------------*/ /* cc -o nifti1_test -O2 nifti1_test.c -lm */ /*-----------------------------------------------*/ /****************************************************************************/ int main( int argc , char *argv[] ) { nifti_image *nim ; int iarg=1 , outmode=1 , ll , argn=1, usegzip=0; char *tmpstr; if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf("Usage: nifti1_test [-n2|-n1|-na|-a2] infile [prefix]\n" "\n" " If prefix is given, then the options mean:\n" " -a2 ==> write an ANALYZE 7.5 file pair: prefix.hdr/prefix.img\n" " -n2 ==> write a NIFTI-1 file pair: prefix.hdr/prefix.img\n" " -n1 ==> write a NIFTI-1 single file: prefix.nii\n" " -na ==> write a NIFTI-1 ASCII+binary file: prefix.nia\n"); printf(" -za2 => write an ANALYZE 7.5 file pair:\n" " prefix.hdr.gz/prefix.img.gz\n" " -zn2 => write a NIFTI-1 file pair: prefix.hdr.gz/prefix.img.gz\n" " -zn1 => write a NIFTI-1 single file: prefix.nii.gz\n"); printf(" The default is '-n1'.\n" "\n" " If prefix is not given, then the header info from infile\n" " file is printed to stdout.\n" "\n" " Please note that the '.nia' format is NOT part of the\n" " NIFTI-1 specification, but is provided mostly for ease\n" " of visualization (e.g., you can edit a .nia file and\n" " change some header fields, then rewrite it as .nii)\n" ) ; printf("\nsizeof(nifti_1_header)=%u\n", (unsigned int)sizeof(nifti_1_header)) ; exit(0) ; } if( argv[1][0] == '-' ){ argn=1; if (argv[1][1] == 'z' ) { usegzip = 1; argn=2; } if( argv[1][argn] == 'a' ){ outmode = 0 ; } else if( argv[1][argn] == 'n' ){ switch( argv[1][argn+1] ){ case '1': outmode = 1 ; break ; default: outmode = 2 ; break ; case 'a': outmode = 3 ; break ; } } iarg++ ; } if( iarg >= argc ){ fprintf(stderr,"** ERROR: no input file on command line!?\n"); exit(1); } nim = nifti_image_read( argv[iarg++] , 1 ) ; if( nim == NULL ) exit(1) ; if( iarg >= argc ){ nifti_image_infodump(nim); exit(0); } nim->nifti_type = outmode ; if( nim->fname != NULL ) free(nim->fname) ; if( nim->iname != NULL ) free(nim->iname) ; ll = strlen(argv[iarg]) ; tmpstr = nifti_makebasename(argv[iarg]); nim->fname = (char *)calloc(1,ll+8) ; strcpy(nim->fname,tmpstr) ; nim->iname = (char *)calloc(1,ll+8) ; strcpy(nim->iname,tmpstr) ; free(tmpstr); if( nim->nifti_type == 1 ){ strcat(nim->fname,".nii") ; strcat(nim->iname,".nii") ; } else if ( nim->nifti_type == 3 ){ strcat(nim->fname,".nia") ; strcat(nim->iname,".nia") ; } else { strcat(nim->fname,".hdr") ; strcat(nim->iname,".img") ; } if (usegzip) { strcat(nim->fname,".gz"); strcat(nim->iname,".gz"); } nifti_image_write( nim ) ; if ( ! local_fileexists( nim->fname ) ) { return EXIT_FAILURE; } nifti_image_free( nim ) ; return EXIT_SUCCESS; } nifti_clib-3.0.1/niftilib/nifti1_tool.c000066400000000000000000004540661371325713600200370ustar00rootroot00000000000000/*--------------------------------------------------------------------------*/ /*! \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_nim
 *   nifti_tool -help_ana
 *   nifti_tool -help_datatypes
 *   nifti_tool -hist
 *   nifti_tool -ver
 *   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_exts -infiles f1 ...
 *   nifti_tool -disp_hdr [-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_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_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 mis-match 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" "----------------------------------------------------------------------\n" }; static char g_version[] = "version 1.24 (September 26, 2012)"; static int g_debug = 1; #define _NIFTI_TOOL_C_ #include "nifti1_io.h" #include "nifti1_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 */ field_s g_hdr_fields[NT_HDR_NUM_FIELDS]; /* nifti_1_header fields */ field_s g_ana_fields[NT_ANA_NUM_FIELDS]; /* nifti_analyze75 */ field_s g_nim_fields[NT_NIM_NUM_FIELDS]; /* nifti_image fields */ 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_hdr_field_array(g_hdr_fields)) != 0 ) FREE_RETURN(rv); if( (rv = fill_nim_field_array(g_nim_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.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_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 wither a difference exists (like the UNIX command) */ if( opts.diff_hdr && ((rv = act_diff_hdrs(&opts)) != 0) ) FREE_RETURN(rv); if( opts.diff_nim && ((rv = act_diff_nims(&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_hdr && ((rv = act_disp_hdrs(&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; memset(opts, 0, sizeof(*opts)); opts->prefix = NULL; opts->debug = 1; /* init debug level to basic output */ /* 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( ! strncmp(argv[ac], "-help_datatypes", 9) ) { 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( ! strncmp(argv[ac], "-help_hdr", 9) ) return usage(argv[0], USE_FIELD_HDR); else if( ! strncmp(argv[ac], "-help_nim", 9) ) return usage(argv[0], USE_FIELD_NIM); else if( ! strncmp(argv[ac], "-help_ana", 9) ) return usage(argv[0], USE_FIELD_ANA); else if( ! strncmp(argv[ac], "-help", 5) ) return usage(argv[0], USE_FULL); else if( ! strncmp(argv[ac], "-hist", 5) ) return usage(argv[0], USE_HIST); else if( ! strncmp(argv[ac], "-ver", 2) ) return usage(argv[0], USE_VERSION); else if( ! strncmp(argv[ac], "-nifti_hist", 11) ) { nifti_disp_lib_hist(); return 1; } else if( ! strncmp(argv[ac], "-nifti_ver", 10) ) { nifti_disp_lib_version(); return 1; } else if( ! strncmp(argv[ac], "-with_zlib", 5) ) { printf("Was NIfTI library compiled with zlib? %s\n", nifti_compiled_with_zlib() ? "YES" : "NO"); return 1; } /* begin normal execution options... */ else if( ! strncmp(argv[ac], "-add_afni_ext", 9) ) { 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", 9) ) { 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( ! strncmp(argv[ac], "-check_hdr", 10) ) opts->check_hdr = 1; else if( ! strncmp(argv[ac], "-check_nim", 10) ) opts->check_nim = 1; else if( ! strncmp(argv[ac], "-copy_brick_list", 11) || ! strncmp(argv[ac], "-copy_im", 10) || ! strncmp(argv[ac], "-cbl", 4) ) { opts->cbl = 1; } else if( ! strncmp(argv[ac], "-copy_collapsed_image", 10) || ! strncmp(argv[ac], "-cci", 4) ) { /* 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 requred"); 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] = atoi(argv[ac]); } opts->cci = 1; } else if( ! strncmp(argv[ac], "-debug", 6) ) { ac++; CHECK_NEXT_OPT(ac, argc, "-debug"); opts->debug = atoi(argv[ac]); } else if( ! strncmp(argv[ac], "-diff_hdr", 8) ) opts->diff_hdr = 1; else if( ! strncmp(argv[ac], "-diff_nim", 8) ) opts->diff_nim = 1; else if( ! strncmp(argv[ac], "-disp_exts", 7) ) opts->disp_exts = 1; else if( ! strncmp(argv[ac], "-disp_hdr", 8) ) opts->disp_hdr = 1; else if( ! strncmp(argv[ac], "-disp_nim", 8) ) opts->disp_nim = 1; else if( ! strncmp(argv[ac], "-disp_ana", 8) ) opts->disp_ana = 1; else if( ! strncmp(argv[ac], "-dci_lines", 6) || /* before -dts */ ! strncmp(argv[ac], "-dts_lines", 6) ) { opts->dci_lines = 1; } else if( ! strncmp(argv[ac], "-disp_collapsed_image", 10) || ! strncmp(argv[ac], "-disp_ci", 8) ) { /* 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 requred"); 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] = atoi(argv[ac]); } opts->dci = 1; } else if( ! strncmp(argv[ac], "-disp_ts", 10) || ! strncmp(argv[ac], "-dts", 4) ) { /* 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 requied\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] = atoi(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( ! strncmp(argv[ac], "-field", 2) ) { ac++; CHECK_NEXT_OPT(ac, argc, "-field"); if( add_string(&opts->flist, argv[ac]) ) return -1; /* add field */ } else if( ! strncmp(argv[ac], "-infiles", 3) ) { int count; /* 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( ! strncmp(argv[ac], "-mod_field", 6) ) { 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( ! strncmp(argv[ac], "-mod_hdr", 7) ) opts->mod_hdr = 1; else if( ! strncmp(argv[ac], "-mod_nim", 7) ) opts->mod_nim = 1; else if( ! strncmp(argv[ac], "-keep_hist", 5) ) 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 requred"); 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] = atoi(argv[ac]); } } else if( ! strncmp(argv[ac], "-new_datatype", 10) ) { ac++; CHECK_NEXT_OPT(ac, argc, "-new_datatype"); opts->new_datatype = atoi(argv[ac]); } else if( ! strncmp(argv[ac], "-overwrite", 6) ) opts->overwrite = 1; else if( ! strncmp(argv[ac], "-prefix", 4) ) { ac++; CHECK_NEXT_OPT(ac, argc, "-prefix"); opts->prefix = argv[ac]; } else if( ! strncmp(argv[ac], "-quiet", 3) ) opts->debug = 0; else if( ! strncmp(argv[ac], "-rm_ext", 7) ) { 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( ! strncmp(argv[ac], "-strip_extras", 6) ) opts->strip = 1; else if( ! strncmp(argv[ac], "-swap_as_analyze", 12) ) opts->swap_ana = 1; else if( ! strncmp(argv[ac], "-swap_as_nifti", 12) ) opts->swap_hdr = 1; else if( ! strncmp(argv[ac], "-swap_as_old", 12) ) 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_nim ) ? 1 : 0; ac += (opts->disp_hdr || opts->disp_nim || opts->disp_ana || opts->disp_exts ) ? 1 : 0; ac += (opts->mod_hdr || opts->mod_nim ) ? 1 : 0; ac += (opts->swap_hdr || opts->swap_ana || opts->swap_old ) ? 1 : 0; ac += (opts->add_exts || opts->rm_exts ) ? 1 : 0; ac += (opts->strip ) ? 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' or '-cci'\n" " (see '%s -help' for details)\n", prog); return 1; } /* can modify nifti_1_header or nifti_image, but not both */ if( opts->mod_hdr && opts->mod_nim ) { fprintf(stderr,"** cannot use both '-mod_hdr' and '-mod_nim'\n"); return 1; } /* can add or remove extensions, but not both */ if( opts->add_exts && opts->rm_exts ) { fprintf(stderr,"** cannot use both '-add_*_ext' and '-rm_ext'\n"); 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_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_hdr || 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_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 *----------------------------------------------------------------------*/ int fill_cmd_string( nt_opts * opts, int argc, char * argv[]) { char * cp; int len, remain = NT_CMD_LEN; /* NT_CMD_LEN is 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 = sprintf( opts->command, "\n command: %s", argv[0] ); 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 = 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 = sprintf(cp, " '%s'", argv[ac]); else len = sprintf(cp, " %s", argv[ac]); remain -= len; /* infiles is okay, but after the *next* argument, we may skip files */ /* (danger, will robinson! hack alert!) */ if( !strncmp(argv[ac-1],"-infiles",3) ) { /* 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(const 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("nifti_tool"); /* 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_HDR ) { field_s nhdr_fields[NT_HDR_NUM_FIELDS]; /* just do it all here */ fill_hdr_field_array(nhdr_fields); disp_field_s_list("nifti_1_header: ", nhdr_fields, NT_HDR_NUM_FIELDS); } 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); } else if( level == USE_FIELD_NIM ) { field_s nim_fields[NT_NIM_NUM_FIELDS]; fill_nim_field_array(nim_fields); disp_field_s_list("nifti_image: ", nim_fields, NT_NIM_NUM_FIELDS); } else if( level == USE_VERSION ) fprintf(stdout, "%s, %s\n", prog, g_version); else { fprintf(stdout,"** illegal level for usage(): %d\n", level); return -1; } return 1; } /*---------------------------------------------------------------------- * full usage *----------------------------------------------------------------------*/ int use_full(const char * prog ) { printf( "%s\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", prog); 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"); printf( "\n" " usage styles:\n" "\n" " nifti_tool -help : show this help\n" " nifti_tool -help_hdr : show nifti_1_header field info\n" " nifti_tool -help_nim : show nifti_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 -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" " nifti_tool -copy_im -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_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_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_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_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 -field dim -field intent_code \\\n" " -infiles dset0.nii dset1.nii \n" " 2. nifti_tool -diff_hdr -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_hdr -field dim -field descrip -infiles dset.nii\n" " 3. nifti_tool -disp_exts -infiles dset0.nii dset1.nii dset2.nii\n" " 4. nifti_tool -disp_ts 23 0 172 -infiles dset1_time.nii\n" " 5. nifti_tool -disp_ci 23 0 172 -1 0 0 0 -infiles dset1_time.nii\n" "\n"); printf( " 6. nifti_tool -disp_ana -infiles analyze.hdr\n" " 7. nifti_tool -disp_nim -infiles nifti.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( " E. copy dataset, brick list or collapsed image:\n" "\n" " 1. nifti_tool -copy_im -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_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_hdr -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" " ------------------------------\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 errros 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_nhdr2nim()\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" " -copy_brick_list : copy a list of volumes to a new dataset\n" " -cbl : (a shorter, alternative form)\n" " -copy_im : (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( " This functionality applies only to 3 or 4-dimensional datasets.\n" "\n" " e.g. to copy a dataset:\n" " nifti_tool -copy_im -prefix new.nii -infiles dset0.nii\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_1_header fields for datasets\n" "\n" " This flag means the user wishes to see some of the nifti_1_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"); printf( " If no '-field' option is present, all fields will be displayed.\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"); 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"); 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_exts : display all AFNI-type extensions\n" "\n" " This flag option is used to display all nifti_1_extension data,\n" " for only those extensions of type AFNI (code = 4). The only\n" " other option used will be '-infiles'.\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_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 datasets.\n" " If any fields are different, the contents of those fields is\n" " displayed (unless the '-quiet' option is used).\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_1_header field differences:\n" " nifti_tool -diff_hdr -infiles dset0.nii dset1.nii\n" "\n"); printf( " e.g. to display selected nifti_1_header 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" " See '-disp_hdr', 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_1_header fields\n" " Use 'nifti_tool -help_nim' to get a list of nifti_image 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_1_header field info\n" "\n" " e.g. nifti_tool -help_hdr\n" "\n" " -help_nim : show nifti_image field info\n" "\n" " e.g. nifti_tool -help_nim\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" " -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" " compiled: %s\n" " %s\n\n", __DATE__, g_version ); 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_hdr, diff_nim = %d, %d\n" " disp_hdr, disp_nim = %d, %d\n" " disp_ana, disp_exts = %d, %d\n" " add_exts, rm_exts = %d, %d\n" " mod_hdr, mod_nim = %d, %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_hdr, opts->diff_nim, opts->disp_hdr, opts->disp_nim, opts->disp_ana, opts->disp_exts, opts->add_exts, opts->rm_exts, opts->mod_hdr, 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_INT32, 8, ' ', 1); fprintf(stderr," new_dim[8] = "); disp_raw_data(opts->new_dim, DT_INT32, 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 ); if( !nim ) return 1; /* errors come from the library */ for( ec = 0; ec < opts->elist.len; ec++ ){ ext = opts->elist.list[ec]; elen = 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_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, 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); nifti_image_write(nim); 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; int len, bytes; if( !filename || !length ) { fprintf(stderr,"** bad params to read_file_text\n"); return NULL; } len = nifti_get_filesize(filename); if( len <= 0 ) { fprintf(stderr,"** RFT: file '%s' appears empty\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(len * sizeof(char)); if( !text ) { fprintf(stderr,"** RFT: failed to allocate %d bytes\n", len); fclose(fp); return NULL; } bytes = fread(text, sizeof(char), len, fp); fclose(fp); /* in any case */ if( bytes != len ) { fprintf(stderr,"** RFT: read only %d of %d bytes from %s\n", bytes, len, filename); free(text); return NULL; } /* success */ if( g_debug > 1 ) { fprintf(stderr,"++ found extension of length %d in file %s\n", len, filename); if( g_debug > 2 ) fprintf(stderr,"++ text is:\n%s\n", text); } *length = len; 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 ); 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); nifti_image_write(nim); 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 ); 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, 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); nifti_image_write(nim); 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 nifti_1_header * * if quiet mode (debug == 0) return on first diff * * return: 1 if diffs exist, 0 otherwise *----------------------------------------------------------------------*/ int act_diff_hdrs( nt_opts * opts ) { nifti_1_header * nhdr0, * nhdr1; int diffs = 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_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); if( ! nhdr0 ) return 1; /* errors have been printed */ nhdr1 = nt_read_header(opts, opts->infiles.list[1], NULL, 0); if( ! nhdr1 ){ free(nhdr0); return 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_hdrs(nhdr0, nhdr1, g_debug > 0); else diffs = diff_hdrs_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); if( ! nim0 ) return 1; /* errors have been printed */ nim1 = nt_image_read(opts, opts->infiles.list[1], 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; 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, opts->infiles.list[filenum], NULL, 0); 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_hdr_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_nhdr2nim(*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]; 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); 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++ ) { sprintf(mesg, " ext #%d : ", ec); disp_nifti1_extension(mesg, nim->ext_list + ec, -1); } nifti_image_free(nim); } return 0; } /*---------------------------------------------------------------------- * for each file, read nifti1_header and display all fields *----------------------------------------------------------------------*/ int act_disp_hdrs( nt_opts * opts ) { nifti_1_header * nhdr; field_s * fnhdr; const char ** sptr; int nfields, filenum, fc; /* set the number of fields to display */ nfields = opts->flist.len > 0 ? opts->flist.len : NT_HDR_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, opts->infiles.list[filenum], NULL, 0); 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_hdr_looks_good(nhdr) ? "valid" : "invalid"); if( opts->flist.len <= 0 ) /* then display all fields */ disp_field("\nall fields:\n", g_hdr_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_hdr_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; /* 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 = (nifti_analyze75 *)nt_read_header(opts, opts->infiles.list[filenum], NULL, 0); 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_hdr_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_hdr_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); 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_nim_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 * - 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=0; 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(opts, fname, &swap, 0); if( !nhdr ) return 1; 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_hdr_looks_good(nhdr) ? "valid" : "invalid"); } /* okay, let's actually trash the data fields */ if( modify_all_fields(nhdr, opts, g_hdr_fields, NT_HDR_NUM_FIELDS) ) { free(nhdr); return 1; } dupname = NULL; /* unless we duplicate file */ /* possibly duplicate the current dataset before writing new header */ if( opts->prefix ) { nim = nt_image_read(opts, fname, 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, strlen(opts->command), NIFTI_ECODE_COMMENT) ) fprintf(stderr,"** failed to add command to image as exten\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; nifti_image_write(nim); /* create the duplicate file */ /* 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; } /*---------------------------------------------------------------------- * - read header * - swap header * - 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; const char * fname; char * dupname; char func[] = { "act_mod_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(opts, fname, &swap, 0); if( !nhdr ) return 1; 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 ) { nim = nt_image_read(opts, fname, 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, strlen(opts->command), NIFTI_ECODE_COMMENT) ) fprintf(stderr,"** failed to add command to image as exten\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; nifti_image_write(nim); /* create the duplicate file */ /* 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); /* with data */ 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_nim_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, 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; } nifti_image_write(nim); /* and write it out, piece of cake :) */ 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; } /*---------------------------------------------------------------------- * 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; } 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_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 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; } /*---------------------------------------------------------------------- * fill the nifti_1_header field list *----------------------------------------------------------------------*/ int fill_hdr_field_array( field_s * nh_fields ) { nifti_1_header nhdr; field_s * nhf = nh_fields; int rv, errs; memset(nhf, 0, NT_HDR_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_HDR_NUM_FIELDS, sizeof(nhdr)) ) return 1; if( g_debug > 3 ) disp_field_s_list("nh_fields: ", nh_fields, NT_HDR_NUM_FIELDS); return 0; } /*---------------------------------------------------------------------- * fill the nifti_image field list *----------------------------------------------------------------------*/ int fill_nim_field_array( field_s * nim_fields ) { nifti_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; NT_SFILL(nim, nif, DT_INT32, 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("nifti_image test: ", nim_fields, NT_NIM_NUM_FIELDS, sizeof(nim)); if( g_debug > 3 ) disp_field_s_list("nim_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 > 2 ) 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 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; } /*---------------------------------------------------------------------- * display the contents of all of the field structures *----------------------------------------------------------------------*/ 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_FLOAT32 ) return "DT_FLOAT32"; 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 */ } #define NT_MAX_DT_STR_LEN 14 /*---------------------------------------------------------------------- * display the contents of all of the field structures *----------------------------------------------------------------------*/ int disp_field_s_list( const char *mesg, field_s * fp, int nfields ) { int c; 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)); 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_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_FLOAT32: 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_nifti1_extension( const char *mesg, nifti1_extension * ext, int maxlen) { int len; if( mesg ) fputs(mesg, stdout); if( !ext ) { fprintf(stderr,"** no extension to display\n"); return 1; } fprintf(stdout,"ecode = %d, esize = %d, edata = ", ext->ecode, ext->esize); if( !ext->edata ) fprintf(stdout,"(NULL)\n"); else if ( ext->ecode == NIFTI_ECODE_AFNI || ext->ecode == NIFTI_ECODE_COMMENT ) { len = ext->esize-8; if( maxlen >= 0 && len > maxlen ) len = maxlen; fprintf(stdout,"%.*s\n", len, (char *)ext->edata); } else fprintf(stdout,"(unknown data type)\n"); fflush(stdout); return 0; } /*---------------------------------------------------------------------- * return the appropritate pointer into the g_hdr_fields struct *----------------------------------------------------------------------*/ field_s * get_hdr_field( const char * fname, int show_fail ) { field_s * fp; int c; if( ! fname || *fname == '\0' ) return NULL; fp = g_hdr_fields; for( c = 0; c < NT_HDR_NUM_FIELDS; c++, fp++ ) if( strcmp(fname, fp->name) == 0 ) break; if( c == NT_HDR_NUM_FIELDS ) { if( show_fail > 0 ) fprintf(stderr,"** get_hdr_field: field not found in hdr: %s\n",fname); return NULL; } return fp; } /*---------------------------------------------------------------------- * return the appropritate pointer into the g_hdr_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_nim_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_hdrs( nifti_1_header * s0, nifti_1_header * s1, int display ) { field_s * fp = g_hdr_fields; int c, ndiff = 0; for( c = 0; c < NT_HDR_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_nim_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_hdrs_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_hdr_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, len, err; 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) = (%d,%d,%d)\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_INT32, 8, ' ', 1); } for( filenum = 0; filenum < opts->infiles.len; filenum++ ) { err = 0; nim = nt_image_read(opts, opts->infiles.list[filenum], 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_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; } len = nifti_read_collapsed_image(nim, opts->ci_dims, &data); if( len < 0 || !data ) { fprintf(stderr,"** FAILURE for dataset '%s'\n", nim->fname); 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_INT32, 3, ' ', 0); else disp_raw_data(opts->ci_dims+1, DT_INT32, 7, ' ', 0); fprintf(stdout,")\n"); } disp_raw_data(data, nim->datatype, len / nim->nbyper, space, 1); nifti_image_free(nim); } if( data ) free(data); return 0; } int disp_raw_data( void * data, int type, int nvals, char space, int newline ) { char * dp, fbuf[32]; int c, size; 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: printf("%d", *(short *)dp); break; case DT_INT32: printf("%d", *(int *)dp); break; case DT_UINT8: printf("%u", *(unsigned char *)dp); break; case DT_UINT16: printf("%u", *(unsigned short *)dp); break; case DT_UINT32: printf("%u", *(unsigned int *)dp); break; case DT_FLOAT32: { sprintf(fbuf,"%f", *(float *)dp); clear_float_zeros(fbuf); printf("%s", fbuf); break; } case DT_FLOAT64: { sprintf(fbuf,"%f", *(double *)dp); 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 * return 1 if something was cleared * 0 if not *----------------------------------------------------------------------*/ int clear_float_zeros( char * str ) { char * dp = strchr(str, '.'), * valp; int 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; } /*---------------------------------------------------------------------- * 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; int * 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); /* get image */ if( !nim ) return 1; /* since nt can be zero now (sigh), check for it 02 Mar 2006 [rickr] */ blist = nifti_get_intlist(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, 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_nim_fields,nim,NT_NIM_NUM_FIELDS,1); /* and finally, write out results */ if( err == 0 && nifti_nim_is_valid(nim, g_debug) ) nifti_image_write_bricks(nim, &NBL); nifti_image_free(nim); nifti_free_NBL(&NBL); free(fname); free(selstr); 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); 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, 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_nim_fields,nim,NT_NIM_NUM_FIELDS,1); /* and finally, write out results */ if( nifti_nim_is_valid(nim, g_debug) ) nifti_image_write(nim); 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" *----------------------------------------------------------------------*/ nifti_image * nt_image_read( nt_opts * opts, const char * fname, int doread ) { if( !opts || !fname ) { fprintf(stderr,"** nt_image_read: bad params (%p,%p)\n", (void *)opts, (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,doread); return nifti_image_read(fname, doread); } /* so generate an emtpy 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_INT32, 8, ' ', 1); printf(" new_datatype = %d\n", opts->new_datatype); fflush(stdout); } } /* create a new nifti_image, with data depending on doread */ return nifti_make_new_nim(opts->new_dim, opts->new_datatype, doread); } /*---------------------------------------------------------------------- * wrapper for nifti_read_header * * this adds the option to generage an empty image, if the * filename starts with "MAKE_IM" *----------------------------------------------------------------------*/ nifti_1_header * nt_read_header(nt_opts * opts, const char * fname, int * swapped, int check) { /* swapped is not necessary */ if( !opts || !fname ) { fprintf(stderr,"** nt_read_header: bad params (%p,%p)\n", (void *)opts,(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_read_header(%s,...)\n", fname); return nifti_read_header(fname, swapped, check); } /* so generate an emtpy 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(opts->new_dim, DT_INT32, 8, ' ', 1); printf(" new_datatype = %d\n", opts->new_datatype); fflush(stdout); } } /* return creation of new header */ return nifti_make_new_header(opts->new_dim, opts->new_datatype); } /*---------------------------------------------------------------------- * wrapper for nifti_read_header * * this adds the option to generage an empty image, if the * filename starts with "MAKE_IM" *----------------------------------------------------------------------*/ nifti_image * nt_read_bricks(nt_opts * opts, const char * fname, int len, int * 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); return nifti_image_read_bricks(fname, len, list, NBL); } /* so generate an emtpy 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_INT32, 8, ' ', 1); printf(" new_datatype = %d\n", opts->new_datatype); if( list && len > 0 ) { printf(" brick_list[%d] = ", len); disp_raw_data(list, DT_INT32, 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 = (size_t)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 %d pointers\n",NBL->nbricks); nifti_image_free(nim); return NULL; } if(g_debug > 1) fprintf(stderr,"+d NRB, allocating %d bricks of %u bytes...\n", NBL->nbricks, (unsigned)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 %u bytes\n", c, (unsigned)NBL->bsize); nifti_free_NBL(NBL); nifti_image_free(nim); return NULL; } } return nim; } nifti_clib-3.0.1/niftilib/nifti1_tool.h000066400000000000000000000173331371325713600200340ustar00rootroot00000000000000#ifndef _NIFTI_TOOL_H_ #define _NIFTI_TOOL_H_ #define NT_CMD_LEN 2048 typedef struct{ int len; const char ** list; } str_list; typedef struct{ int len; int * list; } int_list; typedef struct{ /* action options (flags) */ int check_hdr, check_nim; int diff_hdr, diff_nim; int disp_hdr, disp_nim, disp_ana; int disp_exts, add_exts, rm_exts; int mod_hdr, mod_nim; int swap_hdr, swap_ana, swap_old; int strip; /* strip extras from dataset(s) */ int cbl, cci; /* -copy_XXX option flags */ int dts, dci, dci_lines; /* display collapsed img flags */ int make_im; /* create a new image on the fly */ int ci_dims[8]; /* user dims list (last 7 valid) */ int new_dim[8]; /* user dim list for new image */ int new_datatype; /* datatype for new image */ int debug, keep_hist; /* debug level and history flag */ int overwrite; /* overwrite flag */ char * prefix; /* for output file */ str_list elist; /* extension strings */ int_list etypes; /* extension type list */ str_list flist; /* fields (to display or modify) */ str_list vlist; /* values (to set fields to) */ str_list infiles; /* input files */ char command[NT_CMD_LEN]; /* for inserting the command */ } nt_opts; #define USE_SHORT 1 #define USE_FULL 2 #define USE_HIST 3 #define USE_FIELD_HDR 4 #define USE_FIELD_NIM 5 #define USE_FIELD_ANA 6 #define USE_DTYPES 7 #define USE_VERSION 8 #define CHECK_NEXT_OPT(n,m,str) \ do { if ( (n) >= (m) ) { \ fprintf(stderr,"** option '%s': missing parameter\n",str); \ fprintf(stderr," consider: 'nifti_tool -help'\n"); \ return 1; } \ } while(0) #define CHECK_NEXT_OPT_MSG(n,m,str,msg) \ do { if ( (n) >= (m) ) { \ fprintf(stderr,"** option '%s': %s\n",str,msg); \ fprintf(stderr," consider: 'nifti_tool -help'\n"); \ return 1; } \ } while(0) /*---------------------------------------------------------------------- * this structure and definitions will be used to process the nifti_1_header * and nifti_image structure fields (actions disp, diff, mod) *----------------------------------------------------------------------*/ #define NT_FIELD_NAME_LEN 20 /* more than length of longest name */ #define NT_HDR_NUM_FIELDS 43 /* in the nifti_1_header struct */ #define NT_ANA_NUM_FIELDS 47 /* in the nifti_analyze75 struct */ #define NT_NIM_NUM_FIELDS 63 /* in the nifti_image struct */ #define NT_DT_STRING -0xfff /* some strange number to abuse... */ #define NT_DT_POINTER -0xfef /* some strange number to abuse... */ #define NT_DT_CHAR_PTR -0xfee /* another... */ #define NT_DT_EXT_PTR -0xfed /* and another... */ typedef struct { int type; /* one of the DT_* types from nifti1.h */ int offset; /* bytes from the start of the struct */ int size; /* size of one element type */ int len; /* number of elements */ char name[NT_FIELD_NAME_LEN]; /* actual structure name used */ } field_s; /* for computing the offset from the start of the struct */ #define NT_OFF(str,field) ((int)( ((char *)&str.field) - ((char *)&str) )) /* call fill_field() for a single type, name and number of elements */ /* nstr is the base struct, and fldp is a field pointer */ #define NT_SFILL(nstr,fldp,type,name,num,rv) do{ \ rv=fill_field(fldp,type,NT_OFF(nstr,name),num,#name); \ fldp++; } while (0) #define NT_MAKE_IM_NAME "MAKE_IM" /*----------------------------------------------------------------------*/ /*----- prototypes ---------------------------------------------------*/ /*----------------------------------------------------------------------*/ int act_add_exts ( nt_opts * opts ); int act_cbl ( nt_opts * opts ); /* copy brick list */ int act_cci ( nt_opts * opts ); /* copy collapsed dimensions */ int act_check_hdrs ( nt_opts * opts ); /* check for valid hdr or nim */ int act_diff_hdrs ( nt_opts * opts ); int act_diff_nims ( nt_opts * opts ); int act_disp_ci ( nt_opts * opts ); /* display general collapsed data */ int act_disp_exts ( nt_opts * opts ); int act_disp_hdrs ( nt_opts * opts ); int act_disp_nims ( nt_opts * opts ); int act_disp_anas ( nt_opts * opts ); int act_disp_ts ( nt_opts * opts ); /* display time series */ int act_mod_hdrs ( nt_opts * opts ); int act_mod_nims ( nt_opts * opts ); int act_swap_hdrs ( nt_opts * opts ); int act_rm_ext ( nt_opts * opts ); int act_strip ( nt_opts * opts ); /* strip extras from datasets */ field_s * get_hdr_field( const char * fname, int show_fail ); field_s * get_nim_field( const char * fname, int show_fail ); const char * field_type_str (int type); int diff_hdrs (nifti_1_header *s0, nifti_1_header *s1, int display); int diff_hdrs_list(nifti_1_header *s0, nifti_1_header *s1, str_list *slist, int display); int diff_nims (nifti_image *s0,nifti_image *s1, int display); int diff_nims_list(nifti_image *s0,nifti_image *s1,str_list *slist,int display); int add_int (int_list * ilist, int val); int add_string (str_list * slist, const char * str); int check_total_size ( const char *mesg, field_s *fields, int nfields, int tot_size); int clear_float_zeros( char * str ); int diff_field (field_s *fieldp, void * str0, void * str1, int nfields); int disp_nifti1_extension( const char *mesg, nifti1_extension * ext, int maxlen); int disp_field ( const char *mesg,field_s *fieldp,void *str,int nfields,int header); int disp_field_s_list( const char *mesg, field_s *, int nfields); int disp_nt_opts ( const char *mesg, nt_opts * opts); int disp_raw_data (void * data, int type, int nvals, char space,int newline); int fill_cmd_string (nt_opts * opts, int argc, char * argv[]); int fill_field (field_s *fp, int type, int offset, int num, const char *name); int fill_hdr_field_array(field_s * nh_fields); int fill_nim_field_array(field_s * nim_fields); int fill_ana_field_array(field_s * ah_fields); int modify_all_fields(void *basep, nt_opts *opts, field_s *fields, int flen); int modify_field (void * basep, field_s * field, const char * data); int process_opts (int argc, char * argv[], nt_opts * opts); int remove_ext_list (nifti_image * nim, const char ** elist, int len); int usage (const char * prog, int level); int use_full (const char * prog); int verify_opts (nt_opts * opts, char * prog); int write_hdr_to_file(nifti_1_header * nhdr, const char * fname); /* wrappers for nifti reading functions (allow MAKE_IM) */ nifti_image * nt_image_read (nt_opts * opts, const char * fname, int doread); nifti_image * nt_read_bricks(nt_opts * opts, const char * fname, int len, int * list, nifti_brick_list * NBL); nifti_1_header * nt_read_header(nt_opts * opts, const char * fname, int * swapped, int check); #endif /* _NIFTI_TOOL_H_ */ nifti_clib-3.0.1/niftilib/nifti_tester001.c000066400000000000000000000723051371325713600205200ustar00rootroot00000000000000/* * test program for NIFTI lib. */ #include enum NIFTITEST_BOOL { NIFTITEST_TRUE=1, NIFTITEST_FALSE=0 }; void _PrintTest(const int line,const char * message,const int FailureOccured, const enum NIFTITEST_BOOL isFatal,int *ErrorAccum) { if(FailureOccured==NIFTITEST_TRUE) /* This line can be commented out for a more verbose output */ { char const * const PREFIX= (FailureOccured)?"==========ERROR":"..........SUCCESS"; char const * const ISFATALPREFIX= (isFatal && FailureOccured)?" FATAL":""; printf("%s%s (LINE %d): %s\n",PREFIX,ISFATALPREFIX,line,message); fflush(stdout); *ErrorAccum+=FailureOccured; if(isFatal==NIFTITEST_TRUE && FailureOccured==NIFTITEST_TRUE) { printf("\n\nTOTAL ERRORS=%d\n",*ErrorAccum); exit( *ErrorAccum); } } } #define PrintTest(message,failure,isfailure,errorcount) \ _PrintTest(__LINE__,message,failure,isfailure,errorcount) nifti_image * generate_reference_image( const char * write_image_filename , int * const Errors) { nifti_1_header reference_header; memset(&reference_header,0,sizeof(reference_header)); reference_header.sizeof_hdr=sizeof(reference_header); reference_header.regular='r'; reference_header.extents=16384; reference_header.dim[0]=5; reference_header.dim[1]=23; reference_header.dim[2]=17; reference_header.dim[3]=11; reference_header.dim[4]=7; reference_header.dim[5]=3; reference_header.dim[6]=1; //This MUST be 1 anything else is invalid due to code that usees huristics to fix other possible problems; reference_header.dim[7]=1; //This MUST be 1 anything else is invalid due to code that usees huristics to fix other possible problems; reference_header.intent_p1=10101010.101F; reference_header.intent_p2=987654321.0F; reference_header.intent_p3=-1234.0F; reference_header.intent_code=NIFTI_INTENT_ESTIMATE; reference_header.datatype=DT_INT32; reference_header.pixdim[0]=-1.0F; /* this is really qfac */ reference_header.pixdim[1]=0.25F; reference_header.pixdim[2]=0.5F; reference_header.pixdim[3]=1.0F; reference_header.pixdim[4]=2.0F; reference_header.pixdim[5]=4.0F; reference_header.pixdim[6]=-2.0e10F; reference_header.pixdim[7]=-2.0e10F; reference_header.vox_offset=0; reference_header.scl_slope=0.25; reference_header.scl_inter=128; reference_header.qform_code=NIFTI_XFORM_SCANNER_ANAT; reference_header.quatern_b=-0.5F; reference_header.quatern_c= 0.5F; reference_header.quatern_d=-0.5F; reference_header.qoffset_x=reference_header.dim[1]/2.0F; reference_header.qoffset_y=reference_header.dim[2]/2.0F; reference_header.qoffset_z=reference_header.dim[3]/2.0F; reference_header.sform_code=NIFTI_XFORM_SCANNER_ANAT; reference_header.srow_x[0]=0.5; reference_header.srow_x[1]=0.0; reference_header.srow_x[2]=0.0; reference_header.srow_x[3]=0.0; reference_header.srow_y[0]=0.0; reference_header.srow_y[1]=1.0; reference_header.srow_y[2]=0.0; reference_header.srow_y[3]=0.0; reference_header.srow_z[0]=0.0; reference_header.srow_z[1]=0.0; reference_header.srow_z[2]=2.0; reference_header.srow_z[3]=0.0; reference_header.magic[0]='n'; reference_header.magic[1]='+'; reference_header.magic[2]='1'; reference_header.magic[3]='\0'; /* String is purposfully too long */ strncpy(reference_header.intent_name,"PHANTOM_DATA to be used for regression testing the nifti reader/writer",16); strncpy(reference_header.descrip,"This is a very long dialog here to use up more than 80 characters of space to test to see if the code is robust enough to deal appropriatly with very long and obnoxious lines.",80); { int nbyper; int swapsize; nifti_datatype_sizes(reference_header.datatype ,&nbyper,&swapsize); reference_header.bitpix=nbyper*8; } nifti_image * reference_image=nifti_convert_nhdr2nim(reference_header,write_image_filename); { const unsigned int NumVoxels=reference_image->nx*reference_image->ny*reference_image->nz*reference_image->nt*reference_image->nu; reference_image->data=(signed int *)calloc(NumVoxels,sizeof(signed int)) ; /*!< pointer to data: nbyper*nvox bytes */ PrintTest("Checking memory allocation",reference_image->data ==0 ,NIFTITEST_TRUE,Errors); { if(reference_image->data) { signed int i=0; for(; i < (signed int)NumVoxels ; i++) { ((signed int *)(reference_image->data))[i]=i; } } } } PrintTest("Setting filenames",nifti_set_filenames( reference_image,write_image_filename, 0, 0 ) != 0, NIFTITEST_TRUE,Errors); PrintTest("Setting type from names",nifti_set_type_from_names( reference_image ) != 0, NIFTITEST_TRUE,Errors); /* PrintTest("Checking type and names",nifti_type_and_names_match( reference_image , 1 ) != 1, NIFTITEST_TRUE,Errors); */ PrintTest("Check reference_image data is non null",(reference_image->data==0),NIFTITEST_TRUE,Errors); return reference_image; } void compare_reference_image_values(nifti_image const * const reference_image, nifti_image const * const reloaded_image, int * const Errors) { if( ! reference_image || ! reference_image->data ) { printf("ERROR: Reference image is NULL\n"); exit(-1); } if( ! reloaded_image || ! reloaded_image->data ) { printf("ERROR: Reloaded image is NULL\n"); exit(-1); } PrintTest("Checking nifti_type",(reference_image->nifti_type!=reloaded_image->nifti_type),NIFTITEST_FALSE,Errors); PrintTest("Checking fname",(strcmp(reference_image->fname,reloaded_image->fname)),NIFTITEST_FALSE,Errors); PrintTest("Checking iname",(strcmp(reference_image->iname,reloaded_image->iname)),NIFTITEST_FALSE,Errors); PrintTest("Checking ndim",(reference_image->ndim!=reloaded_image->ndim),NIFTITEST_FALSE,Errors); PrintTest("Checking nx",(reference_image->nx!=reloaded_image->nx),NIFTITEST_FALSE,Errors); PrintTest("Checking ny",(reference_image->ny!=reloaded_image->ny),NIFTITEST_FALSE,Errors); PrintTest("Checking nz",(reference_image->nz!=reloaded_image->nz),NIFTITEST_FALSE,Errors); PrintTest("Checking nt",(reference_image->nt!=reloaded_image->nt),NIFTITEST_FALSE,Errors); PrintTest("Checking nu",(reference_image->nu!=reloaded_image->nu),NIFTITEST_FALSE,Errors); PrintTest("Checking dx",(reference_image->dx!=reloaded_image->dx),NIFTITEST_FALSE,Errors); PrintTest("Checking dy",(reference_image->dy!=reloaded_image->dy),NIFTITEST_FALSE,Errors); PrintTest("Checking dz",(reference_image->dz!=reloaded_image->dz),NIFTITEST_FALSE,Errors); PrintTest("Checking dt",(reference_image->dt!=reloaded_image->dt),NIFTITEST_FALSE,Errors); PrintTest("Checking du",(reference_image->du!=reloaded_image->du),NIFTITEST_FALSE,Errors); PrintTest("Checking datatype",(reference_image->datatype!=reloaded_image->datatype),NIFTITEST_FALSE,Errors); { const unsigned int NumVoxels=reference_image->nx*reference_image->ny*reference_image->nz*reference_image->nt*reference_image->nu; PrintTest("Check loaded data is non null",(reloaded_image->data==0),NIFTITEST_TRUE,Errors); PrintTest("Check reference_image data is non null",(reference_image->data==0),NIFTITEST_TRUE,Errors); { unsigned int CurrVoxel=0; for(; CurrVoxel < NumVoxels ; CurrVoxel++) { /*printf("%d ",CurrVoxel); fflush(stdout);*/ if( ((int *)(reference_image->data))[CurrVoxel] != ((int *)(reloaded_image->data))[CurrVoxel]) { PrintTest("Incorrect Pixel Value Found",0,NIFTITEST_FALSE,Errors); } } } } PrintTest("Checking xyz_units",(reference_image->xyz_units!=reloaded_image->xyz_units),NIFTITEST_FALSE,Errors); PrintTest("Checking time_units",(reference_image->time_units!=reloaded_image->time_units),NIFTITEST_FALSE,Errors); PrintTest("Checking intent_code",(reference_image->intent_code!=reloaded_image->intent_code),NIFTITEST_FALSE,Errors); PrintTest("Checking intent_name",(strncmp(reference_image->intent_name,reloaded_image->intent_name,16) )!=0,NIFTITEST_FALSE,Errors); PrintTest("Checking description",(strncmp(reference_image->descrip,reloaded_image->descrip,80))!=0,NIFTITEST_FALSE,Errors); } int main (int argc, char *argv[]) { if (argc > 1) { printf("The test program takes no arguments: %s", argv[0]); return EXIT_FAILURE; } char TEMP_STR[256]; nifti_set_debug_level(3); int Errors=0; { PrintTest("NOT REALLY AN ERROR, JUST TESTING THE ERROR TEST REPORTING MECHANISM",1,NIFTITEST_FALSE,&Errors); PrintTest("NOT REALLY AN ERROR, JUST TESTING THE ERROR COUNTING MECHANISM",Errors==1,NIFTITEST_FALSE,&Errors); Errors=0; } { const char write_image_filename[6][64]={ "ATestReferenceImageForReadingAndWriting.nii", "ATestReferenceImageForReadingAndWriting.hdr", "ATestReferenceImageForReadingAndWriting.img", "ATestReferenceImageForReadingAndWriting.nii.gz", "ATestReferenceImageForReadingAndWriting.hdr.gz", "ATestReferenceImageForReadingAndWriting.img.gz" }; printf("======= Testing All Nifti Valid Names ======\n"); fflush(stdout); unsigned int filenameindex; for(filenameindex=0;filenameindex<6; filenameindex++) { char buf[512]; int CompressedTwoFile = strstr(write_image_filename[filenameindex],".img.gz") != 0 || strstr(write_image_filename[filenameindex],".hdr.gz") != 0; printf("======= Testing with filename: %s ======\n",write_image_filename[filenameindex]); fflush(stdout); nifti_image * reference_image = generate_reference_image(write_image_filename[filenameindex],&Errors); if( ! reference_image ) { printf("ERROR: reference image not generated."); fflush(stdout); return EXIT_FAILURE; } /* * Add an extension to test extension reading */ { static char ext[] = "THIS IS A TEST"; sprintf(buf,"nifti_add_extension %s",write_image_filename[filenameindex]); PrintTest(buf, nifti_add_extension(reference_image, ext,sizeof(ext), NIFTI_ECODE_COMMENT) == -1, NIFTITEST_FALSE,&Errors); sprintf(buf,"valid_nifti_extension %s",write_image_filename[filenameindex]); PrintTest("valid_nifti_extensions", valid_nifti_extensions(reference_image) == 0, NIFTITEST_FALSE,&Errors); } PrintTest("Create reference image",reference_image==0,NIFTITEST_TRUE,&Errors); nifti_image_write ( reference_image ) ; /* * test nifti_copy_extension */ { nifti_image *nim = nifti_simple_init_nim(); PrintTest("nifti_copy_extension", nifti_copy_extensions(nim,reference_image), NIFTITEST_FALSE,&Errors); nifti_image_free(nim); nim = nifti_copy_nim_info(reference_image); PrintTest("nifti_copy_nim_info", nim == 0, NIFTITEST_FALSE,&Errors); PrintTest("nifti_nim_is_valid", nifti_nim_is_valid(nim,0) == 0, NIFTITEST_FALSE,&Errors); nifti_image_free(nim); } { nifti_image * reloaded_image = (reference_image->fname) ? nifti_image_read(reference_image->fname,1): NULL; PrintTest("Reload of image ",reloaded_image==0,NIFTITEST_TRUE,&Errors); { /* * if the file is named '.img', '.hdr', '.img.gz', or '.hdr.gz', then * the header extensions won't be saved with the file. * The test will fail if it finds an extension in a 2-file NIfTI, or * fails to find one in a '.nii' or '.nii.gz' file. */ int result = valid_nifti_extensions(reloaded_image); sprintf(buf,"reload valid_nifti_extensions %s",write_image_filename[filenameindex]); PrintTest(buf, CompressedTwoFile ? result != 0 : result == 0, NIFTITEST_FALSE,&Errors); } nifti_image_infodump(reloaded_image); compare_reference_image_values(reference_image,reloaded_image,&Errors); nifti_image_free(reloaded_image); } { nifti_brick_list NB_orig, NB_select; nifti_image * nim_orig, * nim_select; int blist[5] = { 7, 0, 5, 5, 9 }; /* * test some error paths in the nifti_image_read_bricks */ nim_orig = nifti_image_read_bricks(reference_image->fname,0,blist, &NB_orig); PrintTest("invalid arg bricked image read 1",nim_orig != 0,NIFTITEST_FALSE,&Errors); nim_orig = nifti_image_read_bricks(reference_image->fname, 0, NULL, &NB_orig); PrintTest("Reload of bricked image",nim_orig == 0,NIFTITEST_FALSE,&Errors); nifti_free_NBL(&NB_orig); nifti_image_free(nim_orig); nim_select = nifti_image_read_bricks(reference_image->fname, 5, blist, &NB_select); PrintTest("Reload of bricked image with blist",nim_orig == 0,NIFTITEST_FALSE,&Errors); nifti_free_NBL(&NB_select); nifti_image_free(nim_select); } /* * test nifti_update_dims_from_array */ PrintTest("nifti_update_dims_from_array -- valid dims", nifti_update_dims_from_array(reference_image) != 0, NIFTITEST_FALSE,&Errors); reference_image->dim[0] = 8; PrintTest("nifti_update_dims_from_array -- invalid dims", nifti_update_dims_from_array(reference_image) == 0, NIFTITEST_FALSE,&Errors); { nifti_1_header x = nifti_convert_nim2nhdr(reference_image); char local_buffer[512]; sprintf(local_buffer,"nifti_hdr_looks_good %s",reference_image->fname); PrintTest(local_buffer, !nifti_hdr_looks_good(&x), NIFTITEST_FALSE,&Errors); } nifti_image_free(reference_image); } /* * check nifti_findimgname */ { char *imgname = nifti_findimgname("ATestReferenceImageForReadingAndWriting.hdr",2); PrintTest("nifti_findimgname", imgname == 0 || strcmp(imgname,"ATestReferenceImageForReadingAndWriting.img") != 0, NIFTITEST_FALSE,&Errors); free(imgname); } { int IsNiftiFile; IsNiftiFile = is_nifti_file(write_image_filename[0]); PrintTest("is_nifti_file0", IsNiftiFile != 1,NIFTITEST_FALSE,&Errors); IsNiftiFile = is_nifti_file(write_image_filename[1]); PrintTest("is_nifti_file1", IsNiftiFile != 2,NIFTITEST_FALSE,&Errors); IsNiftiFile = is_nifti_file(write_image_filename[3]); PrintTest("is_nifti_file2", IsNiftiFile != 1,NIFTITEST_FALSE,&Errors); IsNiftiFile = is_nifti_file(write_image_filename[4]); PrintTest("is_nifti_file2", IsNiftiFile != 2,NIFTITEST_FALSE,&Errors); } } { /* * test writing and reading an ascii file */ nifti_image * reference_image = generate_reference_image("TestAsciiImage.nia",&Errors); reference_image->nifti_type = 3; nifti_image_write(reference_image); nifti_image * reloaded_image = nifti_image_read("TestAsciiImage.nia",1); PrintTest("Read/Write Ascii image", reloaded_image == 0,NIFTITEST_FALSE,&Errors); nifti_image_free(reference_image); nifti_image_free(reloaded_image); } { enum { NUM_FILE_NAMES=8 }; const char * FILE_NAMES[NUM_FILE_NAMES]={ "myimage", "myimage.tif", "myimage.tif.gz", "myimage.nii", "myimage.img.gz", ".nii", ".myhiddenimage", ".myhiddenimage.nii" }; const char * KNOWN_FILE_BASENAMES[NUM_FILE_NAMES]={ "myimage", "myimage.tif", "myimage.tif.gz", "myimage", "myimage", "", ".myhiddenimage", ".myhiddenimage" }; const int KNOWN_nifti_validfilename[NUM_FILE_NAMES]={ 1, 1, 1, 1, 1, 0, 1, 1 }; const int KNOWN_nifti_is_complete_filename[NUM_FILE_NAMES]={ 0, 0, 0, 1, 1, 0, 0, 1 }; unsigned int fni; for(fni=0;fnidata != 0, NIFTITEST_FALSE,&Errors); znzclose(f); nifti_image_free(nim); } /* * call various functions from nifti_stats */ printf("\n\nTOTAL ERRORS=%d\n",Errors); return Errors; } nifti_clib-3.0.1/niftilib/nifti_tester002.c000066400000000000000000000017411371325713600205150ustar00rootroot00000000000000/* * nifti_test2 -- this exercises a particular bug, whereby nifti_copy_nim_info was * not working correctly, which left the copy of an image pointing to the same * extension list, which could cause all sorts of grief. */ #include int main (int argc, char *argv[]) { if (argc > 1) { printf("The test program takes no arguments: %s", argv[0]); return EXIT_FAILURE; } /* * create a 'dummy' image */ nifti_image *i1 = nifti_simple_init_nim(); nifti_image *i2; /* * add an extension to the dummy */ static char ext[] = "THIS IS A TEST"; nifti_add_extension(i1,ext,sizeof(ext),NIFTI_ECODE_COMMENT); /* * make a new nim from the dummy */ i2 = nifti_copy_nim_info(i1); /* * if the bug isn't fixed in niftilib, the second nifti_image_free * will fail because both nims point to the same extensions. With gcc * this will abort inside the standard library */ nifti_image_free(i1); nifti_image_free(i2); return 0; } nifti_clib-3.0.1/packaging/000077500000000000000000000000001371325713600155515ustar00rootroot00000000000000nifti_clib-3.0.1/packaging/DevPackage.template000066400000000000000000000011021371325713600212720ustar00rootroot00000000000000[Setup] Version=__major_version__ AppName=nifticlib AppVersion=__full_version__ AppVerName=nifticlib __full_version__ MenuName=nifticlib Description=Niftilib is a set of i/o libraries for reading and writing files in the NIfTI-1 data format. NIfTI-1 is a binary file format for storing medical image data, e.g. magnetic resonance image (MRI) and functional MRI (fMRI) brain images. Url=http://niftilib.sourceforge.net/ License=LICENSE Readme=README [Files] bin=\bin\ include=\include\ lib=\lib\ [Icons] Website=http://niftilib.sourceforge.net nifti_clib-3.0.1/packaging/nifticlib.spec000066400000000000000000000026541371325713600203770ustar00rootroot00000000000000Name: nifticlib Summary: Niftilib C library Version: 1.1.0 Release: 1 License: Public Domain Group: Applications/Scientific Source: %{name}-%{version}.tar.gz #Patch1: nifticlib.patch URL: http://niftilib.sourceforge.net/ BuildRoot: %{_tmppath}/%{name}-%{version}-root Packager: Andy Loening #Requires: openssl BuildRequires: cmake %description Nifticlib is a set of C i/o libraries for reading and writing files in the nifti-1 data format. nifti-1 is a binary file format for storing medical image data, e.g. magnetic resonance image (MRI) and functional MRI (fMRI) brain images. %package devel Summary: static libraries and header files for nifticlib development Group: Development/Libraries Requires: nifticlib = %{version} %description devel The nifticlib-devel package contains the header files and static libraries necessary for developing programs that make use of the nifticlib library. %prep %setup -q %build cmake -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=%{_prefix} -DNIFTI_INSTALL_INCLUDE_DIR=%{_prefix}/include/nifti . make %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT ## hack to get this to work for x86_64 %if "%{?_lib}" == "lib64" mv $RPM_BUILD_ROOT/usr/lib $RPM_BUILD_ROOT/%{_libdir} %endif %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc README %{_libdir}/* #%{_datadir}/doc/* %files devel %defattr(-,root,root) %{_bindir}/* %{_includedir}/* nifti_clib-3.0.1/real_easy/000077500000000000000000000000001371325713600155715ustar00rootroot00000000000000nifti_clib-3.0.1/real_easy/Demonstrations.md000066400000000000000000000034141371325713600211260ustar00rootroot00000000000000# Demonstration Examples This directory contains stand-alone demonstrations of common ways to include `nifti_clib` integration with your tools. These examples assume a modern ( > 3.0 ) cmake approach. See https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right for details. ```bash git clone https://github.com/NIFTI-Imaging/nifti_clib.git mkdir -p build-nifti_clib cd build-nifti_clib cmake ../nifti_clib make -j 2 ctest mkdir ../build-stand-alone cd ../build-stand-alone export STAND_ALONE_SOURCE_DIR=../nifti_clib/real_easy/stand_alone_app cmake -DNIFTI_DIR:PATH=../build-nifti_clib ${STAND_ALONE_SOURCE_DIR} make ``` ## As an external separately built package If `nifti_clib` (3.0.0 or greater) is installed as part of your distribution (via homebrew/debian/rpm/tgz etc), or as an independent build, then the most convenient way to include nifti support is with the `find_package` support demonstrated in the `stand_alone_app` directory. ## As in integrated part of the current project In this example the `nifti_clib` source code is built as an integral part of our package, and is very tightly integrated. The `parent_project_demo` directory shows how to accomplish the tight integration. For the integrated example, it is recommended that the tight integration use a prefix related to your parent project so that future symbol collisions are avoided. - If you download the `nifti_clib` sourcecode inside your source tree, be sure to add `nifti_clib` to the `.gitignore` to ensure that it does not accidently get commited to your source tree. ```bash git clone https://github.com/NIFTI-Imaging/nifti_clib.git mkdir -p build-test-integrated-demo cd build-test-integrated-demo cmake ../nifti_clib/real_easy/parent_project_demo make ``` nifti_clib-3.0.1/real_easy/minimal_example_of_downstream_usage/000077500000000000000000000000001371325713600250455ustar00rootroot00000000000000nifti_clib-3.0.1/real_easy/minimal_example_of_downstream_usage/CMakeLists.txt000066400000000000000000000022251371325713600276060ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.11.0 FATAL_ERROR) project(PARENTDEMO VERSION 0.0.0.1 DESCRIPTION "A demonstration of how to incorporate nifti as a dependency" LANGUAGES C) # Try to find a system version of nifti find_package(NIFTI 3) if(NOT NIFTI_FOUND) set(DOWNLOAD_TEST_DATA OFF) include(FetchContent) FetchContent_Declare( nifti_clib GIT_REPOSITORY https://github.com/NIFTI-Imaging/nifti_clib.git GIT_TAG master # or v3.0.0, or ) if("${CMAKE_VERSION}" VERSION_LESS_EQUAL "3.14") FetchContent_GetProperties(nifti_clib) if(NOT nifti_clib_POPULATED) set(FETCHCONTENT_QUIET OFF) message(STATUS "Downloading nifti_clib from github ... please wait") FetchContent_Populate( nifti_clib ) message(STATUS "download complete.") add_subdirectory(${nifti_clib_SOURCE_DIR} ${nifti_clib_BINARY_DIR}) endif() else() FetchContent_MakeAvailable(nifti_clib) endif() endif() # Example of linking project executables against nifti_clib defined targets add_executable(parent_exe src/parent_project_exe.c) target_link_libraries(parent_exe PRIVATE NIFTI::nifticdf)nifti_clib-3.0.1/real_easy/minimal_example_of_downstream_usage/src/000077500000000000000000000000001371325713600256345ustar00rootroot00000000000000nifti_clib-3.0.1/real_easy/minimal_example_of_downstream_usage/src/parent_project_exe.c000066400000000000000000000003361371325713600316620ustar00rootroot00000000000000/* A simple program to test linkage against the nifticdf package */ #include "nifticdf.h" int main() { double input= 7.0; const double output = alnrel(&input); return (output > 0.0) ? EXIT_SUCCESS: EXIT_FAILURE ; } nifti_clib-3.0.1/real_easy/parent_project_demo/000077500000000000000000000000001371325713600216145ustar00rootroot00000000000000nifti_clib-3.0.1/real_easy/parent_project_demo/.gitignore000066400000000000000000000000251371325713600236010ustar00rootroot00000000000000nifti_clib_download/ nifti_clib-3.0.1/real_easy/parent_project_demo/CMakeLists.txt000066400000000000000000000147761371325713600243730ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.11.0 FATAL_ERROR) set(PARENTDEMO_MAX_VALIDATED_CMAKE_VERSION "3.13.2") if("${CMAKE_VERSION}" VERSION_LESS_EQUAL "${PARENTDEMO_MAX_VALIDATED_CMAKE_VERSION}") # As of 2018-12-04 NIFTI has been validated to build with cmake version 3.13.1 new policies. # Set and use the newest cmake policies that are validated to work set(PARENTDEMO_CMAKE_POLICY_VERSION "${CMAKE_VERSION}") else() set(PARENTDEMO_CMAKE_POLICY_VERSION "${PARENTDEMO_MAX_VALIDATED_CMAKE_VERSION}") endif() cmake_policy(VERSION ${PARENTDEMO_CMAKE_POLICY_VERSION}) macro(set_if_not_defined var defaultvalue) # Macro allowing to set a variable to its default value if not already defined. # The default value is set with: # (1) if set, the value environment variable . # (2) if set, the value of local variable variable . # (3) if none of the above, the value passed as a parameter. # Setting the optional parameter 'OBFUSCATE' will display 'OBFUSCATED' instead of the real value. set(_obfuscate FALSE) foreach(arg ${ARGN}) if(arg STREQUAL "OBFUSCATE") set(_obfuscate TRUE) endif() endforeach() if(DEFINED ENV{${var}} AND NOT DEFINED ${var}) set(_value "$ENV{${var}}") if(_obfuscate) set(_value "OBFUSCATED") endif() message(STATUS "Setting '${var}' variable with environment variable value '${_value}'") set(${var} $ENV{${var}}) endif() if(NOT DEFINED ${var}) set(_value "${defaultvalue}") if(_obfuscate) set(_value "OBFUSCATED") endif() message(STATUS "Setting '${var}' variable with default value '${_value}'") set(${var} "${defaultvalue}") endif() endmacro() set(PARENTDEMO_HOMEPAGE_URL "https://nifti-imaging.github.io") project(PARENTDEMO VERSION 0.0.0.1 DESCRIPTION "A demonstration of how to pull in nifti as a subdirectory" LANGUAGES C) set( SILLYDEMO_LIBRARY_PROPERTIES BUILD_SHARED_LIBS TRUE POSITION_INDEPENDENT_CODE TRUE VERSION 0.1.2 SOVERSION 4.5.6) set( SILLYDEMONIFTI_INSTALL_RUNTIME_DIR mybin ) set( SILLYDEMONIFTI_INSTALL_LIBRARY_DIR mysharedlibs ) set( SILLYDEMONIFTI_INSTALL_ARCHIVE_DIR mystaticlibs ) set( SILLYDEMO_INSTALL_INCLUDE_DIR myincludes) find_package(ZLIB REQUIRED) set(SILLYDEMOZLIB_LIBRARIES ${ZLIB_LIBRARIES}) set(SILLYDEMO_TARGETS "SillyDemoTargets") ### STEP 1 -- set build configuration items to override nifti_clib defaults set( USE_NIFTI2_CODE ON CACHE BOOL "Do not build NIFTI2 provided by NIFTI" FORCE ) set( USE_FSL_CODE ON CACHE BOOL "Do not build FSL provided by NIFTI" FORCE ) set( USE_CIFTI_CODE ON CACHE BOOL "Do not build CIFTI provided by NIFTI" FORCE ) set( USE_NIFTICDF_CODE ON CACHE BOOL "Do not build NIFTICDF provided by NIFTI" FORCE ) set( NIFTI_USE_PACKAGING OFF CACHE BOOL "Do not use packaging from nifti when included as part of another package" FORCE ) set( NIFTI_BUILD_APPLICATIONS ON CACHE BOOL "Do not build applications provided by NIFTI" FORCE ) # Testing is not compatible with SILLYDEMO at the moment set( NIFTI_BUILD_TESTING ON CACHE BOOL "Do not build nifit testing applications" FORCE) add_definitions(-DHAVE_ZLIB) set(NIFTI_INSTALL_EXPORT_NAME SILLYDEMOTargets CACHE STRING "Set the nifti package export target name " FORCE) set(NIFTI_PACKAGE_PREFIX "${SILLYDEMO_TARGETS}" CACHE STRING "Set the nifti package prefix" FORCE) set(NIFTI_LIBRARY_PROPERTIES ${SILLYDEMO_LIBRARY_PROPERTIES} CACHE STRING "Set the nifti library properties to match SILLYDEMO" FORCE) set(NIFTI_INSTALL_RUNTIME_DIR "${SILLYDEMONIFTI_INSTALL_RUNTIME_DIR}" CACHE PATH "Set nifti install binaries directory" FORCE) set(NIFTI_INSTALL_LIBRARY_DIR "${SILLYDEMONIFTI_INSTALL_LIBRARY_DIR}" CACHE PATH "Set nifti install dynamic libraries directory" FORCE) set(NIFTI_INSTALL_ARCHIVE_DIR "${SILLYDEMONIFTI_INSTALL_ARCHIVE_DIR}" CACHE PATH "Set nifti install dynamic libraries directory" FORCE) set(NIFTI_INSTALL_INCLUDE_DIR "${SILLYDEMO_INSTALL_INCLUDE_DIR}/Utilities") set(NIFTI_ZLIB_LIBRARIES ${SILLYDEMOZLIB_LIBRARIES} CACHE STRING "Set the zlib library associated with SILLYDEMO" FORCE) ### STEP 2 -- fetch nifti_clib immediately at configuration time, so add_subdirectory can be used. include(FetchContent) # If new or changed data is needed, add that data to the https://github.com/NIFTI-Imaging/nifti-test-data repo # make a new release, and then update the URL and hash (shasum -a 256 ). FetchContent_Declare( fetch_nifti_clib_git_repo GIT_REPOSITORY https://github.com/NIFTI-Imaging/nifti_clib.git GIT_TAG master # or v3.0.0, or SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/nifti_clib_download # <- not standard, remove this line to download in binary tree ) FetchContent_GetProperties(fetch_nifti_clib_git_repo) if(NOT fetch_nifti_clib_git_repo) set(FETCHCONTENT_QUIET OFF) message(STATUS "Downloading nifti_clib from github ... please wait") FetchContent_Populate( fetch_nifti_clib_git_repo ) message(STATUS "download complete.") add_subdirectory(${fetch_nifti_clib_git_repo_SOURCE_DIR} ${fetch_nifti_clib_git_repo_BINARY_DIR}) endif() ### STEP 3 -- The reset of the parent project code that depends on nifti_clib add_subdirectory(src) ### STEP 4 -- Export the SILLYDEMO.cmake files ####################################################################### # CMake itself and can use some CMake facilities for creating the package files. # This allows for find_package(SILLYDEMO 0.0.1 NO_MODULE) to work for pulling in # SILLYDEMO libraries into an external project (including SILLYDEMOniftiio.a etc...) include(CMakePackageConfigHelpers) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/SILLYDEMO/SILLYDEMOConfigVersion.cmake" VERSION ${SILLYDEMO_VERSION} COMPATIBILITY AnyNewerVersion ) export(EXPORT SILLYDEMOTargets FILE "${CMAKE_CURRENT_BINARY_DIR}/SILLYDEMO/SILLYDEMOTargets.cmake" NAMESPACE ${SILLYDEMO_PACKAGE_PREFIX}NIFTI:: ) configure_file(cmake/SILLYDEMOConfig.cmake "${CMAKE_CURRENT_BINARY_DIR}/SILLYDEMO/SILLYDEMOConfig.cmake" COPYONLY ) set(ConfigPackageLocation lib/cmake/SILLYDEMO) install(EXPORT SILLYDEMOTargets FILE SILLYDEMOTargets.cmake NAMESPACE ${SILLYDEMO_PACKAGE_PREFIX}NIFTI:: DESTINATION ${ConfigPackageLocation} ) install(FILES cmake/SILLYDEMOConfig.cmake "${CMAKE_CURRENT_BINARY_DIR}/SILLYDEMO/SILLYDEMOConfigVersion.cmake" DESTINATION ${ConfigPackageLocation} COMPONENT Development ) nifti_clib-3.0.1/real_easy/parent_project_demo/cmake/000077500000000000000000000000001371325713600226745ustar00rootroot00000000000000nifti_clib-3.0.1/real_easy/parent_project_demo/cmake/SILLYDEMOConfig.cmake000066400000000000000000000000731371325713600263650ustar00rootroot00000000000000include("${CMAKE_CURRENT_LIST_DIR}/SILLYDEMOTargets.cmake")nifti_clib-3.0.1/real_easy/parent_project_demo/src/000077500000000000000000000000001371325713600224035ustar00rootroot00000000000000nifti_clib-3.0.1/real_easy/parent_project_demo/src/CMakeLists.txt000066400000000000000000000001711371325713600251420ustar00rootroot00000000000000add_executable(parent_exe parent_project_exe.c) target_link_libraries(parent_exe PUBLIC ${NIFTI_PACKAGE_PREFIX}nifticdf) nifti_clib-3.0.1/real_easy/parent_project_demo/src/parent_project_exe.c000066400000000000000000000003361371325713600264310ustar00rootroot00000000000000/* A simple program to test linkage against the nifticdf package */ #include "nifticdf.h" int main() { double input= 7.0; const double output = alnrel(&input); return (output > 0.0) ? EXIT_SUCCESS: EXIT_FAILURE ; } nifti_clib-3.0.1/real_easy/stand_alone_app/000077500000000000000000000000001371325713600207205ustar00rootroot00000000000000nifti_clib-3.0.1/real_easy/stand_alone_app/CMakeLists.txt000066400000000000000000000013411371325713600234570ustar00rootroot00000000000000# This trivial CMakeLists.txt file stands alone from the # rest of the build system. It is intended represent # a down-stream package that depends on the NIFIT # development libraries. # # to configure this stand-alone package # run "cmake -DNIFTI_DIR:PATH=${build_or_install_dir}/NIFTI ${THIS_SOURCE_DIR}" # cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) project(real_easy) find_package(NIFTI 2.1.0 CONFIG REQUIRED) add_executable(real_easy nifti1_read_write.c) target_link_libraries(real_easy PUBLIC ${NIFTI_PACKAGE_PREFIX}NIFTI::${NIFTI_PACKAGE_PREFIX}niftiio) add_executable(nifti_cdf_program nifti_cdf_program.c) target_link_libraries(nifti_cdf_program PUBLIC ${NIFTI_PACKAGE_PREFIX}NIFTI::${NIFTI_PACKAGE_PREFIX}nifticdf) nifti_clib-3.0.1/real_easy/stand_alone_app/clib_01_read_write.c000066400000000000000000000055201371325713600245040ustar00rootroot00000000000000/* ---------------------------------------------------------------------- * A basic example to read/write a nifti dataset (e.g. cp command). * * compile example (consider -pedantic or -Wall): * * gcc -o clib_01_read_write clib_01_read_write.c \ * -I../include -L../lib -lniftiio -lznz -lz -lm * * R Reynolds 14 Apr 2009 *---------------------------------------------------------------------- */ #include #include int show_help( void ) { printf( "clib_01_read_write: short exmample of reading/writing NIfTI\n" "\n" " This program is to demonstrate how to read a NIfTI dataset,\n" " set output filenames and write a NIfTI dataset, all via the\n" " standard NIfTI C library.\n" "\n" " basic usage: clib_01_read_write -input FILE_IN -output FILE_OUT\n" "\n" " options: -help : show this help\n" " -verb LEVEL : the verbose level to LEVEL\n" "\n"); return 0; } int main(int argc, char * argv[]) { nifti_image * nim=NULL; char * fin=NULL, * fout=NULL; int ac; if( argc < 2 ) return show_help(); /* typing '-help' is sooo much work */ /* process user options: 4 are valid presently */ for( ac = 1; ac < argc; ac++ ) { if( ! strncmp(argv[ac], "-h", 2) ) { return show_help(); } else if( ! strcmp(argv[ac], "-input") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -input\n"); return 1; } fin = argv[ac]; /* no string copy, just pointer assignment */ } else if( ! strcmp(argv[ac], "-output") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -output\n"); return 2; } fout = argv[ac]; } else if( ! strcmp(argv[ac], "-verb") ) { if( ++ac >= argc ) { fprintf(stderr, "** missing argument for -verb\n"); return 2; } nifti_set_debug_level(atoi(argv[ac])); } else { fprintf(stderr,"** invalid option, '%s'\n", argv[ac]); return 1; } } if( !fin ) { fprintf(stderr, "** missing option '-input'\n"); return 1; } if( !fout ) { fprintf(stderr, "** missing option '-output'\n"); return 1; } /* read input dataset, including data */ nim = nifti_image_read(fin, 1); if( !nim ) { fprintf(stderr,"** failed to read NIfTI image from '%s'\n", fin); return 2; } /* assign nifti_image fname/iname pair, based on output filename (request to 'check' image and 'set_byte_order' here) */ if( nifti_set_filenames(nim, fout, 1, 1) ) return 1; /* if we get here, write the output dataset */ nifti_image_write( nim ); /* and clean up memory */ nifti_image_free( nim ); return 0; } nifti_clib-3.0.1/real_easy/stand_alone_app/nifti1_read_write.c000066400000000000000000000274411371325713600244730ustar00rootroot00000000000000/********************************************************************* * * Very simple code snippets to read/write nifti1 files * This code is placed in the public domain. * * If you are the type who doesn't want to use a file format unless * you can write your own i/o code in less than 30minutes, this * example is for you. * * This code does not deal with wrong-endian data, compressed data, * the new qform/sform orientation codes, parsing filenames, volume- * wise or timecourse-wise data access or any of a million other very useful * things that are in the niftilib i/o reference libraries. * We encourage people to use the niftilib reference library and send * feedback/suggestions, see http://niftilib.sourceforge.net/ * But, if that is too much to tackle and you just want to jump in, this * code is a starting point. * This code was written for maximum readability, not for the greatest * coding style. * * * If you are already a little familiar with reading/writing Analyze * files of some flavor, and maybe even have some of your own code, here * are the most important things to be aware of in transitioning to nifti1: * * 1. nii vs .hdr/.img * nifti1 datasets can be stored either in .hdr/.img pairs of files * or in 1 .nii file. In a .nii file the data will start at the byte * specified by the vox_offset field, which will be 352 if no extensions * have been added. And, nifti1 really does like that magic field set * to "n+1" for .nii and "ni1" for .img/.hdr * * 2. scaling * nifti1 datasets can contain a scaling factor. You need to check the * scl_slope field and if that isn't 0, scale your data by * Y * scl_slope + scl_inter * * 3. extensions * nifti1 datasets can have some "extension data" stuffed after the * regular header. You can just ignore it, but, be aware that a * .hdr file may be longer than 348 bytes, and, in a .nii file * you can't just jump to byte 352, you need to use the vox_offset * field to get the start of the image data. * * 4. new datatypes * nifti1 added a few new datatypes that were not in the Analyze 7.5 * format from which nifti1 is derived. If you're just working with * your own data this is not an issue but if you get a foreign nifti1 * file, be aware of exotic datatypes like DT_COMPLEX256 and mundane * things like DT_UINT16. * * 5. other stuff * nifti1 really does like the dim[0] field set to the number of * dimensions of the dataset. Other Analyze flavors might not * have been so scrupulous about that. * nifti1 has a bunch of other new fields such as intent codes, * qform/sform, etc. but, if you just want to get your hands on * the data blob you can ignore these. Example use of these fields * is in the niftilib reference libraries. * * * * To compile: * You need to put a copy of the nifti1.h header file in this directory. * It can be obtained from the NIFTI homepage http://nifti.nimh.nih.gov/ * or from the niftilib SourceForge site http://niftilib.sourceforge.net/ * * cc -o nifti1_read_write nifti1_read_write.c * * * To run: * nifti1_read_write -w abc.nii abc.nii * nifti1_read_write -r abc.nii abc.nii * * * The read method is hardcoded to read float32 data. To change * to your datatype, just change the line: * typedef float MY_DATATYPE; * * The write method is hardcoded to write float32 data. To change * to your datatype, change the line: * typedef float MY_DATATYPE; * and change the lines: * hdr.datatype = NIFTI_TYPE_FLOAT32; * hdr.bitpix = 32; * * * Written by Kate Fissell, University of Pittsburgh, May 2005. * *********************************************************************/ #include #include #include #include "nifti1.h" typedef float MY_DATATYPE; #define MIN_HEADER_SIZE 348 #define NII_HEADER_SIZE 352 /********************************************************************** * * read_nifti_file * **********************************************************************/ static int read_nifti_file(char * const hdr_file, char * const data_file) { nifti_1_header hdr; FILE *fp; int ret,i; double total; MY_DATATYPE *data=NULL; /********** open and read header */ fp = fopen(hdr_file,"r"); if (fp == NULL) { fprintf(stderr, "\nError opening header file %s\n",hdr_file); exit(1); } ret = fread(&hdr, MIN_HEADER_SIZE, 1, fp); if (ret != 1) { fprintf(stderr, "\nError reading header file %s\n",hdr_file); exit(1); } fclose(fp); /********** print a little header information */ fprintf(stderr, "\n%s header information:",hdr_file); fprintf(stderr, "\nXYZT dimensions: %d %d %d %d",hdr.dim[1],hdr.dim[2],hdr.dim[3],hdr.dim[4]); fprintf(stderr, "\nDatatype code and bits/pixel: %d %d",hdr.datatype,hdr.bitpix); fprintf(stderr, "\nScaling slope and intercept: %.6f %.6f",hdr.scl_slope,hdr.scl_inter); fprintf(stderr, "\nByte offset to data in datafile: %ld",(long)(hdr.vox_offset)); fprintf(stderr, "\n"); /********** open the datafile, jump to data offset */ fp = fopen(data_file,"r"); if (fp == NULL) { fprintf(stderr, "\nError opening data file %s\n",data_file); exit(1); } ret = fseek(fp, (long)(hdr.vox_offset), SEEK_SET); if (ret != 0) { fprintf(stderr, "\nError doing fseek() to %ld in data file %s\n",(long)(hdr.vox_offset), data_file); exit(1); } /********** allocate buffer and read first 3D volume from data file */ data = (MY_DATATYPE *) malloc(sizeof(MY_DATATYPE) * hdr.dim[1]*hdr.dim[2]*hdr.dim[3]); if (data == NULL) { fprintf(stderr, "\nError allocating data buffer for %s\n",data_file); exit(1); } ret = fread(data, sizeof(MY_DATATYPE), hdr.dim[1]*hdr.dim[2]*hdr.dim[3], fp); if (ret != hdr.dim[1]*hdr.dim[2]*hdr.dim[3]) { fprintf(stderr, "\nError reading volume 1 from %s (%d)\n",data_file,ret); exit(1); } fclose(fp); /********** scale the data buffer */ if (hdr.scl_slope != 0) { for (i=0; i
\n",argv[0]); exit(1); } if (!strncmp(argv[1],"-r",2)) do_read=1; else if (!strncmp(argv[1],"-w",2)) do_write=1; else { fprintf(stderr, "\nUsage: %s <-r|-w>
\n",argv[0]); exit(1); } hdr_file = argv[2]; data_file = argv[3]; /********** do the simple read or write */ if (do_read) read_nifti_file(hdr_file, data_file); else if (do_write) write_nifti_file(hdr_file, data_file); exit(0); } nifti_clib-3.0.1/real_easy/stand_alone_app/nifti_cdf_program.c000066400000000000000000000003451371325713600245420ustar00rootroot00000000000000/* A simple program to test linkage against the nifticdf package */ #include "nifticdf.h" int main() { double input= 7.0; double output; output = alnrel(&input); return (output > 0.0) ? EXIT_SUCCESS: EXIT_FAILURE ; } nifti_clib-3.0.1/znzlib/000077500000000000000000000000001371325713600151355ustar00rootroot00000000000000nifti_clib-3.0.1/znzlib/CMakeLists.txt000066400000000000000000000013671371325713600177040ustar00rootroot00000000000000set(NIFTI_ZNZLIB_NAME ${NIFTI_PACKAGE_PREFIX}znz) add_nifti_library(${NIFTI_ZNZLIB_NAME} znzlib.c ) target_link_libraries( ${NIFTI_ZNZLIB_NAME} PUBLIC ${NIFTI_ZLIB_LIBRARIES} ) set_target_properties( ${NIFTI_ZNZLIB_NAME} PROPERTIES PUBLIC_HEADER ${CMAKE_CURRENT_LIST_DIR}/znzlib.h ) target_compile_definitions(${NIFTI_ZNZLIB_NAME} PUBLIC ${ZNZ_COMPILE_DEF}) # Set library version if building shared libs. if(BUILD_SHARED_LIBS) get_lib_version_vars("znzlib_version.h" ZNZLIB_VERSION ZNZLIB_MAJOR_VERSION) set_target_properties(${NIFTI_ZNZLIB_NAME} PROPERTIES ${NIFTI_LIBRARY_PROPERTIES} VERSION ${ZNZLIB_VERSION} SOVERSION ${ZNZLIB_MAJOR_VERSION} ) endif() install_nifti_target(${NIFTI_ZNZLIB_NAME}) nifti_clib-3.0.1/znzlib/Makefile000066400000000000000000000005701371325713600165770ustar00rootroot00000000000000include ../Makefile PROJNAME = znzlib INCFLAGS = $(ZLIB_INC) SRCS=znzlib.c OBJS=znzlib.o depend: $(RM) -f depend.mk $(MAKE) depend.mk depend.mk: $(CC) $(DEPENDFLAGS) $(INCFLAGS) $(SRCS) >> depend.mk lib: libznz.a znzlib.o: znzlib.c znzlib.h $(CC) -c $(CFLAGS) $(USEZLIB) $(INCFLAGS) $< libznz.a: $(OBJS) $(AR) -r libznz.a $(OBJS) $(RANLIB) $@ include depend.mk nifti_clib-3.0.1/znzlib/znzlib.c000066400000000000000000000201031371325713600166050ustar00rootroot00000000000000/** \file znzlib.c \brief Low level i/o interface to compressed and noncompressed files. Written by Mark Jenkinson, FMRIB This library provides an interface to both compressed (gzip/zlib) and uncompressed (normal) file IO. The functions are written to have the same interface as the standard file IO functions. To use this library instead of normal file IO, the following changes are required: - replace all instances of FILE* with znzFile - change the name of all function calls, replacing the initial character f with the znz (e.g. fseek becomes znzseek) one exception is rewind() -> znzrewind() - add a third parameter to all calls to znzopen (previously fopen) that specifies whether to use compression (1) or not (0) - use znz_isnull rather than any (pointer == NULL) comparisons in the code for znzfile types (normally done after a return from znzopen) NB: seeks for writable files with compression are quite restricted */ #include "znzlib.h" #include "znzlib_version.h" /* znzlib.c (zipped or non-zipped library) ***** This code is released to the public domain. ***** ***** Author: Mark Jenkinson, FMRIB Centre, University of Oxford ***** ***** Date: September 2004 ***** ***** Neither the FMRIB Centre, the University of Oxford, nor any of ***** ***** its employees imply any warranty of usefulness of this software ***** ***** for any purpose, and do not assume any liability for damages, ***** ***** incidental or otherwise, caused by any use of this document. ***** */ /* Note extra argument (use_compression) where use_compression==0 is no compression use_compression!=0 uses zlib (gzip) compression */ znzFile znzopen(const char *path, const char *mode, int use_compression) { znzFile file; file = (znzFile) calloc(1,sizeof(struct znzptr)); if( file == NULL ){ fprintf(stderr,"** ERROR: znzopen failed to alloc znzptr\n"); return NULL; } file->nzfptr = NULL; #ifdef HAVE_ZLIB file->zfptr = NULL; if (use_compression) { file->withz = 1; if((file->zfptr = gzopen(path,mode)) == NULL) { free(file); file = NULL; } } else { #endif file->withz = 0; if((file->nzfptr = fopen(path,mode)) == NULL) { free(file); file = NULL; } #ifdef HAVE_ZLIB } #endif return file; } #ifdef COMPILE_NIFTIUNUSED_CODE znzFile znzdopen(int fd, const char *mode, int use_compression) { znzFile file; file = (znzFile) calloc(1,sizeof(struct znzptr)); if( file == NULL ){ fprintf(stderr,"** ERROR: znzdopen failed to alloc znzptr\n"); return NULL; } #ifdef HAVE_ZLIB if (use_compression) { file->withz = 1; file->zfptr = gzdopen(fd,mode); file->nzfptr = NULL; } else { #endif file->withz = 0; #ifdef HAVE_FDOPEN file->nzfptr = fdopen(fd,mode); #endif #ifdef HAVE_ZLIB file->zfptr = NULL; }; #endif return file; } #endif int Xznzclose(znzFile * file) { int retval = 0; if (*file!=NULL) { #ifdef HAVE_ZLIB if ((*file)->zfptr!=NULL) { retval = gzclose((*file)->zfptr); } #endif if ((*file)->nzfptr!=NULL) { retval = fclose((*file)->nzfptr); } free(*file); *file = NULL; } return retval; } /* we already assume ints are 4 bytes */ #undef ZNZ_MAX_BLOCK_SIZE #define ZNZ_MAX_BLOCK_SIZE (1<<30) size_t znzread(void* buf, size_t size, size_t nmemb, znzFile file) { size_t remain = size*nmemb; char * cbuf = (char *)buf; unsigned n2read; int nread; if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) { /* gzread/write take unsigned int length, so maybe read in int pieces (noted by M Hanke, example given by M Adler) 6 July 2010 [rickr] */ while( remain > 0 ) { n2read = (remain < ZNZ_MAX_BLOCK_SIZE) ? remain : ZNZ_MAX_BLOCK_SIZE; nread = gzread(file->zfptr, (void *)cbuf, n2read); if( nread < 0 ) return nread; /* returns -1 on error */ remain -= nread; cbuf += nread; /* require reading n2read bytes, so we don't get stuck */ if( nread < (int)n2read ) break; /* return will be short */ } /* warn of a short read that will seem complete */ if( remain > 0 && remain < size ) fprintf(stderr,"** znzread: read short by %u bytes\n",(unsigned)remain); return nmemb - remain/size; /* return number of members processed */ } #endif return fread(buf,size,nmemb,file->nzfptr); } size_t znzwrite(const void* buf, size_t size, size_t nmemb, znzFile file) { size_t remain = size*nmemb; const char * cbuf = (const char *)buf; unsigned n2write; int nwritten; if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) { while( remain > 0 ) { n2write = (remain < ZNZ_MAX_BLOCK_SIZE) ? remain : ZNZ_MAX_BLOCK_SIZE; nwritten = gzwrite(file->zfptr, (const void *)cbuf, n2write); /* gzread returns 0 on error, but in case that ever changes... */ if( nwritten < 0 ) return nwritten; remain -= nwritten; cbuf += nwritten; /* require writing n2write bytes, so we don't get stuck */ if( nwritten < (int)n2write ) break; } /* warn of a short write that will seem complete */ if( remain > 0 && remain < size ) fprintf(stderr,"** znzwrite: write short by %u bytes\n",(unsigned)remain); return nmemb - remain/size; /* return number of members processed */ } #endif return fwrite(buf,size,nmemb,file->nzfptr); } znz_off_t znzseek(znzFile file, znz_off_t offset, int whence) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return (znz_off_t) gzseek(file->zfptr,offset,whence); #endif return fseek(file->nzfptr,offset,whence); } int znzrewind(znzFile stream) { if (stream==NULL) { return 0; } #ifdef HAVE_ZLIB /* On some systems, gzrewind() fails for uncompressed files. Use gzseek(), instead. 10, May 2005 [rickr] if (stream->zfptr!=NULL) return gzrewind(stream->zfptr); */ if (stream->zfptr!=NULL) return (int)gzseek(stream->zfptr, 0L, SEEK_SET); #endif rewind(stream->nzfptr); return 0; } znz_off_t znztell(znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return (znz_off_t) gztell(file->zfptr); #endif return ftell(file->nzfptr); } int znzputs(const char * str, znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return gzputs(file->zfptr,str); #endif return fputs(str,file->nzfptr); } #ifdef COMPILE_NIFTIUNUSED_CODE char * znzgets(char* str, int size, znzFile file) { if (file==NULL) { return NULL; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return gzgets(file->zfptr,str,size); #endif return fgets(str,size,file->nzfptr); } int znzflush(znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return gzflush(file->zfptr,Z_SYNC_FLUSH); #endif return fflush(file->nzfptr); } int znzeof(znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return gzeof(file->zfptr); #endif return feof(file->nzfptr); } int znzputc(int c, znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return gzputc(file->zfptr,c); #endif return fputc(c,file->nzfptr); } int znzgetc(znzFile file) { if (file==NULL) { return 0; } #ifdef HAVE_ZLIB if (file->zfptr!=NULL) return gzgetc(file->zfptr); #endif return fgetc(file->nzfptr); } #if !defined (WIN32) int znzprintf(znzFile stream, const char *format, ...) { int retval=0; char *tmpstr; va_list va; if (stream==NULL) { return 0; } va_start(va, format); #ifdef HAVE_ZLIB if (stream->zfptr!=NULL) { int size; /* local to HAVE_ZLIB block */ size = strlen(format) + 1000000; /* overkill I hope */ tmpstr = (char *)calloc(1, size); if( tmpstr == NULL ){ fprintf(stderr,"** ERROR: znzprintf failed to alloc %d bytes\n", size); return retval; } vsprintf(tmpstr,format,va); retval=gzprintf(stream->zfptr,"%s",tmpstr); free(tmpstr); } else #endif { retval=vfprintf(stream->nzfptr,format,va); } va_end(va); return retval; } #endif #endif nifti_clib-3.0.1/znzlib/znzlib.h000066400000000000000000000066651371325713600166330ustar00rootroot00000000000000#ifndef _ZNZLIB_H_ #define _ZNZLIB_H_ /* znzlib.h (zipped or non-zipped library) ***** This code is released to the public domain. ***** ***** Author: Mark Jenkinson, FMRIB Centre, University of Oxford ***** ***** Date: September 2004 ***** ***** Neither the FMRIB Centre, the University of Oxford, nor any of ***** ***** its employees imply any warranty of usefulness of this software ***** ***** for any purpose, and do not assume any liability for damages, ***** ***** incidental or otherwise, caused by any use of this document. ***** */ /* This library provides an interface to both compressed (gzip/zlib) and uncompressed (normal) file IO. The functions are written to have the same interface as the standard file IO functions. To use this library instead of normal file IO, the following changes are required: - replace all instances of FILE* with znzFile - change the name of all function calls, replacing the initial character f with the znz (e.g. fseek becomes znzseek) - add a third parameter to all calls to znzopen (previously fopen) that specifies whether to use compression (1) or not (0) - use znz_isnull rather than any (pointer == NULL) comparisons in the code NB: seeks for writable files with compression are quite restricted */ /*=================*/ #ifdef __cplusplus extern "C" { #endif /*=================*/ #include #include #include #include /* include optional check for HAVE_FDOPEN here, from deleted config.h: uncomment the following line if fdopen() exists for your compiler and compiler options */ /* #define HAVE_FDOPEN */ #if defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64) || defined(_MSVC) || defined(_MSC_VER) #include #define fseek _fseeki64 #define ftell _ftelli64 #define znz_off_t long long #elif defined(__APPLE__) || defined(__FreeBSD__) #define znz_off_t off_t #else #include #include #define znz_off_t off_t #endif #ifdef HAVE_ZLIB #if defined(ITKZLIB) && !defined(ITK_USE_SYSTEM_ZLIB) #include "itk_zlib.h" #else #include "zlib.h" #endif #endif struct znzptr { int withz; FILE* nzfptr; #ifdef HAVE_ZLIB gzFile zfptr; #endif } ; /* the type for all file pointers */ typedef struct znzptr * znzFile; /* int znz_isnull(znzFile f); */ /* int znzclose(znzFile f); */ #define znz_isnull(f) ((f) == NULL) #define znzclose(f) Xznzclose(&(f)) /* Note extra argument (use_compression) where use_compression==0 is no compression use_compression!=0 uses zlib (gzip) compression */ znzFile znzopen(const char *path, const char *mode, int use_compression); #ifdef COMPILE_NIFTIUNUSED_CODE znzFile znzdopen(int fd, const char *mode, int use_compression); #endif int Xznzclose(znzFile * file); size_t znzread(void* buf, size_t size, size_t nmemb, znzFile file); size_t znzwrite(const void* buf, size_t size, size_t nmemb, znzFile file); znz_off_t znzseek(znzFile file, znz_off_t offset, int whence); int znzrewind(znzFile stream); znz_off_t znztell(znzFile file); int znzputs(const char *str, znzFile file); #ifdef COMPILE_NIFTIUNUSED_CODE char * znzgets(char* str, int size, znzFile file); int znzputc(int c, znzFile file); int znzgetc(znzFile file); #if !defined(WIN32) int znzprintf(znzFile stream, const char *format, ...); #endif #endif /*=================*/ #ifdef __cplusplus } #endif /*=================*/ #endif nifti_clib-3.0.1/znzlib/znzlib_version.h000066400000000000000000000012611371325713600203630ustar00rootroot00000000000000/* NOTE: When changing version consider the impact on versions in nifti2_io_version.h nifti1_io_version.h nifticdf_version.h and znzlib.h */ #define ZNZLIB_VERSION_MAJOR 3 #define ZNZLIB_VERSION_MINOR 0 #define ZNZLIB_VERSION_PATCH 0 /* main string macros: ZNZLIB_VERSION and ZNZLIB_SOURCE_VERSION */ #define ZNZLIB_VERSION_TO_STRING(x) ZNZLIB_VERSION_TO_STRING0(x) #define ZNZLIB_VERSION_TO_STRING0(x) #x #define ZNZLIB_VERSION \ ZNZLIB_VERSION_TO_STRING(ZNZLIB_VERSION_MAJOR) \ "." ZNZLIB_VERSION_TO_STRING(ZNZLIB_VERSION_MINOR) \ "." ZNZLIB_VERSION_TO_STRING(ZNZLIB_VERSION_PATCH) #define ZNZLIB_SOURCE_VERSION "znz version " ZNZLIB_VERSION