1 #include <stdbool.h> //requires VS 2015 or later
2 #include <string.h>
3 #include <stdint.h>
4 #include "nifti1_io_core.h"
5 #ifndef USING_R
6 #include "nifti1.h"
7 #endif
8 
9 #ifndef MRIpro_nii_dcm_h
10 
11 #define MRIpro_nii_dcm_h
12 
13 #ifdef  __cplusplus
14 extern "C" {
15 #endif
16 
17 #define STR_HELPER(x) #x
18 #define STR(x) STR_HELPER(x)
19 
20  #if defined(myEnableJPEGLS) || defined(myEnableJPEGLS1)
21    #define kLSsuf " (JP-LS:CharLS)"
22  #else
23    #define kLSsuf ""
24  #endif
25  #ifdef myEnableJasper
26   #define kJP2suf " (JP2:JasPer)"
27  #else
28   #ifdef myDisableOpenJPEG
29     #define kJP2suf ""
30   #else
31     #define kJP2suf " (JP2:OpenJPEG)"
32   #endif
33  #endif
34 #if defined(__ICC) || defined(__INTEL_COMPILER)
35 	#define kCCsuf  " IntelCC" STR(__INTEL_COMPILER)
36 #elif defined(_MSC_VER)
37 	#define kCCsuf  " MSC" STR(_MSC_VER)
38 #elif defined(__clang__)
39 	#define kCCsuf  " Clang" STR(__clang_major__) "." STR(__clang_minor__) "." STR(__clang_patchlevel__)
40 #elif defined(__GNUC__) || defined(__GNUG__)
41     #define kCCsuf  " GCC" STR(__GNUC__) "." STR(__GNUC_MINOR__) "." STR(__GNUC_PATCHLEVEL__)
42 #else
43 	#define kCCsuf " CompilerNA" //unknown compiler!
44 #endif
45 #if defined(__arm__) || defined(__ARM_ARCH)
46     #define kCPUsuf " ARM"
47 #elif defined(__x86_64)
48     #define kCPUsuf " x86-64"
49 #else
50     #define kCPUsuf " " //unknown CPU
51 #endif
52 
53 #define kDCMdate "v1.0.20211006"
54 #define kDCMvers kDCMdate " " kJP2suf kLSsuf kCCsuf kCPUsuf
55 
56 static const int kMaxEPI3D = 1024; //maximum number of EPI images in Siemens Mosaic
57 static const int kMaxSlice2D = 65535; //issue460 maximum number of 2D slices in 4D (Philips) images
58 static const int kMaxDTI4D = kMaxSlice2D; //issue460: maximum number of DTI directions for 4D (Philips) images, also maximum number of 2D slices for Enhanced DICOM and PAR/REC
59 
60 #define kDICOMStr 66 //64 characters plus NULL https://github.com/rordenlab/dcm2niix/issues/268
61 #define kDICOMStrLarge 256
62 
63 #define kMANUFACTURER_UNKNOWN  0
64 #define kMANUFACTURER_SIEMENS  1
65 #define kMANUFACTURER_GE  2
66 #define kMANUFACTURER_PHILIPS  3
67 #define kMANUFACTURER_TOSHIBA  4
68 #define kMANUFACTURER_UIH  5
69 #define kMANUFACTURER_BRUKER  6
70 #define kMANUFACTURER_HITACHI  7
71 #define kMANUFACTURER_CANON  8
72 #define kMANUFACTURER_MEDISO  9
73 
74 //note: note a complete modality list, e.g. XA,PX, etc
75 #define kMODALITY_UNKNOWN  0
76 #define kMODALITY_CR  1
77 #define kMODALITY_CT  2
78 #define kMODALITY_MR  3
79 #define kMODALITY_PT  4
80 #define kMODALITY_US  5
81 
82 // PartialFourierDirection 0018,9036
83 #define kPARTIAL_FOURIER_DIRECTION_UNKNOWN  0
84 #define kPARTIAL_FOURIER_DIRECTION_PHASE  1
85 #define kPARTIAL_FOURIER_DIRECTION_FREQUENCY  2
86 #define kPARTIAL_FOURIER_DIRECTION_SLICE_SELECT  3
87 #define kPARTIAL_FOURIER_DIRECTION_COMBINATION  4
88 
89 //GE EPI settings
90 #define kGE_EPI_UNKNOWN  -1
91 #define kGE_EPI_EPI  0
92 #define kGE_EPI_EPIRT  1
93 #define kGE_EPI_EPI2  2
94 #define kGE_EPI_PEPOLAR_FWD  3
95 #define kGE_EPI_PEPOLAR_REV  4
96 #define kGE_EPI_PEPOLAR_REV_FWD  5
97 #define kGE_EPI_PEPOLAR_FWD_REV  6
98 #define kGE_EPI_PEPOLAR_REV_FWD_FLIP  7
99 #define kGE_EPI_PEPOLAR_FWD_REV_FLIP  8
100 
101 
102 //GE phase encoding
103 #define kGE_PHASE_ENCODING_POLARITY_UNKNOWN  -1
104 #define kGE_PHASE_ENCODING_POLARITY_UNFLIPPED  0
105 #define kGE_PHASE_ENCODING_POLARITY_FLIPPED  4
106 #define kGE_SLICE_ORDER_UNKNOWN -1
107 #define kGE_SLICE_ORDER_TOP_DOWN  0
108 #define kGE_SLICE_ORDER_BOTTOM_UP  2
109 
110 
111 //#define kGE_PHASE_DIRECTION_CENTER_OUT_REV  3
112 //#define kGE_PHASE_DIRECTION_CENTER_OUT  4
113 
114 //EXIT_SUCCESS 0
115 //EXIT_FAILURE 1
116 #define kEXIT_NO_VALID_FILES_FOUND  2
117 #define kEXIT_REPORT_VERSION  3
118 #define kEXIT_CORRUPT_FILE_FOUND  4
119 #define kEXIT_INPUT_FOLDER_INVALID  5
120 #define kEXIT_OUTPUT_FOLDER_INVALID  6
121 #define kEXIT_OUTPUT_FOLDER_READ_ONLY  7
122 #define kEXIT_SOME_OK_SOME_BAD  8
123 #define kEXIT_RENAME_ERROR  9
124 #define kEXIT_INCOMPLETE_VOLUMES_FOUND  10 //issue 515
125 #define kEXIT_NOMINAL  11 //did not expect to convert files
126 
127 //0043,10A3  ---: PSEUDOCONTINUOUS
128 //0043,10A4  ---: 3D pulsed continuous ASL technique
129 #define kASL_FLAG_NONE 0
130 #define kASL_FLAG_GE_3DPCASL 1
131 #define kASL_FLAG_GE_3DCASL 2
132 #define kASL_FLAG_GE_PSEUDOCONTINUOUS 4
133 #define kASL_FLAG_GE_CONTINUOUS 8
134 #define kASL_FLAG_PHILIPS_CONTROL 16
135 #define kASL_FLAG_PHILIPS_LABEL 32
136 
137 
138 //for spoiling 0018,9016
139 #define kSPOILING_UNKOWN -1
140 #define kSPOILING_NONE 0
141 #define kSPOILING_RF 1
142 #define kSPOILING_GRADIENT 2
143 #define kSPOILING_RF_AND_GRADIENT 3
144 
145 static const int kSliceOrientUnknown = 0;
146 static const int kSliceOrientTra = 1;
147 static const int kSliceOrientSag = 2;
148 static const int kSliceOrientCor = 3;
149 static const int kSliceOrientMosaicNegativeDeterminant = 4;
150 static const int kCompressNone = 0;
151 static const int kCompressYes = 1;
152 static const int kCompressC3 = 2; //obsolete JPEG lossless
153 static const int kCompress50 = 3; //obsolete JPEG lossy
154 static const int kCompressRLE = 4; //run length encoding
155 static const int kCompressPMSCT_RLE1 = 5; //see rle2img: Philips/ELSCINT1 run-length compression 07a1,1011= PMSCT_RLE1
156 static const int kCompressJPEGLS = 6; //LoCo JPEG-LS
157 static const int kMaxOverlay = 16; //even group values 0x6000..0x601E
158 #ifdef myEnableJasper
159     static const int kCompressSupport = kCompressYes; //JASPER for JPEG2000
160 #else
161     #ifdef myDisableOpenJPEG
162         static const int kCompressSupport = kCompressNone; //no decompressor
163     #else
164         static const int kCompressSupport = kCompressYes; //OPENJPEG for JPEG2000
165     #endif
166 #endif
167 
168 // Maximum number of dimensions for .dimensionIndexValues, i.e. possibly the
169 // number of axes in the output .nii.
170 static const uint8_t MAX_NUMBER_OF_DIMENSIONS = 8;
171     struct TDTI {
172         float V[4];
173         //int totalSlicesIn4DOrder;
174     };
175     struct TDTI4D {
176         struct TDTI S[kMaxDTI4D];
177         int sliceOrder[kMaxSlice2D]; // [7,3,2] means the first slice on disk should be moved to 7th position
178         int gradDynVol[kMaxDTI4D]; //used to parse dimensions of Philips data, e.g. file with multiple dynamics, echoes, phase+magnitude
179         //int fragmentOffset[kMaxDTI4D], fragmentLength[kMaxDTI4D]; //for images with multiple compressed fragments
180         float frameDuration[kMaxDTI4D], decayFactor[kMaxDTI4D], volumeOnsetTime[kMaxDTI4D], triggerDelayTime[kMaxDTI4D], TE[kMaxDTI4D], RWVScale[kMaxDTI4D], RWVIntercept[kMaxDTI4D], intenScale[kMaxDTI4D], intenIntercept[kMaxDTI4D], intenScalePhilips[kMaxDTI4D];
181         bool isReal[kMaxDTI4D];
182         bool isImaginary[kMaxDTI4D];
183         bool isPhase[kMaxDTI4D];
184         float repetitionTimeExcitation, repetitionTimeInversion;
185     };
186 
187 #ifdef _MSC_VER //Microsoft nomenclature for packed structures is different...
188     #pragma pack(2)
189     typedef struct {
190         char name[64]; //null-terminated
191         int32_t vm;
192         char vr[4]; //  possibly nul-term string
193         int32_t syngodt;//  ??
194         int32_t nitems;// number of items in CSA
195         int32_t xx;// maybe == 77 or 205
196     } TCSAtag; //Siemens csa tag structure
197     typedef struct {
198         int32_t xx1, xx2_Len, xx3_77, xx4;
199     } TCSAitem; //Siemens csa item structure
200     #pragma pack()
201 #else
202     typedef struct __attribute__((packed)) {
203         char name[64]; //null-terminated
204         int32_t vm;
205         char vr[4]; //  possibly nul-term string
206         int32_t syngodt;//  ??
207         int32_t nitems;// number of items in CSA
208         int32_t xx;// maybe == 77 or 205
209     } TCSAtag; //Siemens csa tag structure
210     typedef struct __attribute__((packed)) {
211         int32_t xx1, xx2_Len, xx3_77, xx4;
212     } TCSAitem; //Siemens csa item structure
213 #endif
214     struct TCSAdata {
215     	float sliceTiming[kMaxEPI3D], dtiV[4], sliceNormV[4], bandwidthPerPixelPhaseEncode, sliceMeasurementDuration;
216         int numDti, SeriesHeader_offset, SeriesHeader_length, multiBandFactor, sliceOrder, slice_start, slice_end, mosaicSlices, protocolSliceNumber1, phaseEncodingDirectionPositive;
217     	bool isPhaseMap;
218 
219     };
220     struct TDICOMdata {
221         long seriesNum;
222         int xyzDim[5];
223         uint32_t coilCrc, seriesUidCrc, instanceUidCrc;
224         int overlayStart[kMaxOverlay];
225         int phaseNumber, spoiling, mtState, partialFourierDirection, interp3D, aslFlags, durationLabelPulseGE, epiVersionGE, internalepiVersionGE, maxEchoNumGE, rawDataRunNumber, numberOfImagesInGridUIH, numberOfDiffusionDirectionGE, phaseEncodingGE, protocolBlockStartGE, protocolBlockLengthGE, modality, dwellTime, effectiveEchoSpacingGE, phaseEncodingLines, phaseEncodingSteps, echoTrainLength, echoNum, sliceOrient, manufacturer, converted2NII, acquNum, imageNum, imageStart, imageBytes, bitsStored, bitsAllocated, samplesPerPixel,locationsInAcquisition, locationsInAcquisitionConflict, compressionScheme;
226         float 	xRayTubeCurrent, exposureTimeMs, numberOfExcitations, numberOfArms, numberOfPointsPerArm, groupDelay, decayFactor, percentSampling,waterFatShift, numberOfAverages, imagingFrequency, patientWeight, zSpacing, zThick, pixelBandwidth, SAR, phaseFieldofView, accelFactPE, accelFactOOP, flipAngle, fieldStrength, TE, TI, TR, intenScale, intenIntercept, intenScalePhilips, gantryTilt, lastScanLoc, angulation[4];
227         float orient[7], patientPosition[4], patientPositionLast[4], xyzMM[4], stackOffcentre[4];
228         float rtia_timerGE, radionuclidePositronFraction, radionuclideTotalDose, radionuclideHalfLife, doseCalibrationFactor; //PET ISOTOPE MODULE ATTRIBUTES (C.8-57)
229 		float frameDuration, ecat_isotope_halflife, ecat_dosage;
230 		float pixelPaddingValue;  // used for both FloatPixelPaddingValue (0028, 0122) and PixelPaddingValue (0028, 0120); NaN if not present.
231         double acquisitionDuration, triggerDelayTime, RWVScale, RWVIntercept, dateTime, acquisitionTime, acquisitionDate, bandwidthPerPixelPhaseEncode;
232         char parallelAcquisitionTechnique[kDICOMStr], radiopharmaceutical[kDICOMStr], convolutionKernel[kDICOMStr], unitsPT[kDICOMStr], decayCorrection[kDICOMStr], attenuationCorrectionMethod[kDICOMStr],reconstructionMethod[kDICOMStr];
233         char imageOrientationText[kDICOMStr], coilElements[kDICOMStr], coilName[kDICOMStr], phaseEncodingDirectionDisplayedUIH[kDICOMStr], imageBaseName[kDICOMStr], scanOptions[kDICOMStr], stationName[kDICOMStr], softwareVersions[kDICOMStr], deviceSerialNumber[kDICOMStr], institutionName[kDICOMStr], referringPhysicianName[kDICOMStr], instanceUID[kDICOMStr], seriesInstanceUID[kDICOMStr], studyInstanceUID[kDICOMStr], bodyPartExamined[kDICOMStr], procedureStepDescription[kDICOMStr], imageType[kDICOMStr], institutionalDepartmentName[kDICOMStr], manufacturersModelName[kDICOMStr], patientID[kDICOMStr], patientOrient[kDICOMStr], patientName[kDICOMStr], accessionNumber[kDICOMStr], seriesDescription[kDICOMStr], studyID[kDICOMStr], sequenceName[kDICOMStr], protocolName[kDICOMStr],sequenceVariant[kDICOMStr],scanningSequence[kDICOMStr], patientBirthDate[kDICOMStr], patientAge[kDICOMStr],  studyDate[kDICOMStr],studyTime[kDICOMStr];
234         char institutionAddress[kDICOMStrLarge], imageComments[kDICOMStrLarge];
235         uint32_t dimensionIndexValues[MAX_NUMBER_OF_DIMENSIONS];
236         struct TCSAdata CSA;
237         bool isRealIsPhaseMapHz, isPrivateCreatorRemap, isHasOverlay, isEPI, isIR, isPartialFourier, isDiffusion, isVectorFromBMatrix, isRawDataStorage, isGrayscaleSoftcopyPresentationState, isStackableSeries, isCoilVaries, isNonParallelSlices, isBVecWorldCoordinates, isSegamiOasis, isXA10A, isScaleOrTEVaries, isScaleVariesEnh, isDerived, isXRay, isMultiEcho, isValid, is3DAcq, is2DAcq, isExplicitVR, isLittleEndian, isPlanarRGB, isSigned, isHasPhase, isHasImaginary, isHasReal, isHasMagnitude,isHasMixed, isFloat, isResampled, isLocalizer;
238         char phaseEncodingRC, patientSex;
239     };
240     struct TDCMprefs {
241         int isVerbose, compressFlag, isIgnoreTriggerTimes;
242 	};
243 
244     size_t nii_ImgBytes(struct nifti_1_header hdr);
245 	void setDefaultPrefs (struct TDCMprefs *prefs);
246     int isSameFloatGE (float a, float b);
247     void getFileNameX( char *pathParent, const char *path, int maxLen);
248     struct TDICOMdata readDICOMv(char * fname, int isVerbose, int compressFlag, struct TDTI4D *dti4D);
249     struct TDICOMdata readDICOMx(char * fname, struct TDCMprefs* prefs, struct TDTI4D *dti4D);
250 
251 	struct TDICOMdata readDICOM(char * fname);
252     struct TDICOMdata clear_dicom_data(void);
253     struct TDICOMdata  nii_readParRec (char * parname, int isVerbose, struct TDTI4D *dti4D, bool isReadPhase);
254     unsigned char * nii_flipY(unsigned char* bImg, struct nifti_1_header *h);
255     unsigned char *nii_flipImgY(unsigned char *bImg, struct nifti_1_header *hdr);
256     unsigned char * nii_flipZ(unsigned char* bImg, struct nifti_1_header *h);
257     //*unsigned char * nii_reorderSlices(unsigned char* bImg, struct nifti_1_header *h, struct TDTI4D *dti4D);
258     void changeExt (char *file_name, const char* ext);
259     unsigned char * nii_planar2rgb(unsigned char* bImg, struct nifti_1_header *hdr, int isPlanar);
260 	int isDICOMfile(const char * fname); //0=not DICOM, 1=DICOM, 2=NOTSURE(not part 10 compliant)
261     void setQSForm(struct nifti_1_header *h, mat44 Q44i, bool isVerbose);
262     int headerDcm2Nii2(struct TDICOMdata d, struct TDICOMdata d2, struct nifti_1_header *h, int isVerbose);
263     int headerDcm2Nii(struct TDICOMdata d, struct nifti_1_header *h, bool isComputeSForm) ;
264     unsigned char * nii_loadImgXL(char* imgname, struct nifti_1_header *hdr, struct TDICOMdata dcm, bool iVaries, int compressFlag, int isVerbose, struct TDTI4D *dti4D);
265 #ifdef  __cplusplus
266 }
267 #endif
268 
269 #endif
270