31 #include "Common/AString.h"
33 #include "Common/ByteSwapping.h"
34 #include "Common/BinaryFile.h"
35 #include "Common/CiftiException.h"
36 #include "Common/CiftiMutex.h"
37 #include "Nifti/NiftiHeader.h"
40 #include "Common/MultiDimIterator.h"
53 std::vector<int64_t> m_dims;
54 std::vector<char> m_scratch;
56 int numBytesPerElem();
57 template<
typename TO,
typename FROM>
58 void convertRead(TO* out, FROM* in,
const int64_t& count);
59 template<
typename TO,
typename FROM>
60 void convertWrite(TO* out,
const FROM* in,
const int64_t& count);
61 template<
typename TO,
typename FROM>
62 static TO clamp(
const FROM& in);
64 void openRead(
const AString& filename);
65 void writeNew(
const AString& filename,
const NiftiHeader& header,
const int& version = 1,
const bool& withRead =
false,
const bool& swapEndian =
false);
66 AString getFilename()
const {
return m_file.getFilename(); }
67 void overrideDimensions(
const std::vector<int64_t>& newDims) { m_dims = newDims; }
69 const NiftiHeader& getHeader()
const {
return m_header; }
70 const std::vector<int64_t>& getDimensions()
const {
return m_dims; }
71 int getNumComponents()
const;
75 void readData(T* dataOut,
const int& fullDims,
const std::vector<int64_t>& indexSelect,
const bool& tolerateShortRead =
false);
77 void writeData(
const T* dataIn,
const int& fullDims,
const std::vector<int64_t>& indexSelect);
81 void NiftiIO::readData(T* dataOut,
const int& fullDims,
const std::vector<int64_t>& indexSelect,
const bool& tolerateShortRead)
83 if (fullDims < 0)
throw CiftiException(
"NiftiIO: fulldims must not be negative");
84 if (fullDims > (
int)m_dims.size())
throw CiftiException(
"NiftiIO: fulldims must not be greater than number of dimensions");
85 if ((
size_t)fullDims + indexSelect.size() != m_dims.size())
87 throw CiftiException(
"NiftiIO: fulldims plus length of indexSelect must equal number of dimensions");
89 int64_t numElems = getNumComponents();
91 for (curDim = 0; curDim < fullDims; ++curDim)
93 numElems *= m_dims[curDim];
95 int64_t numDimSkip = numElems, numSkip = 0;
96 for (; curDim < (int)m_dims.size(); ++curDim)
98 if (indexSelect[curDim - fullDims] < 0)
throw CiftiException(
"NiftiIO: indices must not be negative");
99 if (indexSelect[curDim - fullDims] >= m_dims[curDim])
throw CiftiException(
"NiftiIO: index exceeds nifti dimension length");
100 numSkip += indexSelect[curDim - fullDims] * numDimSkip;
101 numDimSkip *= m_dims[curDim];
103 CiftiMutexLocker locked(&m_mutex);
106 m_scratch.resize(numElems * numBytesPerElem());
107 m_file.seek(numSkip * numBytesPerElem() + m_header.getDataOffset());
109 m_file.read(m_scratch.data(), m_scratch.size(), &numRead);
110 if ((numRead != (int64_t)m_scratch.size() && !tolerateShortRead) || numRead < 0)
112 throw CiftiException(
"error while reading from file '" + m_file.getFilename() +
"'");
114 switch (m_header.getDataType())
118 convertRead(dataOut, (uint8_t*)m_scratch.data(), numElems);
121 convertRead(dataOut, (int8_t*)m_scratch.data(), numElems);
124 convertRead(dataOut, (uint16_t*)m_scratch.data(), numElems);
127 convertRead(dataOut, (int16_t*)m_scratch.data(), numElems);
130 convertRead(dataOut, (uint32_t*)m_scratch.data(), numElems);
133 convertRead(dataOut, (int32_t*)m_scratch.data(), numElems);
136 convertRead(dataOut, (uint64_t*)m_scratch.data(), numElems);
139 convertRead(dataOut, (int64_t*)m_scratch.data(), numElems);
143 convertRead(dataOut, (
float*)m_scratch.data(), numElems);
147 convertRead(dataOut, (
double*)m_scratch.data(), numElems);
151 convertRead(dataOut, (
long double*)m_scratch.data(), numElems);
154 throw CiftiException(
"internal error, tell the developers what you just tried to do");
159 void NiftiIO::writeData(
const T* dataIn,
const int& fullDims,
const std::vector<int64_t>& indexSelect)
161 if (fullDims < 0)
throw CiftiException(
"NiftiIO: fulldims must not be negative");
162 if (fullDims > (
int)m_dims.size())
throw CiftiException(
"NiftiIO: fulldims must not be greater than number of dimensions");
163 if ((
size_t)fullDims + indexSelect.size() != m_dims.size())
165 throw CiftiException(
"NiftiIO: fulldims plus length of indexSelect must equal number of dimensions");
167 int64_t numElems = getNumComponents();
169 for (curDim = 0; curDim < fullDims; ++curDim)
171 numElems *= m_dims[curDim];
173 int64_t numDimSkip = numElems, numSkip = 0;
174 for (; curDim < (int)m_dims.size(); ++curDim)
176 if (indexSelect[curDim - fullDims] < 0)
throw CiftiException(
"NiftiIO: indices must not be negative");
177 if (indexSelect[curDim - fullDims] >= m_dims[curDim])
throw CiftiException(
"NiftiIO: index exceeds nifti dimension length");
178 numSkip += indexSelect[curDim - fullDims] * numDimSkip;
179 numDimSkip *= m_dims[curDim];
181 CiftiMutexLocker locked(&m_mutex);
183 m_scratch.resize(numElems * numBytesPerElem());
184 m_file.seek(numSkip * numBytesPerElem() + m_header.getDataOffset());
185 switch (m_header.getDataType())
189 convertWrite((uint8_t*)m_scratch.data(), dataIn, numElems);
192 convertWrite((int8_t*)m_scratch.data(), dataIn, numElems);
195 convertWrite((uint16_t*)m_scratch.data(), dataIn, numElems);
198 convertWrite((int16_t*)m_scratch.data(), dataIn, numElems);
201 convertWrite((uint32_t*)m_scratch.data(), dataIn, numElems);
204 convertWrite((int32_t*)m_scratch.data(), dataIn, numElems);
207 convertWrite((uint64_t*)m_scratch.data(), dataIn, numElems);
210 convertWrite((int64_t*)m_scratch.data(), dataIn, numElems);
214 convertWrite((
float*)m_scratch.data(), dataIn, numElems);
218 convertWrite((
double*)m_scratch.data(), dataIn, numElems);
222 convertWrite((
long double*)m_scratch.data(), dataIn, numElems);
225 throw CiftiException(
"internal error, tell the developers what you just tried to do");
227 m_file.write(m_scratch.data(), m_scratch.size());
230 template<
typename TO,
typename FROM>
231 void NiftiIO::convertRead(TO* out, FROM* in,
const int64_t& count)
233 if (m_header.isSwapped())
235 ByteSwapping::swapArray(in, count);
238 bool doScale = m_header.getDataScaling(mult, offset);
239 if (std::numeric_limits<TO>::is_integer)
243 for (int64_t i = 0; i < count; ++i)
245 out[i] = clamp<TO, long double>(floor(0.5l + offset + mult * (
long double)in[i]));
248 for (int64_t i = 0; i < count; ++i)
250 out[i] = clamp<TO, double>(floor(0.5 + in[i]));
256 for (int64_t i = 0; i < count; ++i)
258 out[i] = (TO)(offset + mult * (
long double)in[i]);
261 for (int64_t i = 0; i < count; ++i)
269 template<
typename TO,
typename FROM>
270 void NiftiIO::convertWrite(TO* out,
const FROM* in,
const int64_t& count)
273 bool doScale = m_header.getDataScaling(mult, offset);
274 if (std::numeric_limits<TO>::is_integer)
278 for (int64_t i = 0; i < count; ++i)
280 out[i] = clamp<TO, long double>(floor(0.5l + ((
long double)in[i] - offset) / mult));
283 for (int64_t i = 0; i < count; ++i)
285 out[i] = clamp<TO, double>(floor(0.5 + in[i]));
291 for (int64_t i = 0; i < count; ++i)
293 out[i] = (TO)(((
long double)in[i] - offset) / mult);
296 for (int64_t i = 0; i < count; ++i)
302 if (m_header.isSwapped()) ByteSwapping::swapArray(out, count);
305 template<
typename TO,
typename FROM>
306 TO NiftiIO::clamp(
const FROM& in)
308 typedef std::numeric_limits<TO> mylimits;
309 if (mylimits::has_infinity && std::isinf(in))
return (TO)in;
310 if (mylimits::max() < in)
return mylimits::max();
311 if (mylimits::is_integer)
313 if (mylimits::min() > in)
return mylimits::min();
315 if (-mylimits::max() > in)
return -mylimits::max();
Definition: BinaryFile.h:41
Definition: CiftiException.h:40
const int32_t NIFTI_TYPE_UINT64
Definition: nifti1.h:568
const int32_t NIFTI_TYPE_COMPLEX64
Definition: nifti1.h:554
const int32_t NIFTI_TYPE_FLOAT64
Definition: nifti1.h:556
const int32_t NIFTI_TYPE_INT8
Definition: nifti1.h:560
const int32_t NIFTI_TYPE_UINT8
Definition: nifti1.h:546
const int32_t NIFTI_TYPE_FLOAT32
Definition: nifti1.h:552
const int32_t NIFTI_TYPE_RGB24
Definition: nifti1.h:558
const int32_t NIFTI_TYPE_INT64
Definition: nifti1.h:566
const int32_t NIFTI_TYPE_INT32
Definition: nifti1.h:550
const int32_t NIFTI_TYPE_INT16
Definition: nifti1.h:548
const int32_t NIFTI_TYPE_UINT16
Definition: nifti1.h:562
const int32_t NIFTI_TYPE_COMPLEX128
Definition: nifti1.h:572
const int32_t NIFTI_TYPE_FLOAT128
Definition: nifti1.h:570
const int32_t NIFTI_TYPE_COMPLEX256
Definition: nifti1.h:574
const int32_t NIFTI_TYPE_UINT32
Definition: nifti1.h:564
namespace for all CiftiLib functionality
Definition: CiftiBrainModelsMap.h:42