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