[med-svn] [dcm2niix] 01/04: New upstream version 1.0.20170624

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Thu Jul 13 18:14:18 UTC 2017


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to branch debian/master
in repository dcm2niix.

commit 32a51618658343319bcb9c056b1a6bec13c6d12b
Author: Ghislain Antony Vaillant <ghisvail at gmail.com>
Date:   Thu Jul 13 18:59:50 2017 +0100

    New upstream version 1.0.20170624
---
 .gitmodules                        |   3 +
 .travis.yml                        |   5 ++
 COMPILE.md                         |  26 +++---
 README.md                          |  18 +++-
 SuperBuild/External-OPENJPEG.cmake |   6 +-
 SuperBuild/External-YAML-CPP.cmake |   6 +-
 SuperBuild/SuperBuild.cmake        |  22 +++--
 console/CMakeLists.txt             |   9 ++
 console/main_console.cpp           |   5 +-
 console/nii_dicom.cpp              | 176 +++++++++++++++++++++++++------------
 console/nii_dicom.h                |  14 +--
 console/nii_dicom_batch.cpp        |  85 +++++++++++++-----
 console/nii_foreign.cpp            |   1 -
 13 files changed, 252 insertions(+), 124 deletions(-)

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..511dc74
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "dcm_qa"]
+	path = dcm_qa
+	url = http://github.com/neurolabusc/dcm_qa
diff --git a/.travis.yml b/.travis.yml
index 79f8259..80f4058 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,8 +11,13 @@ matrix:
     - os: osx
       env: TARGET=mac
 
+before_install:
+  - git submodule update --init --depth=3 dcm_qa
+
 script:
   - mkdir build && cd build && cmake -DBATCH_VERSION=ON -DUSE_OPENJPEG=ON .. && make && cd -
+  - export PATH=$PWD/build/bin:$PATH
+  - cd dcm_qa; ./batch.sh
 
 before_deploy:
   - export DATE=`date +%-d-%b-%Y`
diff --git a/COMPILE.md b/COMPILE.md
index ed69b48..46ce378 100644
--- a/COMPILE.md
+++ b/COMPILE.md
@@ -12,7 +12,7 @@ The text below generally describes how to build dcm2niix using the [GCC](https:/
 You can also build the software without C-make. The easiest way to do this is to run the function "make" from the "console" folder. Note that this only creates the default version of dcm2niix, not the optional batch version described above. The make command simply calls the g++ compiler, and if you want you can tune this for your build. In essence, the make function simply calls
 
 ```
-g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp  -o dcm2niix -DmyDisableOpenJPEG -DmyDisableJasper
+g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp nii_foreign.cpp -o dcm2niix -DmyDisableOpenJPEG -DmyDisableJasper
 ```
 
 The following sub-sections list how you can modify this basic recipe for your needs.
@@ -21,7 +21,7 @@ The following sub-sections list how you can modify this basic recipe for your ne
  If we have zlib, we can use it (-lz) and disable [miniz](https://code.google.com/p/miniz/) (-myDisableMiniZ)
 
 ```
-g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -dead_strip -o dcm2niix -lz -DmyDisableMiniZ
+g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -dead_strip -o dcm2niix -lz -DmyDisableMiniZ
 ```
 
 ##### MINGW BUILD
@@ -29,7 +29,7 @@ g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cp
 If you use the (obsolete) compiler MinGW on Windows you will want to include the rare libgcc libraries with your executable so others can use it. Here I also demonstrate the optional "-DmyDisableZLib" to remove zip support.
 
 ```
-g++ -O3 -s -DmyDisableOpenJPEG -DmyDisableZLib -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -o dcm2niix  -static-libgcc
+g++ -O3 -s -DmyDisableOpenJPEG -DmyDisableZLib -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -o dcm2niix -static-libgcc
 ```
 
 ##### DISABLING CLASSIC JPEG
@@ -37,7 +37,7 @@ g++ -O3 -s -DmyDisableOpenJPEG -DmyDisableZLib -I. main_console.cpp nii_dicom.cp
 DICOM images can be stored as either raw data or compressed using one of many formats as described by the [transfer syntaxes](https://www.nitrc.org/plugins/mwiki/index.php/dcm2nii:MainPage#Transfer_Syntaxes_and_Compressed_Images). One of the compressed formats is the lossy classic JPEG format (which is separate from and predates the lossy JPEG 2000 format). This software comes with the [NanoJPEG](http://keyj.emphy.de/nanojpeg/) library to handle these images. However, you can use the `my [...]
 
 ```
-g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp  -o dcm2niix -DmyDisableClassicJPEG -DmyDisableOpenJPEG -DmyDisableJasper
+g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp nii_foreign.cpp -o dcm2niix -DmyDisableClassicJPEG -DmyDisableOpenJPEG -DmyDisableJasper
 ```
 
 ##### USING LIBJPEG-TURBO TO DECODE CLASSIC JPEG
@@ -45,7 +45,7 @@ g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp nifti1_io_co
 By default, classic JPEG images will be decoded using the [compact NanoJPEG decoder](http://keyj.emphy.de/nanojpeg/). However, the compiler directive `myTurboJPEG`  will create an executable based on the [libjpeg-turbo](http://www.libjpeg-turbo.org) library. This library is a faster decoder and is the standard for many Linux distributions. On the other hand, the lossy classic JPEG is rarely used for DICOM images, so this compilation has extra dependencies and can result in a larger execu [...]
 
 ```
-g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp  -o dcm2niix -DmyDisableOpenJPEG -DmyDisableJasper -DmyTurboJPEG -I/opt/libjpeg-turbo/include /opt/libjpeg-turbo/lib/libturbojpeg.a
+g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp nii_foreign.cpp -o dcm2niix -DmyDisableOpenJPEG -DmyDisableJasper -DmyTurboJPEG -I/opt/libjpeg-turbo/include /opt/libjpeg-turbo/lib/libturbojpeg.a
 ```
 
 ##### JPEG2000 BUILD
@@ -59,23 +59,23 @@ g++ -dead_strip -O3 -I. main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp ni
 You should then be able to run then run:
 
 ```
-g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp  jpg_0XC3.cpp ujpeg.cpp -o dcm2niix -lopenjp2
+g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -o dcm2niix -lopenjp2
 ```
 
 But in my experience this works best if you explicitly tell the software how to find the libraries, so your compile will probably look like one of these two options:
 
 ```
-g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -o dcm2niix  -I/usr/local/include /usr/local/lib/libopenjp2.a
+g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -o dcm2niix -I/usr/local/include/openjpeg-2.1 /usr/local/lib/libopenjp2.a
 ```
 
 ```
-g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -o dcm2niix  -I/usr/local/lib /usr/local/lib/libopenjp2.a
+g++ -O3 -dead_strip -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -o dcm2niix -I/usr/local/lib /usr/local/lib/libopenjp2.a
 ```
 
  If you want to build this with JPEG2000 decompression support using Jasper: You will need to have the Jasper (http://www.ece.uvic.ca/~frodo/jasper/) and libjpeg (http://www.ijg.org) libraries installed which for Linux users may be as easy as running 'sudo apt-get install libjasper-dev' (otherwise, see http://www.ece.uvic.ca/~frodo/jasper/#doc). You can then run:
 
 ```
-g++ -O3 -DmyDisableOpenJPEG -DmyEnableJasper -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp  -s -o dcm2niix -ljasper -ljpeg
+g++ -O3 -DmyDisableOpenJPEG -DmyEnableJasper -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -s -o dcm2niix -ljasper -ljpeg
 ```
 
 ##### VISUAL STUDIO BUILD
@@ -84,7 +84,7 @@ This software can be compiled with VisualStudio 2015. This example assumes the c
 
 ```
 vcvarsall amd64
-cl /EHsc main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp -DmyDisableOpenJPEG -DmyDisableJasper /odcm2niix
+cl /EHsc main_console.cpp nii_dicom.cpp jpg_0XC3.cpp ujpeg.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp nii_foreign.cpp -DmyDisableOpenJPEG -DmyDisableJasper /odcm2niix
 ```
 
 ##### OSX BUILD WITH BOTH 32 AND 64-BIT SUPPORT
@@ -93,11 +93,11 @@ Building command line version universal binary from OSX 64 bit system:
  This requires a C compiler. With a terminal, change directory to the 'conosle' folder and run the following:
 
 ```
-g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -dead_strip -arch i386 -o dcm2niix32
+g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -dead_strip -arch i386 -o dcm2niix32
 ```
 
 ```
-g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp -dead_strip -o dcm2niix64
+g++ -O3 -DmyDisableOpenJPEG -I. main_console.cpp nii_dicom.cpp nifti1_io_core.cpp nii_ortho.cpp nii_dicom_batch.cpp jpg_0XC3.cpp ujpeg.cpp nii_foreign.cpp -dead_strip -o dcm2niix64
 ```
 
 ```
@@ -140,4 +140,4 @@ CXXFLAGS = -DmyUseCOut -DWX_PRECOMP ....
  i.) For a full refresh
 rm clipboard
 rm *.o
-make
+make
\ No newline at end of file
diff --git a/README.md b/README.md
index 075ff2f..43bf91f 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,16 @@ This software is open source. The bulk of the code is covered by the BSD license
 
 ## Versions
 
+23-June-2017
+ - [Ensure slice timing always encoded for Siemens EPI](https://github.com/neurolabusc/dcm_qa/issues/4#issuecomment-310707906)
+ - [Integrates validation](https://github.com/neurolabusc/dcm_qa)
+ - JSON fix (InstitutionName -> InstitutionAddress)
+
+21-June-2017
+ - Read DICOM header in 1Mb segments rather than loading whole file : reduces ram usage and [faster for systems with slow io](https://github.com/rordenlab/dcm2niix/issues/104).
+ - Report [TotalReadoutTime](https://github.com/rordenlab/dcm2niix/issues/98).
+ - Fix JPEG2000 support in [Superbuild](https://github.com/rordenlab/dcm2niix/issues/105).
+
 28-May-2017
  - Remove all derived images from [Philips DTI series](http://www.nitrc.org/forum/message.php?msg_id=21025).
  - Provide some [Siemens EPI sequence details](https://github.com/rordenlab/dcm2niix/issues).
@@ -152,7 +162,13 @@ make
 
 **optional building with OpenJPEG:**
 
-Support for JPEG2000 using OpenJPEG is optional. To build with OpenJPEG change the cmake command to `cmake -DUSE_OPENJPEG=ON ..`
+Support for JPEG2000 using OpenJPEG is optional. To build with OpenJPEG change the cmake command to `cmake -DUSE_OPENJPEG=ON ..`:
+
+```bash
+mkdir build && cd build
+cmake -DUSE_OPENJPEG=ON ..
+make
+```
 
 **optional batch processing version:**
 
diff --git a/SuperBuild/External-OPENJPEG.cmake b/SuperBuild/External-OPENJPEG.cmake
index 38f7301..5cfdb51 100644
--- a/SuperBuild/External-OPENJPEG.cmake
+++ b/SuperBuild/External-OPENJPEG.cmake
@@ -1,4 +1,4 @@
-set(OPENJPEG_TAG 151e322) # version openjepg-2.1
+set(OPENJPEG_TAG  v2.1-static) # version v2.1-static
 
 ExternalProject_Add(openjpeg
     GIT_REPOSITORY "${git_protocol}://github.com/ningfei/openjpeg.git"
@@ -9,7 +9,7 @@ ExternalProject_Add(openjpeg
         -Wno-dev
         --no-warn-unused-cli
         -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-        -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}
+        -DCMAKE_INSTALL_PREFIX=${DEP_INSTALL_DIR}
 )
 
-set(OPENJPEG_DIR ${CMAKE_BINARY_DIR}/lib/openjpeg-2.1)
+set(OPENJPEG_DIR ${DEP_INSTALL_DIR}/lib/openjpeg-2.1)
diff --git a/SuperBuild/External-YAML-CPP.cmake b/SuperBuild/External-YAML-CPP.cmake
index ada7d8f..305faaf 100644
--- a/SuperBuild/External-YAML-CPP.cmake
+++ b/SuperBuild/External-YAML-CPP.cmake
@@ -1,4 +1,4 @@
-set(YAML-CPP_TAG 5c3cb09) # version yaml-cpp-0.5.3
+set(YAML-CPP_TAG yaml-cpp-0.5.3) # version yaml-cpp-0.5.3
 
 ExternalProject_Add(yaml-cpp
     GIT_REPOSITORY "${git_protocol}://github.com/ningfei/yaml-cpp.git"
@@ -9,7 +9,7 @@ ExternalProject_Add(yaml-cpp
         -Wno-dev
         --no-warn-unused-cli
         -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-        -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}
+        -DCMAKE_INSTALL_PREFIX=${DEP_INSTALL_DIR}
 )
 
-set(YAML-CPP_DIR ${CMAKE_BINARY_DIR}/lib/cmake/yaml-cpp)
+set(YAML-CPP_DIR ${DEP_INSTALL_DIR}/lib/cmake/yaml-cpp)
diff --git a/SuperBuild/SuperBuild.cmake b/SuperBuild/SuperBuild.cmake
index 969b95a..4c37373 100644
--- a/SuperBuild/SuperBuild.cmake
+++ b/SuperBuild/SuperBuild.cmake
@@ -15,6 +15,7 @@ endif()
 # Basic CMake build settings
 set(CMAKE_BUILD_TYPE "Release" CACHE STRING
     "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
+set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS  "Debug;Release;RelWithDebInfo;MinSizeRel")
 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
 
 option(USE_STATIC_RUNTIME "Use static runtime" ON)
@@ -30,6 +31,14 @@ include(ExternalProject)
 
 set(DEPENDENCIES)
 
+option(INSTALL_DEPENDENCIES "Optionally install built dependent libraries (OpenJPEG and yaml-cpp) for future use." OFF)
+
+if(INSTALL_DEPENDENCIES)
+    set(DEP_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
+else()
+    set(DEP_INSTALL_DIR ${CMAKE_BINARY_DIR})
+endif()
+
 if(USE_OPENJPEG)
     message("-- Build with OpenJPEG: ${USE_OPENJPEG}")
 
@@ -77,6 +86,7 @@ ExternalProject_Add(console
         -Wno-dev
         --no-warn-unused-cli
         -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
+        -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}
         -DUSE_STATIC_RUNTIME:BOOL=${USE_STATIC_RUNTIME}
         -DUSE_SYSTEM_ZLIB:BOOL=${USE_SYSTEM_ZLIB}
         -DUSE_SYSTEM_TURBOJPEG:BOOL=${USE_SYSTEM_TURBOJPEG}
@@ -87,23 +97,11 @@ ExternalProject_Add(console
         # yaml-cpp
         -DBATCH_VERSION:BOOL=${BATCH_VERSION}
         -DYAML-CPP_DIR:PATH=${YAML-CPP_DIR}
-        -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}
 )
 
 install(DIRECTORY ${CMAKE_BINARY_DIR}/bin/ DESTINATION bin
         USE_SOURCE_PERMISSIONS)
 
-# Install dependent libraries for future use
-if(BUILD_OPENJPEG OR BUILD_YAML-CPP)
-    option(INSTALL_DEPENDENCIES "Optionally install dependent libraries (OpenJPEG and yaml-cpp) for future use." OFF)
-    if(INSTALL_DEPENDENCIES)
-        install(DIRECTORY ${CMAKE_BINARY_DIR}/include/ DESTINATION include
-                USE_SOURCE_PERMISSIONS)
-        install(DIRECTORY ${CMAKE_BINARY_DIR}/lib/ DESTINATION lib
-                USE_SOURCE_PERMISSIONS)
-    endif()
-endif()
-
 option(BUILD_DOCS "Build documentation (manpages)" OFF)
 if(BUILD_DOCS)
     add_subdirectory(docs)
diff --git a/console/CMakeLists.txt b/console/CMakeLists.txt
index 8e98cdc..54d9749 100644
--- a/console/CMakeLists.txt
+++ b/console/CMakeLists.txt
@@ -80,6 +80,15 @@ if(USE_OPENJPEG)
     option(OpenJPEG_DIR "Path to OpenJPEG configuration file" "")
 
     find_package(OpenJPEG)
+
+    if(WIN32)
+        if(BUILD_SHARED_LIBS)
+            add_definitions(-DOPJ_EXPORTS)
+        else()
+            add_definitions(-DOPJ_STATIC)
+        endif()
+    endif()
+
     target_include_directories(dcm2niix PRIVATE ${OPENJPEG_INCLUDE_DIRS})
     target_link_libraries(dcm2niix ${OPENJPEG_LIBRARIES})
 else ()
diff --git a/console/main_console.cpp b/console/main_console.cpp
index 6434aa1..fa65b95 100644
--- a/console/main_console.cpp
+++ b/console/main_console.cpp
@@ -78,10 +78,11 @@ void showHelp(const char * argv[], struct TDCMopts opts) {
     if (opts.isAnonymizeBIDS) bidsCh = 'y'; else bidsCh = 'n';
     printf("   -ba : anonymize BIDS (y/n, default %c)\n", bidsCh);
     #ifdef mySegmentByAcq
-    printf("  -f : filename (%%a=antenna  (coil) number, %%c=comments, %%d=description, %%e echo number, %%f=folder name, %%i ID of patient, %%j seriesInstanceUID, %%k studyInstanceUID, %%m=manufacturer, %%n=name of patient, %%p=protocol, %%q=sequence number, %%s=series number, %%t=time, %%u=acquisition number, %%z sequence name; default '%s')\n",opts.filename);
+     #define kQstr " %%q=sequence number,"
     #else
-    printf("  -f : filename (%%a=antenna  (coil) number, %%c=comments, %%d=description, %%e echo number, %%f=folder name, %%i ID of patient, %%j seriesInstanceUID, %%k studyInstanceUID, %%m=manufacturer, %%n=name of patient, %%p=protocol, %%s=series number, %%t=time, %%u=acquisition number, %%z sequence name; default '%s')\n",opts.filename);
+     #define kQstr ""
     #endif
+    printf("  -f : filename (%%a=antenna  (coil) number, %%c=comments, %%d=description, %%e echo number, %%f=folder name, %%i ID of patient, %%j seriesInstanceUID, %%k studyInstanceUID, %%m=manufacturer, %%n=name of patient, %%p=protocol,%s %%s=series number, %%t=time, %%u=acquisition number, %%x study ID; %%z sequence name; default '%s')\n", kQstr, opts.filename);
     printf("  -h : show help\n");
     printf("  -i : ignore derived, localizer and 2D images (y/n, default n)\n");
     printf("  -t : text notes includes private patient details (y/n, default n)\n");
diff --git a/console/nii_dicom.cpp b/console/nii_dicom.cpp
index 667426a..624bf4d 100644
--- a/console/nii_dicom.cpp
+++ b/console/nii_dicom.cpp
@@ -50,7 +50,7 @@
     #include <jasper/jasper.h>
 #endif
 #ifndef myDisableOpenJPEG
-    #include <openjpeg.h>
+    #include "openjpeg.h"
 
 #ifdef myEnableJasper
 ERROR: YOU CAN NOT COMPILE WITH myEnableJasper AND NOT myDisableOpenJPEG OPTIONS SET SIMULTANEOUSLY
@@ -621,6 +621,7 @@ struct TDICOMdata clear_dicom_data() {
         d.angulation[i] = 0.0f;
         d.xyzMM[i] = 1;
     }
+    d.CSA.sliceTiming[0] = -1.0f; //impossible value denotes not known
     d.CSA.numDti = 0;
     for (int i=0; i < 5; i++)
         d.xyzDim[i] = 1;
@@ -637,15 +638,18 @@ struct TDICOMdata clear_dicom_data() {
     strcpy(d.sequenceName, "");
     strcpy(d.scanningSequence, "");
     strcpy(d.sequenceVariant, "");
-    strcpy(d.manufacturersModelName, "N/A");
+    strcpy(d.manufacturersModelName, "");
     strcpy(d.procedureStepDescription, "");
     strcpy(d.institutionName, "");
+    strcpy(d.referringPhysicianName, "");
     strcpy(d.institutionAddress, "");
     strcpy(d.deviceSerialNumber, "");
     strcpy(d.softwareVersions, "");
     strcpy(d.seriesInstanceUID, "");
+    strcpy(d.studyID, "");
     strcpy(d.studyInstanceUID, "");
     strcpy(d.bodyPartExamined,"");
+    d.phaseEncodingLines = 0;
     d.patientPositionSequentialRepeats = 0;
     d.isHasPhase = false;
     d.isHasMagnitude = false;
@@ -660,11 +664,14 @@ struct TDICOMdata clear_dicom_data() {
     d.TE = 0.0;
     d.TI = 0.0;
     d.flipAngle = 0.0;
+    d.bandwidthPerPixelPhaseEncode = 0.0;
     d.fieldStrength = 0.0;
     d.numberOfDynamicScans = 0;
     d.echoNum = 1;
     d.echoTrainLength = 0;
+    d.phaseEncodingSteps = 0;
     d.coilNum = 1;
+    d.accelFactPE = 0.0;
     d.patientPositionNumPhilips = 0;
     d.imageBytes = 0;
     d.intenScale = 1;
@@ -722,7 +729,6 @@ void dcmStrDigitsOnly(char* lStr) {
     for (int i = 0; i < (int) len; i++)
         if (!isdigit(lStr[i]) )
             lStr[i] = ' ';
-
 }
 
 void dcmStr(int lLength, unsigned char lBuffer[], char* lOut) {
@@ -964,11 +970,9 @@ int readCSAImageHeader(unsigned char *buff, int lLength, struct TCSAdata *CSA, i
     for (int lT = 1; lT <= lnTag; lT++) {
         memcpy(&tagCSA, &buff[lPos], sizeof(tagCSA)); //read tag
         lPos +=sizeof(tagCSA);
-
         // Storage order is always little-endian, so byte-swap required values if necessary
         if (!littleEndianPlatform())
             nifti_swap_4bytes(1, &tagCSA.nitems);
-
         if (isVerbose > 1) //extreme verbosity: show every CSA tag
         	printMessage("%d CSA of %s %d\n",lPos, tagCSA.name, tagCSA.nitems);
         if (tagCSA.nitems > 0) {
@@ -1001,19 +1005,16 @@ int readCSAImageHeader(unsigned char *buff, int lLength, struct TCSAdata *CSA, i
             else if (strcmp(tagCSA.name, "BandwidthPerPixelPhaseEncode") == 0)
                 CSA->bandwidthPerPixelPhaseEncode = csaMultiFloat (&buff[lPos], 3,lFloats, &itemsOK);
             else if ((strcmp(tagCSA.name, "MosaicRefAcqTimes") == 0) && (tagCSA.nitems > 3)  ){
-//#ifdef _MSC_VER
 				float * sliceTimes = (float *)malloc(sizeof(float) * (tagCSA.nitems + 1));
-//#else
-//				float sliceTimes[tagCSA.nitems + 1];
-//#endif
                 csaMultiFloat (&buff[lPos], tagCSA.nitems,sliceTimes, &itemsOK);
                 float maxTimeValue, minTimeValue, timeValue1;
-                for (int z = 0; z < kMaxDTI4D; z++)
-        			dti4D->S[z].sliceTiming = -1.0;
-
-                if (itemsOK <= kMaxDTI4D)
+                for (int z = 0; z < kMaxEPI3D; z++)
+        			CSA->sliceTiming[z] = -1.0;
+        		if (itemsOK <= kMaxEPI3D) {
                 	for (int z = 1; z <= itemsOK; z++)
-                		dti4D->S[z-1].sliceTiming = sliceTimes[z];
+                		CSA->sliceTiming[z-1] = sliceTimes[z];
+                } else
+                	printError("Please increase kMaxEPI3D and recompile\n");
                 CSA->multiBandFactor = 1;
                 timeValue1 = sliceTimes[1];
                 int nTimeZero = 0;
@@ -1090,6 +1091,15 @@ int readCSAImageHeader(unsigned char *buff, int lLength, struct TCSAdata *CSA, i
     return EXIT_SUCCESS;
 } // readCSAImageHeader()
 
+void dcmMultiShorts (int lByteLength, unsigned char lBuffer[], int lnShorts, uint16_t *lShorts, bool littleEndian) {
+//read array of unsigned shorts US http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html
+    if ((lnShorts < 1) || (lByteLength != (lnShorts * 2))) return;
+    memcpy(&lShorts[0], (uint16_t *)&lBuffer[0], lByteLength);
+    bool swap = (littleEndian != littleEndianPlatform());
+    if (swap)
+    	nifti_swap_2bytes(lnShorts, &lShorts[0]);
+} //dcmMultiShorts()
+
 void dcmMultiFloat (int lByteLength, char lBuffer[], int lnFloats, float *lFloats) {
     //warning: lFloats indexed from 1! will fill lFloats[1]..[nFloats]
     if ((lnFloats < 1) || (lByteLength < 1)) return;
@@ -1316,10 +1326,8 @@ struct TDICOMdata  nii_readParRec (char * parname, int isVerbose, struct TDTI4D
     char *p = fgets (buff, LINESZ, fp);
     bool isIntenScaleVaries = false;
     bool isIndexSequential = true;
-    for (int i = 0; i < kMaxDTI4D; i++) {
+    for (int i = 0; i < kMaxDTI4D; i++)
         dti4D->S[i].V[0] = -1.0;
-        dti4D->S[i].sliceTiming = -1.0;
-    }
     //d.dti4D = (TDTI *)malloc(kMaxDTI4D * sizeof(TDTI));
     while (p) {
         if (strlen(buff) < 1)
@@ -2455,14 +2463,12 @@ int isDICOMfile(const char * fname) { //0=NotDICOM, 1=DICOM, 2=Maybe(not Part 10
 } //isDICOMfile()
 
 struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, struct TDTI4D *dti4D) {
-//struct TDICOMdata readDICOMv(char * fname, bool isVerbose, int compressFlag) {
 	struct TDICOMdata d = clear_dicom_data();
     strcpy(d.protocolName, ""); //erase dummy with empty
     strcpy(d.protocolName, ""); //erase dummy with empty
     strcpy(d.seriesDescription, ""); //erase dummy with empty
     strcpy(d.sequenceName, ""); //erase dummy with empty
     //do not read folders - code specific to GCC (LLVM/Clang seems to recognize a small file size)
-
     struct stat s;
     if( stat(fname,&s) == 0 ) {
         if( !(s.st_mode & S_IFREG) ){
@@ -2489,31 +2495,42 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
         printMessage( "File too small to be a DICOM image %s\n", fname);
 		return d;
 	}
+	//Since size of DICOM header is unknown, we will load it in 1mb segments
+	//This uses less RAM and makes is faster for computers with slow disk access
+	//Benefit is largest for 4D images.
+	//To disable caching and load entire file to RAM, compile with "-dmyLoadWholeFileToReadHeader"
+	//To implement the segments, we define these variables:
+	// fileLen = size of file in bytes
+	// MaxBufferSz = maximum size of buffer in bytes
+	// Buffer = array with n elements, where n is smaller of fileLen or MaxBufferSz
+	// lPos = position in Buffer (indexed from 0), 0..(n-1)
+	// lFileOffset = offset of Buffer in file: true file position is lOffset+lPos (initially 0)
+	#ifdef myLoadWholeFileToReadHeader
+	size_t MaxBufferSz = fileLen;
+	#else
+	size_t MaxBufferSz = 1000000; //ideally size of DICOM header, but this varies from 2D to 4D files
+	#endif
+	if (MaxBufferSz > fileLen)
+		MaxBufferSz = fileLen;
+	long lFileOffset = 0;
 	fseek(file, 0, SEEK_SET);
 	//Allocate memory
-	unsigned char *buffer=(unsigned char *)malloc(fileLen+1);
+	unsigned char *buffer=(unsigned char *)malloc(MaxBufferSz+1);
 	if (!buffer) {
 		printError( "Memory exhausted!");
         fclose(file);
 		return d;
 	}
 	//Read file contents into buffer
-	size_t sz = fread(buffer, 1, fileLen, file);
-	fclose(file);
-	if (sz < fileLen) {
-         printError("Only loaded %zu of %ld bytes for %s\n", sz, fileLen, fname);
+	size_t sz = fread(buffer, 1, MaxBufferSz, file);
+	if (sz < MaxBufferSz) {
+         printError("Only loaded %zu of %zu bytes for %s\n", sz, MaxBufferSz, fname);
+         fclose(file);
          return d;
     }
-	//bool isPart10prefix = true; //assume 132 byte header http://nipy.bic.berkeley.edu/nightly/nibabel/doc/dicom/dicom_intro.html
-    //if ((buffer[128] != 'D') || (buffer[129] != 'I')  || (buffer[130] != 'C') || (buffer[131] != 'M')) {
-    //    if ((buffer[0] != 8) || (buffer[1] != 0)  || (buffer[2] != 5) || (buffer[3] != 0)){
-    //		free (buffer);
-    //    	return d;
-    //	}
-    //	isPart10prefix = false; //no 132 byte header, not a valid part 10 file http://fileformats.archiveteam.org/wiki/DICOM
-    //	d.isExplicitVR = false;
-    //	//printWarning("Not a valid part 10 DICOM (missing 'DICM' signature): %s\n", fname);
-    //}
+	#ifdef myLoadWholeFileToReadHeader
+	fclose(file);
+	#endif
     //DEFINE DICOM TAGS
 #define  kUnused 0x0001+(0x0001 << 16 )
 #define  kStart 0x0002+(0x0000 << 16 )
@@ -2528,6 +2545,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
 #define  kManufacturer 0x0008+(0x0070 << 16 )
 #define  kInstitutionName 0x0008+(0x0080 << 16 )
 #define  kInstitutionAddress 0x0008+(0x0081 << 16 )
+#define  kReferringPhysicianName 0x0008+(0x0090 << 16 )
 #define  kSeriesDescription 0x0008+(0x103E << 16 ) // '0008' '103E' 'LO' 'SeriesDescription'
 #define  kManufacturersModelName 0x0008+(0x1090 << 16 )
 #define  kDerivationDescription 0x0008+(0x2111 << 16 )
@@ -2556,6 +2574,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
 #define  kRadionuclidePositronFraction  0x0018+(0x1076<< 16 )
 #define  kGantryTilt  0x0018+(0x1120  << 16 )
 #define  kXRayExposure  0x0018+(0x1152  << 16 )
+#define  kAcquisitionMatrix  0x0018+(0x1310  << 16 ) //US
 #define  kFlipAngle  0x0018+(0x1314  << 16 )
 #define  kInPlanePhaseEncodingDirection  0x0018+(0x1312<< 16 ) //CS
 #define  kPatientOrient  0x0018+(0x5100<< 16 )    //0018,5100. patient orientation - 'HFS'
@@ -2564,12 +2583,14 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
 #define  kDiffusionDirectionGEX  0x0019+(0x10BB<< 16 ) //DS
 #define  kDiffusionDirectionGEY  0x0019+(0x10BC<< 16 ) //DS
 #define  kDiffusionDirectionGEZ  0x0019+(0x10BD<< 16 ) //DS
-#define  kStudyInstanceUID 0x0020+(0x000D << 16 )
-#define  kSeriesInstanceUID 0x0020+(0x000E << 16 )
-#define  kPatientPosition 0x0020+(0x0032 << 16 )
+#define  kBandwidthPerPixelPhaseEncode  0x0019+(0x1028<< 16 ) //FD
+#define  kStudyID 0x0020+(0x0010 << 16 )
 #define  kSeriesNum 0x0020+(0x0011 << 16 )
 #define  kAcquNum 0x0020+(0x0012 << 16 )
 #define  kImageNum 0x0020+(0x0013 << 16 )
+#define  kStudyInstanceUID 0x0020+(0x000D << 16 )
+#define  kSeriesInstanceUID 0x0020+(0x000E << 16 )
+#define  kPatientPosition 0x0020+(0x0032 << 16 )
 #define  kOrientationACR 0x0020+(0x0035 << 16 )
 #define  kOrientation 0x0020+(0x0037 << 16 )
 #define  kImagesInAcquisition 0x0020+(0x1002 << 16 ) //IS
@@ -2595,6 +2616,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
 #define  kRealWorldSlope  0x0040+uint32_t(0x9225 << 16 ) //IS dicm2nii's SlopInt_6_9
 #define  kDiffusionBFactorGE  0x0043+(0x1039 << 16 ) //IS dicm2nii's SlopInt_6_9
 #define  kCoilSiemens  0x0051+(0x100F << 16 )
+#define  kImaPATModeText  0x0051+(0x1011 << 16 )
 #define  kLocationsInAcquisition  0x0054+(0x0081 << 16 )
 #define  kDoseCalibrationFactor  0x0054+(0x1322<< 16 )
 #define  kIconImageSequence 0x0088+(0x0200 << 16 )
@@ -2624,7 +2646,6 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
 #define kNest 0xFFFE +(0xE000 << 16 ) //Item follows SQ
 #define  kUnnest 0xFFFE +(0xE00D << 16 ) //ItemDelimitationItem [length defined] http://www.dabsoft.ch/dicom/5/7.5/
 #define  kUnnest2 0xFFFE +(0xE0DD << 16 )//SequenceDelimitationItem [length undefined]
-    dti4D->S[0].sliceTiming = -1.0;
     int nest = 0;
     double zSpacing = -1.0l; //includes slice thickness plus gap
     int locationsInAcquisitionGE = 0;
@@ -2652,13 +2673,27 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
     bool is2005140FSQwarned = false; //for buggy Philips
     bool isAtFirstPatientPosition = false; //for 3d and 4d files: flag is true for slices at same position as first slice
     bool isMosaic = false;
-    int phaseEncodingSteps = 0;
     int patientPositionNum = 0;
     int sqDepth = 0;
     float patientPosition[4] = {NAN, NAN, NAN, NAN}; //used to compute slice direction for Philips 4D
     float patientPositionEndPhilips[4] = {NAN, NAN, NAN, NAN};
     float patientPositionStartPhilips[4] = {NAN, NAN, NAN, NAN};
-    while ((d.imageStart == 0) && ((lPos+8) <  fileLen)) {
+    while ((d.imageStart == 0) && ((lPos+8+lFileOffset) <  fileLen)) {
+    	#ifndef myLoadWholeFileToReadHeader //read one segment at a time
+    	if ((lPos + 128) > MaxBufferSz) { //avoid overreading the file
+    		lFileOffset = lFileOffset + lPos;
+    		if ((lFileOffset+MaxBufferSz) > fileLen)
+    			MaxBufferSz = fileLen - lFileOffset;
+			fseek(file, lFileOffset, SEEK_SET);
+			size_t sz = fread(buffer, 1, MaxBufferSz, file);
+			if (sz < MaxBufferSz) {
+         		printError("Only loaded %zu of %zu bytes for %s\n", sz, MaxBufferSz, fname);
+         		fclose(file);
+         		return d;
+    		}
+			lPos = 0;
+    	}
+    	#endif
         if (d.isLittleEndian)
             groupElement = buffer[lPos] | (buffer[lPos+1] << 8) | (buffer[lPos+2] << 16) | (buffer[lPos+3] << 24);
         else
@@ -2679,8 +2714,6 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
             vr[0] = 'N';
             vr[1] = 'A';
             if (groupElement == kUnnest2) sqDepth--;
-            //if (groupElement == kUnnest2) printMessage("SQend %d\n", sqDepth);
-
             //if (groupElement == kUnnest) geiisBug = false; //don't exit if there is a proprietary thumbnail
             lLength = 4;
         } else if (d.isExplicitVR) {
@@ -2738,7 +2771,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
             d.imageBytes = dcmInt(4,&buffer[lPos-4],d.isLittleEndian);
             //printMessage("compressed data %d-> %ld\n",d.imageBytes, lPos);
             if (d.imageBytes > 128) {
-                d.imageStart = (int)lPos;
+                d.imageStart = (int)lPos + (int)lFileOffset;
             }
         }
         if ((isIconImageSequence) && ((groupElement & 0x0028) == 0x0028 )) groupElement = kUnused; //ignore icon dimensions
@@ -2749,7 +2782,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
             case 	kTransferSyntax: {
                 char transferSyntax[kDICOMStr];
                 dcmStr (lLength, &buffer[lPos], transferSyntax);
-                //printMessage("transfer syntax '%s'\n", transferSyntax);
+                //printMessage("%d transfer syntax>>> '%s'\n", compressFlag, transferSyntax);
                 if (strcmp(transferSyntax, "1.2.840.10008.1.2.1") == 0)
                     ; //default isExplicitVR=true; //d.isLittleEndian=true
                 else if  (strcmp(transferSyntax, "1.2.840.10008.1.2.4.50") == 0) {
@@ -2826,6 +2859,9 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
             case kInstitutionAddress:
             	dcmStr(lLength, &buffer[lPos], d.institutionAddress);
             	break;
+            case kReferringPhysicianName:
+            	dcmStr(lLength, &buffer[lPos], d.referringPhysicianName);
+            	break;
             case 	kComplexImageComponent:
                 d.isHasPhase = (buffer[lPos]=='P') && (toupper(buffer[lPos+1]) == 'H');
                 d.isHasMagnitude = (buffer[lPos]=='M') && (toupper(buffer[lPos+1]) == 'A');
@@ -2893,6 +2929,9 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
                     d.CSA.numDti = 1;
                 }
                 break;
+        	case kBandwidthPerPixelPhaseEncode:
+        		d.bandwidthPerPixelPhaseEncode = dcmFloatDouble(lLength, &buffer[lPos],d.isLittleEndian);
+        		break;
             case kStudyInstanceUID :
                 dcmStr (lLength, &buffer[lPos], d.studyInstanceUID);
                 break;
@@ -2933,6 +2972,9 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
             case 	kInPlanePhaseEncodingDirection:
                 d.phaseEncodingRC = toupper(buffer[lPos]); //first character is either 'R'ow or 'C'ol
                 break;
+            case kStudyID:
+            	dcmStr (lLength, &buffer[lPos], d.studyID);
+            	break;
             case 	kSeriesNum:
                 d.seriesNum =  dcmStrInt(lLength, &buffer[lPos]);
                 break;
@@ -2960,7 +3002,6 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
                 break;
             case 	kXYSpacing:
                 dcmMultiFloat(lLength, (char*)&buffer[lPos], 2, d.xyzMM);
-
                 break;
             case 	kImageComments:
                 dcmStr (lLength, &buffer[lPos], d.imageComments);
@@ -2999,11 +3040,21 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
                 zSpacing = dcmStrFloat(lLength, &buffer[lPos]);
                 break;
             case kPhaseEncodingSteps :
-                phaseEncodingSteps =  dcmStrInt(lLength, &buffer[lPos]);
+                d.phaseEncodingSteps =  dcmStrInt(lLength, &buffer[lPos]);
                 break;
             case kEchoTrainLength :
             	d.echoTrainLength  =  dcmStrInt(lLength, &buffer[lPos]);
-            //	printf(">>>>>>>>>>>>>>>> %d", d.echoTrainLength);
+            	break;
+        	case kAcquisitionMatrix :
+				if (lLength == 8) {
+                	uint16_t acquisitionMatrix[4];
+                	dcmMultiShorts(lLength, &buffer[lPos], 4, &acquisitionMatrix[0],d.isLittleEndian); //slice position
+            		//phaseEncodingLines stored in either image columns or rows
+            		if (acquisitionMatrix[3] > 0)
+            			d.phaseEncodingLines = acquisitionMatrix[3];
+            		if (acquisitionMatrix[2] > 0)
+            			d.phaseEncodingLines = acquisitionMatrix[2];
+            	}
             	break;
             case kFlipAngle :
             	d.flipAngle = dcmStrFloat(lLength, &buffer[lPos]);
@@ -3053,6 +3104,15 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
                         d.coilNum = 0;
                 }
                 break; }
+            case kImaPATModeText : { //e.g. Siemens iPAT x2 listed as "p2"
+            	char accelStr[kDICOMStr];
+                dcmStr (lLength, &buffer[lPos], accelStr);
+                char *ptr;
+                dcmStrDigitsOnly(accelStr);
+                d.accelFactPE = (float)strtof(accelStr, &ptr);
+                if (*ptr != '\0')
+                	d.accelFactPE = 0.0;
+				break; }
             case 	kLocationsInAcquisition :
                 d.locationsInAcquisition = dcmInt(lLength,&buffer[lPos],d.isLittleEndian);
                 break;
@@ -3257,7 +3317,7 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
             case 	kImageStart:
                 //if ((!geiisBug) && (!isIconImageSequence)) //do not exit for proprietary thumbnails
                 if ((d.compressionScheme == kCompressNone ) && (!isIconImageSequence)) //do not exit for proprietary thumbnails
-                    d.imageStart = (int)lPos;
+                    d.imageStart = (int)lPos + (int)lFileOffset;
                 //geiisBug = false;
                 //http://www.dclunie.com/medical-image-faq/html/part6.html
                 //unlike raw data, Encapsulated data is stored as Fragments contained in Items that are the Value field of Pixel Data
@@ -3270,20 +3330,19 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
             case 	kImageStartFloat:
                 d.isFloat = true;
                 if (!isIconImageSequence) //do not exit for proprietary thumbnails
-                    d.imageStart = (int)lPos;
+                    d.imageStart = (int)lPos + (int)lFileOffset;
                 isIconImageSequence = false;
                 break;
             case 	kImageStartDouble:
                 printWarning("Double-precision DICOM conversion untested: please provide samples to developer\n");
                 d.isFloat = true;
                 if (!isIconImageSequence) //do not exit for proprietary thumbnails
-                    d.imageStart = (int)lPos;
+                    d.imageStart = (int)lPos + (int)lFileOffset;
                 isIconImageSequence = false;
                 break;
 
         } //switch/case for groupElement
         } //if nest
-        //#ifdef MY_DEBUG
         if (isVerbose > 1) {
         	if ((lLength > 12) && (lLength < 128)) { //if length is greater than 8 bytes (+4 hdr) the data must be a string [or image data]
         		char tagStr[kDICOMStr];
@@ -3297,12 +3356,11 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
            					|| (tagStr[pos] == '*') || (tagStr[pos] == '|') || (tagStr[pos] == '?'))
             					tagStr[pos] = 'x';
 				}
-            	printMessage(" Tag\t%04x,%04x\tSize=%u\tOffset=%ld\t%s\n",   groupElement & 65535,groupElement>>16, lLength, lPos, tagStr);
+            	printMessage(" Tag\t%04x,%04x\tSize=%u\tOffset=%ld\t%s\n",   groupElement & 65535,groupElement>>16, lLength, lFileOffset+lPos, tagStr);
             	//printMessage(" Tag\t%04x,%04x\tSize=%u\tOffset=%ld\tnest=%d\t%s\n",   groupElement & 65535,groupElement>>16, lLength, lPos, nest, tagStr);
             } else
-            	printMessage(" Tag\t%04x,%04x\tSize=%u\tOffset=%ld\tnest=%d\n",   groupElement & 65535,groupElement>>16, lLength, lPos, nest);
+            	printMessage(" Tag\t%04x,%04x\tSize=%u\tOffset=%ld\tnest=%d\n",   groupElement & 65535,groupElement>>16, lLength, lFileOffset+lPos, nest);
         }   //printMessage(" tag=%04x,%04x length=%u pos=%ld %c%c nest=%d\n",   groupElement & 65535,groupElement>>16, lLength, lPos,vr[0], vr[1], nest);
-        //#endif
         lPos = lPos + (lLength);
         //printMessage("%d\n",d.imageStart);
     } //while d.imageStart == 0
@@ -3367,8 +3425,8 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
         printError("Unable to decode %d-bit images with Transfer Syntax 1.2.840.10008.1.2.4.51, decompress with dcmdjpg\n", d.bitsAllocated);
         d.isValid = false;
     }
-    if ((d.manufacturer == kMANUFACTURER_SIEMENS) && (isMosaic) && (d.CSA.mosaicSlices < 1) && (phaseEncodingSteps > 0) && ((d.xyzDim[1] % phaseEncodingSteps) == 0) && ((d.xyzDim[2] % phaseEncodingSteps) == 0) ) {
-    	d.CSA.mosaicSlices = (d.xyzDim[1] / phaseEncodingSteps) * (d.xyzDim[2] / phaseEncodingSteps);
+    if ((d.manufacturer == kMANUFACTURER_SIEMENS) && (isMosaic) && (d.CSA.mosaicSlices < 1) && (d.phaseEncodingSteps > 0) && ((d.xyzDim[1] % d.phaseEncodingSteps) == 0) && ((d.xyzDim[2] % d.phaseEncodingSteps) == 0) ) {
+    	d.CSA.mosaicSlices = (d.xyzDim[1] / d.phaseEncodingSteps) * (d.xyzDim[2] / d.phaseEncodingSteps);
     	printWarning("Mosaic inferred without CSA header (check number of slices and spatial orientation)\n");
     }
     if ((d.manufacturer == kMANUFACTURER_SIEMENS) && (d.CSA.dtiV[1] < -1.0) && (d.CSA.dtiV[2] < -1.0) && (d.CSA.dtiV[3] < -1.0))
@@ -3410,6 +3468,10 @@ struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, stru
         d.CSA.numDti = 0;
     }
     //d.isValid = false; //debug only - will not create output!
+    #ifndef myLoadWholeFileToReadHeader
+	fclose(file);
+	#endif
+    //printMessage("buffer usage %d  %d  %d\n",d.imageStart, lPos+lFileOffset, MaxBufferSz);
     return d;
 } // readDICOM()
 
@@ -3418,5 +3480,3 @@ struct TDICOMdata readDICOM(char * fname) {
     return readDICOMv(fname, false, 0, &unused);
 } // readDICOM()
 
-
-
diff --git a/console/nii_dicom.h b/console/nii_dicom.h
index 8d1b50a..276ca4d 100644
--- a/console/nii_dicom.h
+++ b/console/nii_dicom.h
@@ -38,8 +38,9 @@ extern "C" {
 	#define kCCsuf " CompilerNA" //unknown compiler!
 #endif
 
- #define kDCMvers "v1.0.20170528" kDCMsuf kCCsuf
+ #define kDCMvers "v1.0.20170624" kDCMsuf kCCsuf
 
+static const int kMaxEPI3D = 1024; //maximum number of EPI images in Siemens Mosaic
 static const int kMaxDTI4D = 4096; //maximum number of DTI directions for 4D (Philips) images, also maximum number of 3D slices for Philips 3D and 4D images
 #define kDICOMStr 64
 #define kMANUFACTURER_UNKNOWN  0
@@ -58,7 +59,6 @@ static const int kCompressC3 = 2; //obsolete JPEG lossless
 static const int kCompress50 = 3; //obsolete JPEG lossy
     struct TDTI {
         float V[4];
-        float sliceTiming;
         int sliceNumberMrPhilips;
     };
     struct TDTI4D {
@@ -93,21 +93,21 @@ static const int kCompress50 = 3; //obsolete JPEG lossy
 #endif
     struct TCSAdata {
     	bool isPhaseMap;
-        float dtiV[4], sliceNormV[4], bandwidthPerPixelPhaseEncode, sliceMeasurementDuration;
+        float sliceTiming[kMaxEPI3D], dtiV[4], sliceNormV[4], bandwidthPerPixelPhaseEncode, sliceMeasurementDuration;
         int numDti, SeriesHeader_offset, SeriesHeader_length, multiBandFactor, sliceOrder, slice_start, slice_end, mosaicSlices,protocolSliceNumber1,phaseEncodingDirectionPositive;
     };
     struct TDICOMdata {
         long seriesNum;
         int xyzDim[5];
-        int echoTrainLength, patientPositionNumPhilips, coilNum, echoNum, sliceOrient,numberOfDynamicScans, manufacturer, converted2NII, acquNum, imageNum, imageStart, imageBytes, bitsStored, bitsAllocated, samplesPerPixel,patientPositionSequentialRepeats,locationsInAcquisition, compressionScheme;
-        float flipAngle, fieldStrength, TE, TI, TR, intenScale, intenIntercept, intenScalePhilips, gantryTilt, lastScanLoc, angulation[4];
+        int phaseEncodingLines, phaseEncodingSteps, echoTrainLength, patientPositionNumPhilips, coilNum, echoNum, sliceOrient,numberOfDynamicScans, manufacturer, converted2NII, acquNum, imageNum, imageStart, imageBytes, bitsStored, bitsAllocated, samplesPerPixel,patientPositionSequentialRepeats,locationsInAcquisition, compressionScheme;
+        float accelFactPE, flipAngle, fieldStrength, TE, TI, TR, intenScale, intenIntercept, intenScalePhilips, gantryTilt, lastScanLoc, angulation[4];
         float orient[7], patientPosition[4], patientPositionLast[4], xyzMM[4], stackOffcentre[4];
         float radionuclidePositronFraction, radionuclideTotalDose, radionuclideHalfLife, doseCalibrationFactor; //PET ISOTOPE MODULE ATTRIBUTES (C.8-57)
 		float ecat_isotope_halflife, ecat_dosage;
-        double dateTime, acquisitionTime, acquisitionDate;
+        double dateTime, acquisitionTime, acquisitionDate, bandwidthPerPixelPhaseEncode;
         bool isXRay, isMultiEcho, isSlicesSpatiallySequentialPhilips, isNonImage, isValid, is3DAcq, isExplicitVR, isLittleEndian, isPlanarRGB, isSigned, isHasPhase,isHasMagnitude,isHasMixed, isFloat, isResampled;
         char phaseEncodingRC;
-        char softwareVersions[kDICOMStr], deviceSerialNumber[kDICOMStr], institutionAddress[kDICOMStr], institutionName[kDICOMStr], seriesInstanceUID[kDICOMStr], studyInstanceUID[kDICOMStr], bodyPartExamined[kDICOMStr], procedureStepDescription[kDICOMStr], imageType[kDICOMStr], manufacturersModelName[kDICOMStr], patientID[kDICOMStr], patientOrient[kDICOMStr], patientName[kDICOMStr],seriesDescription[kDICOMStr], sequenceName[kDICOMStr], protocolName[kDICOMStr],sequenceVariant[kDICOMStr],s [...]
+        char softwareVersions[kDICOMStr], deviceSerialNumber[kDICOMStr], institutionAddress[kDICOMStr], institutionName[kDICOMStr], referringPhysicianName[kDICOMStr], seriesInstanceUID[kDICOMStr], studyInstanceUID[kDICOMStr], bodyPartExamined[kDICOMStr], procedureStepDescription[kDICOMStr], imageType[kDICOMStr], manufacturersModelName[kDICOMStr], patientID[kDICOMStr], patientOrient[kDICOMStr], patientName[kDICOMStr],seriesDescription[kDICOMStr], studyID[kDICOMStr], sequenceName[kDICOMStr [...]
         struct TCSAdata CSA;
     };
 
diff --git a/console/nii_dicom_batch.cpp b/console/nii_dicom_batch.cpp
index 86386e1..1c1ea16 100755
--- a/console/nii_dicom_batch.cpp
+++ b/console/nii_dicom_batch.cpp
@@ -332,7 +332,12 @@ bool isDerived(struct TDICOMdata d) {
 		return true;
 }
 
-#ifdef _MSC_VER
+#ifdef myReadAsciiCsa
+//read from the ASCII portion of the Siemens CSA series header
+//  this is not recommended: poorly documented
+//  it is better to stick to the binary portion of the Siemens CSA image header
+
+#if defined(_WIN64) || defined(_WIN32)
 //https://opensource.apple.com/source/Libc/Libc-1044.1.2/string/FreeBSD/memmem.c
 /*-
  * Copyright (c) 2005 Pascal Gloor <pascal.gloor at spale.com>
@@ -475,6 +480,8 @@ int siemensEchoEPIFactor(const char * filename,  int csaOffset, int csaLength, i
 	return ret;
 }
 
+#endif //myReadAsciiCsa
+
 void nii_SaveBIDS(char pathoutname[], struct TDICOMdata d, struct TDCMopts opts, struct TDTI4D *dti4D, struct nifti_1_header *h, const char * filename) {
 //https://docs.google.com/document/d/1HFUkAEE-pB-angVcYe6pf_-fVf4sCpOHKesUvfb8Grc/edit#
 // Generate Brain Imaging Data Structure (BIDS) info
@@ -508,22 +515,34 @@ void nii_SaveBIDS(char pathoutname[], struct TDICOMdata d, struct TDCMopts opts,
 			fprintf(fp, "\t\"SeriesInstanceUID\": \"%s\",\n", d.seriesInstanceUID );
 		if (strlen(d.studyInstanceUID) > 0)
 			fprintf(fp, "\t\"StudyInstanceUID\": \"%s\",\n", d.studyInstanceUID );
+		if (strlen(d.referringPhysicianName) > 0)
+			fprintf(fp, "\t\"ReferringPhysicianName\": \"%s\",\n", d.referringPhysicianName );
+		if (strlen(d.studyID) > 0)
+			fprintf(fp, "\t\"StudyID\": \"%s\",\n", d.studyID );
+		//Next lines directly reveal patient identity
+		//if (strlen(d.patientName) > 0)
+		//	fprintf(fp, "\t\"PatientName\": \"%s\",\n", d.patientName );
+		//if (strlen(d.patientID) > 0)
+		//	fprintf(fp, "\t\"PatientID\": \"%s\",\n", d.patientID );
 	}
-	//printMessage("-->%d %d %s\n", d.CSA.SeriesHeader_offset, d.CSA.SeriesHeader_length, filename);
+	#ifdef myReadAsciiCsa
 	if ((d.manufacturer == kMANUFACTURER_SIEMENS) && (d.CSA.SeriesHeader_offset > 0) && (d.CSA.SeriesHeader_length > 0) &&
 	    (strlen(d.scanningSequence) > 1) && (d.scanningSequence[0] == 'E') && (d.scanningSequence[1] == 'P')) { //for EPI scans only
 		int echoSpacing, echoTrainDuration, epiFactor;
 		epiFactor = siemensEchoEPIFactor(filename,  d.CSA.SeriesHeader_offset, d.CSA.SeriesHeader_length, &echoSpacing, &echoTrainDuration);
 		//printMessage("ES %d ETD %d EPI %d\n", echoSpacing, echoTrainDuration, epiFactor);
 		if (echoSpacing > 0)
-			 fprintf(fp, "\t\"EchoSpacing\": %d,\n", echoSpacing);
+			 fprintf(fp, "\t\"EchoSpacing\": %g,\n", echoSpacing / 1000000.0); //usec -> sec
 		if (echoTrainDuration > 0)
-			 fprintf(fp, "\t\"EchoTrainDuration\": %d,\n", echoTrainDuration);
+			 fprintf(fp, "\t\"EchoTrainDuration\": %g,\n", echoTrainDuration / 1000000.0); //usec -> sec
 		if (epiFactor > 0)
 			 fprintf(fp, "\t\"EPIFactor\": %d,\n", epiFactor);
 	}
+	#endif
 	if (d.echoTrainLength > 1) //>1 as for Siemens EPI this is 1, Siemens uses EPI factor http://mriquestions.com/echo-planar-imaging.html
 		fprintf(fp, "\t\"EchoTrainLength\": %d,\n", d.echoTrainLength);
+	if (d.echoNum > 1)
+		fprintf(fp, "\t\"EchoNumber\": %d,\n", d.echoNum);
 	if (d.isNonImage) //DICOM is derived image or non-spatial file (sounds, etc)
 		fprintf(fp, "\t\"RawImage\": false,\n");
 	if (d.acquNum > 0)
@@ -531,7 +550,7 @@ void nii_SaveBIDS(char pathoutname[], struct TDICOMdata d, struct TDCMopts opts,
 	if (strlen(d.institutionName) > 0)
 		fprintf(fp, "\t\"InstitutionName\": \"%s\",\n", d.institutionName );
 	if (strlen(d.institutionAddress) > 0)
-		fprintf(fp, "\t\"InstitutionName\": \"%s\",\n", d.institutionAddress );
+		fprintf(fp, "\t\"InstitutionAddress\": \"%s\",\n", d.institutionAddress );
 	if (strlen(d.deviceSerialNumber) > 0)
 		fprintf(fp, "\t\"DeviceSerialNumber\": \"%s\",\n", d.deviceSerialNumber );
 	if (strlen(d.softwareVersions) > 0)
@@ -613,29 +632,45 @@ void nii_SaveBIDS(char pathoutname[], struct TDICOMdata d, struct TDCMopts opts,
     if (d.TI > 0.0) fprintf(fp, "\t\"InversionTime\": %g,\n", d.TI / 1000.0 );
     if (d.ecat_isotope_halflife > 0.0) fprintf(fp, "\t\"IsotopeHalfLife\": %g,\n", d.ecat_isotope_halflife);
     if (d.ecat_dosage > 0.0) fprintf(fp, "\t\"Dosage\": %g,\n", d.ecat_dosage);
-    //fprintf(fp, "\t\"XXXX\": %g,\n", d.CSA.bandwidthPerPixelPhaseEncode );
-    if ((d.CSA.bandwidthPerPixelPhaseEncode > 0.0) &&  (h->dim[2] > 0) && (h->dim[1] > 0)) {
-		float dwellTime = 0.0f;
+    double bandwidthPerPixelPhaseEncode = d.bandwidthPerPixelPhaseEncode;
+    int phaseEncodingLines = d.phaseEncodingLines;
+    if ((phaseEncodingLines == 0) &&  (h->dim[2] > 0) && (h->dim[1] > 0)) {
 		if  (h->dim[2] == h->dim[2]) //phase encoding does not matter
-			dwellTime =  1.0/d.CSA.bandwidthPerPixelPhaseEncode/h->dim[2];
+			phaseEncodingLines = h->dim[2];
 		else if (d.phaseEncodingRC =='R')
-			dwellTime =  1.0/d.CSA.bandwidthPerPixelPhaseEncode/h->dim[2];
+			phaseEncodingLines = h->dim[2];
 		else if (d.phaseEncodingRC =='C')
-			dwellTime =  1.0/d.CSA.bandwidthPerPixelPhaseEncode/h->dim[1];
-		if (dwellTime != 0.0f) //as long as phase encoding = R or C or does not matter
-			fprintf(fp, "\t\"EffectiveEchoSpacing\": %g,\n", dwellTime );
-    }
-	bool first = 1;
-	if (dti4D->S[0].sliceTiming >= 0.0) {
+			phaseEncodingLines = h->dim[1];
+    }
+    if (bandwidthPerPixelPhaseEncode == 0.0)
+    	bandwidthPerPixelPhaseEncode = 	d.CSA.bandwidthPerPixelPhaseEncode;
+    if (phaseEncodingLines > 0.0) fprintf(fp, "\t\"PhaseEncodingLines\": %d,\n", phaseEncodingLines );
+    if (bandwidthPerPixelPhaseEncode > 0.0)
+    	fprintf(fp, "\t\"BandwidthPerPixelPhaseEncode\": %g,\n", bandwidthPerPixelPhaseEncode );
+    double effectiveEchoSpacing = 0.0;
+    if ((phaseEncodingLines > 0) && (bandwidthPerPixelPhaseEncode > 0.0))
+    	effectiveEchoSpacing = 1.0 / (bandwidthPerPixelPhaseEncode * phaseEncodingLines) ;
+    if (effectiveEchoSpacing > 0.0)
+    		fprintf(fp, "\t\"EffectiveEchoSpacing\": %g,\n", effectiveEchoSpacing);
+    //FSL definition is start of first line until start of last line, so n-1 unless accelerated in-plane acquisition
+    // to check: partial Fourier, iPAT, etc.
+	int fencePost = 1;
+    if (d.accelFactPE > 1.0)
+    	fencePost = (int)round(d.accelFactPE); //e.g. if 64 lines with iPAT=2, we want time from start of first until start of 62nd effective line
+    if ((d.phaseEncodingSteps > 1) && (effectiveEchoSpacing > 0.0))
+		fprintf(fp, "\t\"TotalReadoutTime\": %g,\n", effectiveEchoSpacing * ((float)d.phaseEncodingSteps - fencePost));
+    if (d.accelFactPE > 1.0) {
+    		fprintf(fp, "\t\"AccelFactPE\": %g,\n", d.accelFactPE);
+    		if (effectiveEchoSpacing > 0.0)
+    			fprintf(fp, "\t\"TrueEchoSpacing\": %g,\n", effectiveEchoSpacing * d.accelFactPE);
+	}
+	if (d.CSA.sliceTiming[0] >= 0.0) {
    		fprintf(fp, "\t\"SliceTiming\": [\n");
-   		for (int i = 0; i < kMaxDTI4D; i++) {
-			if (dti4D->S[i].sliceTiming >= 0.0){
-			  if (!first)
-				  fprintf(fp, ",\n");
-				else
-				  first = 0;
-				fprintf(fp, "\t\t%g", dti4D->S[i].sliceTiming / 1000.0 );
-			}
+   		for (int i = 0; i < kMaxEPI3D; i++) {
+   			if (d.CSA.sliceTiming[i] < 0.0) break;
+			if (i != 0)
+				fprintf(fp, ",\n");
+			fprintf(fp, "\t\t%g", d.CSA.sliceTiming[i] / 1000.0 );
 		}
 		fprintf(fp, "\t],\n");
 	}
@@ -1045,6 +1080,8 @@ int nii_createFilename(struct TDICOMdata dcm, char * niiFilename, struct TDCMopt
     			printWarning("Ignoring '%%u' in output filename (recompile to segment by acquisition)\n");
     			#endif
 			}
+			if (f == 'X')
+				strcat (outname,dcm.studyID);
             if (f == 'Z')
                 strcat (outname,dcm.sequenceName);
             if ((f >= '0') && (f <= '9')) {
diff --git a/console/nii_foreign.cpp b/console/nii_foreign.cpp
index 97ad9dc..13989be 100644
--- a/console/nii_foreign.cpp
+++ b/console/nii_foreign.cpp
@@ -400,7 +400,6 @@ int  convert_foreign (const char *fn, struct TDCMopts opts){
 	printMessage("Saving ECAT as '%s'\n", niiFilename);
 	if (ret != EXIT_SUCCESS) return ret;
 	struct TDTI4D dti4D;
-	dti4D.S[0].sliceTiming = -1.0;
 	nii_SaveBIDS(niiFilename, dcm, opts, &dti4D, &hdr, fn);
 	ret = nii_saveNII(niiFilename, hdr, img, opts);
 	free(img);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/dcm2niix.git



More information about the debian-med-commit mailing list