/src/lerc/src/LercLib/Lerc.cpp
Line | Count | Source |
1 | | /* |
2 | | Copyright 2015 - 2026 Esri |
3 | | |
4 | | Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | you may not use this file except in compliance with the License. |
6 | | You may obtain a copy of the License at |
7 | | |
8 | | http://www.apache.org/licenses/LICENSE-2.0 |
9 | | |
10 | | Unless required by applicable law or agreed to in writing, software |
11 | | distributed under the License is distributed on an "AS IS" BASIS, |
12 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | See the License for the specific language governing permissions and |
14 | | limitations under the License. |
15 | | |
16 | | A local copy of the license and additional notices are located with the |
17 | | source distribution at: |
18 | | |
19 | | http://github.com/Esri/lerc/ |
20 | | |
21 | | Contributors: Thomas Maurer |
22 | | */ |
23 | | |
24 | | #include "Defines.h" |
25 | | #include "Lerc.h" |
26 | | #include "Lerc2.h" |
27 | | #include <cstring> |
28 | | #include <functional> |
29 | | #include <limits> |
30 | | #include <typeinfo> |
31 | | |
32 | | #ifdef HAVE_LERC1_DECODE |
33 | | #include "Lerc1Decode/CntZImage.h" |
34 | | #endif |
35 | | |
36 | | using namespace std; |
37 | | USING_NAMESPACE_LERC |
38 | | |
39 | | // -------------------------------------------------------------------------- ; |
40 | | |
41 | | ErrCode Lerc::ComputeCompressedSize(const void* pData, int version, DataType dt, int nDepth, int nCols, int nRows, int nBands, |
42 | | int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded, const unsigned char* pUsesNoData, const double* noDataValues) |
43 | 0 | { |
44 | 0 | #define LERC_ARG_1 version, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded, pUsesNoData, noDataValues |
45 | |
|
46 | 0 | switch (dt) |
47 | 0 | { |
48 | 0 | case DT_Char: return ComputeCompressedSizeTempl((const signed char*)pData, LERC_ARG_1); |
49 | 0 | case DT_Byte: return ComputeCompressedSizeTempl((const Byte*)pData, LERC_ARG_1); |
50 | 0 | case DT_Short: return ComputeCompressedSizeTempl((const short*)pData, LERC_ARG_1); |
51 | 0 | case DT_UShort: return ComputeCompressedSizeTempl((const unsigned short*)pData, LERC_ARG_1); |
52 | 0 | case DT_Int: return ComputeCompressedSizeTempl((const int*)pData, LERC_ARG_1); |
53 | 0 | case DT_UInt: return ComputeCompressedSizeTempl((const unsigned int*)pData, LERC_ARG_1); |
54 | 0 | case DT_Float: return ComputeCompressedSizeTempl((const float*)pData, LERC_ARG_1); |
55 | 0 | case DT_Double: return ComputeCompressedSizeTempl((const double*)pData, LERC_ARG_1); |
56 | | |
57 | 0 | default: |
58 | 0 | return ErrCode::WrongParam; |
59 | 0 | } |
60 | |
|
61 | 0 | #undef LERC_ARG_1 |
62 | 0 | } |
63 | | |
64 | | // -------------------------------------------------------------------------- ; |
65 | | |
66 | | ErrCode Lerc::Encode(const void* pData, int version, DataType dt, int nDepth, int nCols, int nRows, int nBands, |
67 | | int nMasks, const Byte* pValidBytes, double maxZErr, Byte* pBuffer, unsigned int numBytesBuffer, |
68 | | unsigned int& numBytesWritten, const unsigned char* pUsesNoData, const double* noDataValues) |
69 | 0 | { |
70 | 0 | #define LERC_ARG_2 version, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten, pUsesNoData, noDataValues |
71 | |
|
72 | 0 | switch (dt) |
73 | 0 | { |
74 | 0 | case DT_Char: return EncodeTempl((const signed char*)pData, LERC_ARG_2); |
75 | 0 | case DT_Byte: return EncodeTempl((const Byte*)pData, LERC_ARG_2); |
76 | 0 | case DT_Short: return EncodeTempl((const short*)pData, LERC_ARG_2); |
77 | 0 | case DT_UShort: return EncodeTempl((const unsigned short*)pData, LERC_ARG_2); |
78 | 0 | case DT_Int: return EncodeTempl((const int*)pData, LERC_ARG_2); |
79 | 0 | case DT_UInt: return EncodeTempl((const unsigned int*)pData, LERC_ARG_2); |
80 | 0 | case DT_Float: return EncodeTempl((const float*)pData, LERC_ARG_2); |
81 | 0 | case DT_Double: return EncodeTempl((const double*)pData, LERC_ARG_2); |
82 | | |
83 | 0 | default: |
84 | 0 | return ErrCode::WrongParam; |
85 | 0 | } |
86 | |
|
87 | 0 | #undef LERC_ARG_2 |
88 | 0 | } |
89 | | |
90 | | // -------------------------------------------------------------------------- ; |
91 | | |
92 | | ErrCode Lerc::GetLercInfo(const Byte* pLercBlob, unsigned int numBytesBlob, struct LercInfo& lercInfo, double* pMins, double* pMaxs, size_t nElem) |
93 | 9 | { |
94 | 9 | lercInfo.RawInit(); |
95 | | |
96 | | // first try Lerc2 |
97 | 9 | struct Lerc2::HeaderInfo lerc2Info; |
98 | 9 | bool bHasMask = false; |
99 | 9 | int nMasks = 0; |
100 | | |
101 | 9 | if (Lerc2::GetHeaderInfo(pLercBlob, numBytesBlob, lerc2Info, bHasMask)) |
102 | 0 | { |
103 | 0 | if (lerc2Info.blobSize < 0) |
104 | 0 | return ErrCode::Failed; |
105 | | |
106 | 0 | lercInfo.version = lerc2Info.version; |
107 | 0 | lercInfo.nDepth = lerc2Info.nDepth; |
108 | 0 | lercInfo.nCols = lerc2Info.nCols; |
109 | 0 | lercInfo.nRows = lerc2Info.nRows; |
110 | 0 | lercInfo.numValidPixel = lerc2Info.numValidPixel; // for 1st band |
111 | 0 | lercInfo.blobSize = (unsigned int)lerc2Info.blobSize; // blob size per band is in [0 .. 2 GB] |
112 | 0 | lercInfo.dt = (DataType)lerc2Info.dt; |
113 | 0 | lercInfo.zMin = lerc2Info.zMin; |
114 | 0 | lercInfo.zMax = lerc2Info.zMax; |
115 | 0 | lercInfo.maxZError = lerc2Info.maxZError; |
116 | 0 | lercInfo.nUsesNoDataValue = lerc2Info.bPassNoDataValues ? 1 : 0; |
117 | |
|
118 | 0 | bool bTryNextBlob = (lerc2Info.version <= 5) || (lerc2Info.nBlobsMore > 0); |
119 | |
|
120 | 0 | if (bHasMask || lercInfo.numValidPixel == 0) |
121 | 0 | nMasks = 1; |
122 | |
|
123 | 0 | if (pMins && pMaxs) |
124 | 0 | { |
125 | 0 | ErrCode errCode = GetRanges(pLercBlob, numBytesBlob, 0, lerc2Info, pMins, pMaxs, nElem); // band 0 |
126 | 0 | if (errCode != ErrCode::Ok) |
127 | 0 | return errCode; |
128 | 0 | } |
129 | | |
130 | 0 | lercInfo.nBands = 1; |
131 | |
|
132 | 0 | if (lercInfo.blobSize > numBytesBlob) // truncated blob, we won't be able to read this band |
133 | 0 | return ErrCode::Failed; |
134 | | |
135 | 0 | struct Lerc2::HeaderInfo hdInfo; |
136 | 0 | while (bTryNextBlob && Lerc2::GetHeaderInfo(pLercBlob + lercInfo.blobSize, numBytesBlob - lercInfo.blobSize, hdInfo, bHasMask)) |
137 | 0 | { |
138 | 0 | if (hdInfo.nDepth != lercInfo.nDepth |
139 | 0 | || hdInfo.nCols != lercInfo.nCols |
140 | 0 | || hdInfo.nRows != lercInfo.nRows |
141 | 0 | || (int)hdInfo.dt != (int)lercInfo.dt |
142 | 0 | || hdInfo.blobSize < 0) |
143 | 0 | { |
144 | 0 | return ErrCode::Failed; |
145 | 0 | } |
146 | | |
147 | 0 | bTryNextBlob = (hdInfo.version <= 5) || (hdInfo.nBlobsMore > 0); |
148 | |
|
149 | 0 | if (hdInfo.bPassNoDataValues) |
150 | 0 | lercInfo.nUsesNoDataValue++; |
151 | |
|
152 | 0 | if (bHasMask || hdInfo.numValidPixel != lercInfo.numValidPixel) // support mask per band |
153 | 0 | nMasks = 2; |
154 | |
|
155 | 0 | if ((size_t)lercInfo.blobSize > (size_t)UINT_MAX - hdInfo.blobSize) // guard against overflow |
156 | 0 | return ErrCode::Failed; |
157 | | |
158 | 0 | if ((size_t)lercInfo.blobSize + hdInfo.blobSize > (size_t)numBytesBlob) // truncated blob, we won't be able to read this band |
159 | 0 | return ErrCode::Failed; |
160 | | |
161 | 0 | lercInfo.zMin = min(lercInfo.zMin, hdInfo.zMin); |
162 | 0 | lercInfo.zMax = max(lercInfo.zMax, hdInfo.zMax); |
163 | 0 | lercInfo.maxZError = max(lercInfo.maxZError, hdInfo.maxZError); // with the new bitplane compression, maxZError can vary between bands |
164 | |
|
165 | 0 | if (pMins && pMaxs) |
166 | 0 | { |
167 | 0 | ErrCode errCode = GetRanges(pLercBlob + lercInfo.blobSize, numBytesBlob - lercInfo.blobSize, lercInfo.nBands, hdInfo, pMins, pMaxs, nElem); |
168 | 0 | if (errCode != ErrCode::Ok) |
169 | 0 | return errCode; |
170 | 0 | } |
171 | | |
172 | 0 | lercInfo.blobSize += hdInfo.blobSize; |
173 | 0 | lercInfo.nBands++; |
174 | 0 | } |
175 | | |
176 | 0 | lercInfo.nMasks = nMasks > 1 ? lercInfo.nBands : nMasks; |
177 | | |
178 | 0 | if (lercInfo.nUsesNoDataValue > 0) |
179 | 0 | lercInfo.nUsesNoDataValue = lercInfo.nBands; // if there is any noData used in any band, allow for different noData per band |
180 | |
|
181 | 0 | return ErrCode::Ok; |
182 | 0 | } |
183 | | |
184 | | |
185 | 9 | #ifdef HAVE_LERC1_DECODE |
186 | | // only if not Lerc2, try legacy Lerc1 |
187 | 9 | unsigned int numBytesHeaderBand0 = CntZImage::computeNumBytesNeededToReadHeader(false); |
188 | 9 | unsigned int numBytesHeaderBand1 = CntZImage::computeNumBytesNeededToReadHeader(true); |
189 | 9 | const Byte* pByte = pLercBlob; |
190 | | |
191 | 9 | lercInfo.zMin = FLT_MAX; |
192 | 9 | lercInfo.zMax = -FLT_MAX; |
193 | | |
194 | 9 | CntZImage cntZImg; |
195 | 9 | if (numBytesHeaderBand0 <= numBytesBlob && cntZImg.read(&pByte, pLercBlob + numBytesBlob, 1e12, true)) // read just the header |
196 | 0 | { |
197 | 0 | size_t nBytesRead = pByte - pLercBlob; |
198 | 0 | size_t nBytesNeeded = 10 + 4 * sizeof(int) + 1 * sizeof(double); |
199 | |
|
200 | 0 | if (nBytesRead < nBytesNeeded) |
201 | 0 | return ErrCode::Failed; |
202 | | |
203 | 0 | const Byte* ptr = pLercBlob; |
204 | 0 | ptr += 10 + 2 * sizeof(int); |
205 | |
|
206 | 0 | int height(0), width(0); |
207 | 0 | memcpy(&height, ptr, sizeof(int)); ptr += sizeof(int); |
208 | 0 | memcpy(&width, ptr, sizeof(int)); ptr += sizeof(int); |
209 | 0 | double maxZErrorInFile(0); |
210 | 0 | memcpy(&maxZErrorInFile, ptr, sizeof(double)); |
211 | |
|
212 | 0 | if (height < 0 || width < 0 || height > 40000 || width > 40000) // guard against bogus numbers; size limitation for old Lerc1 |
213 | 0 | return ErrCode::Failed; |
214 | | |
215 | 0 | if (sizeof(CntZ) * height * width > (size_t)INT_MAX) |
216 | 0 | return ErrCode::Failed; |
217 | | |
218 | 0 | lercInfo.nDepth = 1; |
219 | 0 | lercInfo.nCols = width; |
220 | 0 | lercInfo.nRows = height; |
221 | 0 | lercInfo.dt = Lerc::DT_Float; |
222 | 0 | lercInfo.maxZError = maxZErrorInFile; |
223 | |
|
224 | 0 | pByte = pLercBlob; |
225 | 0 | bool onlyZPart = false; |
226 | |
|
227 | 0 | while (lercInfo.blobSize + numBytesHeaderBand1 < numBytesBlob) // means there could be another band |
228 | 0 | { |
229 | 0 | if (!cntZImg.read(&pByte, pLercBlob + numBytesBlob, 1e12, false, onlyZPart)) |
230 | 0 | return (lercInfo.nBands > 0) ? ErrCode::Ok : ErrCode::Failed; // no other band, we are done |
231 | | |
232 | 0 | onlyZPart = true; |
233 | 0 | lercInfo.blobSize = (int)(pByte - pLercBlob); |
234 | | |
235 | | // now that we have decoded it, we can go the extra mile and collect some extra info |
236 | 0 | int numValidPixels = 0; |
237 | 0 | float zMin = FLT_MAX; |
238 | 0 | float zMax = -FLT_MAX; |
239 | |
|
240 | 0 | for (int i = 0; i < height; i++) |
241 | 0 | { |
242 | 0 | for (int j = 0; j < width; j++) |
243 | 0 | if (cntZImg(i, j).cnt > 0) |
244 | 0 | { |
245 | 0 | numValidPixels++; |
246 | 0 | float z = cntZImg(i, j).z; |
247 | 0 | zMax = max(zMax, z); |
248 | 0 | zMin = min(zMin, z); |
249 | 0 | } |
250 | 0 | } |
251 | |
|
252 | 0 | lercInfo.numValidPixel = numValidPixels; |
253 | 0 | lercInfo.zMin = std::min(lercInfo.zMin, (double)zMin); |
254 | 0 | lercInfo.zMax = std::max(lercInfo.zMax, (double)zMax); |
255 | 0 | lercInfo.nMasks = numValidPixels < width * height ? 1 : 0; |
256 | |
|
257 | 0 | if (pMins && pMaxs) |
258 | 0 | { |
259 | 0 | pMins[lercInfo.nBands] = zMin; |
260 | 0 | pMaxs[lercInfo.nBands] = zMax; |
261 | 0 | } |
262 | |
|
263 | 0 | lercInfo.nBands++; |
264 | 0 | } |
265 | | |
266 | 0 | return ErrCode::Ok; |
267 | 0 | } |
268 | 9 | #endif |
269 | | |
270 | 9 | return ErrCode::Failed; |
271 | 9 | } |
272 | | |
273 | | // -------------------------------------------------------------------------- ; |
274 | | |
275 | | ErrCode Lerc::Decode(const Byte* pLercBlob, unsigned int numBytesBlob, int nMasks, Byte* pValidBytes, |
276 | | int nDepth, int nCols, int nRows, int nBands, DataType dt, void* pData, unsigned char* pUsesNoData, double* noDataValues) |
277 | 0 | { |
278 | 0 | #define LERC_ARG_3 pLercBlob, numBytesBlob, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, pUsesNoData, noDataValues |
279 | |
|
280 | 0 | switch (dt) |
281 | 0 | { |
282 | 0 | case DT_Char: return DecodeTempl((signed char*)pData, LERC_ARG_3); |
283 | 0 | case DT_Byte: return DecodeTempl((Byte*)pData, LERC_ARG_3); |
284 | 0 | case DT_Short: return DecodeTempl((short*)pData, LERC_ARG_3); |
285 | 0 | case DT_UShort: return DecodeTempl((unsigned short*)pData, LERC_ARG_3); |
286 | 0 | case DT_Int: return DecodeTempl((int*)pData, LERC_ARG_3); |
287 | 0 | case DT_UInt: return DecodeTempl((unsigned int*)pData, LERC_ARG_3); |
288 | 0 | case DT_Float: return DecodeTempl((float*)pData, LERC_ARG_3); |
289 | 0 | case DT_Double: return DecodeTempl((double*)pData, LERC_ARG_3); |
290 | | |
291 | 0 | default: |
292 | 0 | return ErrCode::WrongParam; |
293 | 0 | } |
294 | |
|
295 | 0 | #undef LERC_ARG_3 |
296 | 0 | } |
297 | | |
298 | | // -------------------------------------------------------------------------- ; |
299 | | |
300 | | ErrCode Lerc::ConvertToDouble(const void* pDataIn, DataType dt, size_t nDataValues, double* pDataOut) |
301 | 0 | { |
302 | 0 | switch (dt) |
303 | 0 | { |
304 | 0 | case DT_Char: return ConvertToDoubleTempl((const signed char*)pDataIn, nDataValues, pDataOut); |
305 | 0 | case DT_Byte: return ConvertToDoubleTempl((const Byte*)pDataIn, nDataValues, pDataOut); |
306 | 0 | case DT_Short: return ConvertToDoubleTempl((const short*)pDataIn, nDataValues, pDataOut); |
307 | 0 | case DT_UShort: return ConvertToDoubleTempl((const unsigned short*)pDataIn, nDataValues, pDataOut); |
308 | 0 | case DT_Int: return ConvertToDoubleTempl((const int*)pDataIn, nDataValues, pDataOut); |
309 | 0 | case DT_UInt: return ConvertToDoubleTempl((const unsigned int*)pDataIn, nDataValues, pDataOut); |
310 | 0 | case DT_Float: return ConvertToDoubleTempl((const float*)pDataIn, nDataValues, pDataOut); |
311 | | //case DT_Double: no convert double to double |
312 | | |
313 | 0 | default: |
314 | 0 | return ErrCode::WrongParam; |
315 | 0 | } |
316 | 0 | } |
317 | | |
318 | | // -------------------------------------------------------------------------- ; |
319 | | // -------------------------------------------------------------------------- ; |
320 | | |
321 | | template<class T> |
322 | | ErrCode Lerc::ComputeCompressedSizeTempl(const T* pData, int version, int nDepth, int nCols, int nRows, |
323 | | int nBands, int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded, |
324 | | const unsigned char* pUsesNoData, const double* noDataValues) |
325 | 0 | { |
326 | 0 | numBytesNeeded = 0; |
327 | |
|
328 | 0 | if (!pData || nDepth <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || maxZErr < 0) |
329 | 0 | return ErrCode::WrongParam; |
330 | | |
331 | 0 | if (!(nMasks == 0 || nMasks == 1 || nMasks == nBands) || (nMasks > 0 && !pValidBytes)) |
332 | 0 | return ErrCode::WrongParam; |
333 | | |
334 | 0 | if (!CheckDimensions(nDepth, nCols, nRows, sizeof(T))) |
335 | 0 | return ErrCode::DimensionsTooLarge; |
336 | | |
337 | 0 | unsigned int numBytesWritten = 0; |
338 | |
|
339 | 0 | if (version >= 0 && version <= 5) |
340 | 0 | { |
341 | 0 | if (pUsesNoData) |
342 | 0 | for (int i = 0; i < nBands; i++) |
343 | 0 | if (pUsesNoData[i]) |
344 | 0 | return ErrCode::WrongParam; |
345 | | |
346 | 0 | return EncodeInternal_v5(pData, version, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, |
347 | 0 | numBytesNeeded, nullptr, 0, numBytesWritten); |
348 | 0 | } |
349 | 0 | else |
350 | 0 | { |
351 | 0 | return EncodeInternal(pData, version, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, |
352 | 0 | numBytesNeeded, nullptr, 0, numBytesWritten, pUsesNoData, noDataValues); |
353 | 0 | } |
354 | 0 | } Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<signed char>(signed char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<unsigned char>(unsigned char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<short>(short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<unsigned short>(unsigned short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<int>(int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<unsigned int>(unsigned int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<float>(float const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ComputeCompressedSizeTempl<double>(double const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char const*, double const*) |
355 | | |
356 | | // -------------------------------------------------------------------------- ; |
357 | | |
358 | | template<class T> |
359 | | ErrCode Lerc::EncodeTempl(const T* pData, int version, int nDepth, int nCols, int nRows, int nBands, |
360 | | int nMasks, const Byte* pValidBytes, double maxZErr, Byte* pBuffer, unsigned int numBytesBuffer, |
361 | | unsigned int& numBytesWritten, const unsigned char* pUsesNoData, const double* noDataValues) |
362 | 0 | { |
363 | 0 | numBytesWritten = 0; |
364 | |
|
365 | 0 | if (!pData || nDepth <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || maxZErr < 0 || !pBuffer || !numBytesBuffer) |
366 | 0 | return ErrCode::WrongParam; |
367 | | |
368 | 0 | if (!(nMasks == 0 || nMasks == 1 || nMasks == nBands) || (nMasks > 0 && !pValidBytes)) |
369 | 0 | return ErrCode::WrongParam; |
370 | | |
371 | 0 | if (!CheckDimensions(nDepth, nCols, nRows, sizeof(T))) |
372 | 0 | return ErrCode::DimensionsTooLarge; |
373 | | |
374 | 0 | memset(pBuffer, 0, (size_t)numBytesBuffer); |
375 | |
|
376 | 0 | unsigned int numBytesNeeded = 0; |
377 | |
|
378 | 0 | if (version >= 0 && version <= 5) |
379 | 0 | { |
380 | 0 | if (pUsesNoData) |
381 | 0 | for (int i = 0; i < nBands; i++) |
382 | 0 | if (pUsesNoData[i]) |
383 | 0 | return ErrCode::WrongParam; |
384 | | |
385 | 0 | return EncodeInternal_v5(pData, version, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, |
386 | 0 | numBytesNeeded, pBuffer, numBytesBuffer, numBytesWritten); |
387 | 0 | } |
388 | 0 | else |
389 | 0 | { |
390 | 0 | return EncodeInternal(pData, version, nDepth, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, |
391 | 0 | numBytesNeeded, pBuffer, numBytesBuffer, numBytesWritten, pUsesNoData, noDataValues); |
392 | 0 | } |
393 | 0 | } Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<signed char>(signed char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<unsigned char>(unsigned char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<short>(short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<unsigned short>(unsigned short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<int>(int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<unsigned int>(unsigned int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<float>(float const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeTempl<double>(double const*, int, int, int, int, int, int, unsigned char const*, double, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) |
394 | | |
395 | | // -------------------------------------------------------------------------- ; |
396 | | |
397 | | template<class T> |
398 | | ErrCode Lerc::DecodeTempl(T* pData, const Byte* pLercBlob, unsigned int numBytesBlob, |
399 | | int nDepth, int nCols, int nRows, int nBands, int nMasks, Byte* pValidBytes, |
400 | | unsigned char* pUsesNoData, double* noDataValues) |
401 | 0 | { |
402 | 0 | if (!pData || nDepth <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || !pLercBlob || !numBytesBlob) |
403 | 0 | return ErrCode::WrongParam; |
404 | | |
405 | 0 | if (!(nMasks == 0 || nMasks == 1 || nMasks == nBands) || (nMasks > 0 && !pValidBytes)) |
406 | 0 | return ErrCode::WrongParam; |
407 | | |
408 | 0 | if (!CheckDimensions(nDepth, nCols, nRows, sizeof(T))) |
409 | 0 | return ErrCode::DimensionsTooLarge; |
410 | | |
411 | 0 | const Byte* pByte = pLercBlob; |
412 | 0 | Lerc2::HeaderInfo hdInfo; |
413 | 0 | bool bHasMask = false; |
414 | |
|
415 | 0 | if (Lerc2::GetHeaderInfo(pByte, numBytesBlob, hdInfo, bHasMask) && hdInfo.version >= 1) // if Lerc2 |
416 | 0 | { |
417 | 0 | LercInfo lercInfo; |
418 | 0 | ErrCode errCode = GetLercInfo(pLercBlob, numBytesBlob, lercInfo); // fast for Lerc2, does most checks |
419 | 0 | if (errCode != ErrCode::Ok) |
420 | 0 | return errCode; |
421 | | |
422 | | // caller must provide enough space for the masks that are there (e.g., if they differ between bands) |
423 | 0 | if (nMasks < lercInfo.nMasks) // 0, 1, or nBands |
424 | 0 | return ErrCode::WrongParam; |
425 | | |
426 | | // caller cannot ask for more bands than are there |
427 | 0 | if (nBands > lercInfo.nBands) |
428 | 0 | return ErrCode::WrongParam; |
429 | | |
430 | | // if Lerc blob has noData values not covered by the mask, caller must get it (make sure caller cannot miss it) |
431 | 0 | if (lercInfo.nUsesNoDataValue && nDepth > 1) |
432 | 0 | { |
433 | 0 | if (!pUsesNoData || !noDataValues) |
434 | 0 | return ErrCode::HasNoData; |
435 | | |
436 | 0 | try |
437 | 0 | { |
438 | 0 | memset(pUsesNoData, 0, nBands); |
439 | 0 | memset(noDataValues, 0, nBands * sizeof(double)); |
440 | 0 | } |
441 | 0 | catch (...) |
442 | 0 | { |
443 | 0 | return ErrCode::HasNoData; |
444 | 0 | } |
445 | 0 | } |
446 | | |
447 | 0 | size_t nBytesRemaining = numBytesBlob; |
448 | 0 | Lerc2 lerc2; |
449 | 0 | BitMask bitMask; |
450 | |
|
451 | 0 | for (int iBand = 0; iBand < nBands; iBand++) |
452 | 0 | { |
453 | 0 | if (((size_t)(pByte - pLercBlob) < numBytesBlob) && Lerc2::GetHeaderInfo(pByte, nBytesRemaining, hdInfo, bHasMask)) |
454 | 0 | { |
455 | 0 | if (hdInfo.nDepth != nDepth || hdInfo.nCols != nCols || hdInfo.nRows != nRows || hdInfo.blobSize < 0) |
456 | 0 | return ErrCode::Failed; |
457 | | |
458 | 0 | if ((pByte - pLercBlob) + (size_t)hdInfo.blobSize > numBytesBlob) // corrupted blob |
459 | 0 | return ErrCode::Failed; |
460 | | |
461 | 0 | size_t nPix = (size_t)iBand * nRows * nCols; |
462 | 0 | T* arr = pData + nPix * nDepth; |
463 | |
|
464 | 0 | bool bGetMask = iBand < nMasks; |
465 | |
|
466 | 0 | if (bGetMask && !bitMask.SetSize(nCols, nRows)) |
467 | 0 | return ErrCode::Failed; |
468 | | |
469 | 0 | if (!lerc2.Decode(&pByte, nBytesRemaining, arr, bGetMask ? bitMask.Bits() : nullptr)) |
470 | 0 | return ErrCode::Failed; |
471 | | |
472 | 0 | if (lercInfo.nUsesNoDataValue && nDepth > 1) |
473 | 0 | { |
474 | 0 | pUsesNoData[iBand] = hdInfo.bPassNoDataValues ? 1 : 0; |
475 | 0 | noDataValues[iBand] = hdInfo.noDataValOrig; |
476 | |
|
477 | 0 | if (hdInfo.bPassNoDataValues && !RemapNoData(arr, bitMask, hdInfo)) |
478 | 0 | return ErrCode::Failed; |
479 | 0 | } |
480 | | |
481 | 0 | if (bGetMask && !Convert(bitMask, pValidBytes + nPix)) |
482 | 0 | return ErrCode::Failed; |
483 | 0 | } |
484 | 0 | } // iBand |
485 | 0 | } // Lerc2 |
486 | | |
487 | 0 | else // might be old Lerc1 |
488 | 0 | { |
489 | 0 | #ifdef HAVE_LERC1_DECODE |
490 | 0 | unsigned int numBytesHeaderBand0 = CntZImage::computeNumBytesNeededToReadHeader(false); |
491 | 0 | unsigned int numBytesHeaderBand1 = CntZImage::computeNumBytesNeededToReadHeader(true); |
492 | 0 | const Byte* pByte1 = pLercBlob; |
493 | 0 | CntZImage zImg; |
494 | |
|
495 | 0 | for (int iBand = 0; iBand < nBands; iBand++) |
496 | 0 | { |
497 | 0 | unsigned int numBytesHeader = iBand == 0 ? numBytesHeaderBand0 : numBytesHeaderBand1; |
498 | 0 | if ((size_t)(pByte1 - pLercBlob) + numBytesHeader > numBytesBlob) // corrupted blob or wrong nBands |
499 | 0 | return ErrCode::Failed; |
500 | | |
501 | 0 | bool onlyZPart = iBand > 0; |
502 | 0 | if (!zImg.read(&pByte1, pLercBlob + numBytesBlob, 1e12, false, onlyZPart)) |
503 | 0 | return ErrCode::Failed; |
504 | | |
505 | 0 | if (zImg.getWidth() != nCols || zImg.getHeight() != nRows) |
506 | 0 | return ErrCode::Failed; |
507 | | |
508 | 0 | size_t nPix = (size_t)iBand * nRows * nCols; |
509 | 0 | T* arr = pData + nPix; |
510 | 0 | Byte* pDst = iBand < nMasks ? pValidBytes + nPix : nullptr; |
511 | |
|
512 | 0 | if (!Convert(zImg, arr, pDst, iBand == 0)) |
513 | 0 | return ErrCode::Failed; |
514 | 0 | } |
515 | | #else |
516 | | return ErrCode::Failed; |
517 | | #endif |
518 | 0 | } |
519 | | |
520 | 0 | return ErrCode::Ok; |
521 | 0 | } Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<signed char>(signed char*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<unsigned char>(unsigned char*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<short>(short*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<unsigned short>(unsigned short*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<int>(int*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<unsigned int>(unsigned int*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<float>(float*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::DecodeTempl<double>(double*, unsigned char const*, unsigned int, int, int, int, int, int, unsigned char*, unsigned char*, double*) |
522 | | |
523 | | // -------------------------------------------------------------------------- ; |
524 | | // -------------------------------------------------------------------------- ; |
525 | | |
526 | | template<class T> |
527 | | ErrCode Lerc::EncodeInternal_v5(const T* pData, int version, int nDepth, int nCols, int nRows, int nBands, |
528 | | int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded, |
529 | | Byte* pBuffer, unsigned int numBytesBuffer, unsigned int& numBytesWritten) |
530 | 0 | { |
531 | 0 | numBytesNeeded = 0; |
532 | 0 | numBytesWritten = 0; |
533 | |
|
534 | 0 | Lerc2 lerc2; |
535 | 0 | if (version >= 0 && !lerc2.SetEncoderToOldVersion(version)) |
536 | 0 | return ErrCode::WrongParam; |
537 | | |
538 | 0 | Byte* pDst = pBuffer; |
539 | |
|
540 | 0 | const size_t nPix = (size_t)nCols * nRows; |
541 | 0 | const size_t nElem = nPix * nDepth; |
542 | |
|
543 | 0 | const Byte* pPrevByteMask = nullptr; |
544 | 0 | vector<T> dataBuffer; |
545 | 0 | vector<Byte> maskBuffer, prevMaskBuffer; |
546 | 0 | BitMask bitMask; |
547 | | |
548 | | // loop over the bands |
549 | 0 | for (int iBand = 0; iBand < nBands; iBand++) |
550 | 0 | { |
551 | 0 | bool bEncMsk = (iBand == 0); |
552 | | |
553 | | // using the proper section of valid bytes, check this band for NaN |
554 | 0 | const T* arr = pData + nElem * iBand; |
555 | 0 | const Byte* pByteMask = (nMasks > 0) ? (pValidBytes + ((nMasks > 1) ? nPix * iBand : 0)) : nullptr; |
556 | |
|
557 | 0 | ErrCode errCode = CheckForNaN(arr, nDepth, nCols, nRows, pByteMask); |
558 | 0 | if (errCode != ErrCode::Ok && errCode != ErrCode::NaN) |
559 | 0 | return errCode; |
560 | | |
561 | 0 | if (errCode == ErrCode::NaN) // found NaN values |
562 | 0 | { |
563 | 0 | if (!Resize(dataBuffer, nElem) || !Resize(maskBuffer, nPix)) |
564 | 0 | return ErrCode::Failed; |
565 | | |
566 | 0 | memcpy(&dataBuffer[0], arr, nElem * sizeof(T)); |
567 | 0 | pByteMask ? memcpy(&maskBuffer[0], pByteMask, nPix) : memset(&maskBuffer[0], 1, nPix); |
568 | |
|
569 | 0 | if (!ReplaceNaNValues(dataBuffer, maskBuffer, nDepth, nCols, nRows)) |
570 | 0 | return ErrCode::Failed; |
571 | | |
572 | 0 | if (iBand > 0 && MasksDiffer(&maskBuffer[0], pPrevByteMask, nPix)) |
573 | 0 | bEncMsk = true; |
574 | |
|
575 | 0 | if (iBand < nBands - 1) |
576 | 0 | { |
577 | | // keep current mask as new previous band mask |
578 | 0 | prevMaskBuffer = maskBuffer; |
579 | 0 | pPrevByteMask = &prevMaskBuffer[0]; |
580 | 0 | } |
581 | |
|
582 | 0 | arr = &dataBuffer[0]; |
583 | 0 | pByteMask = &maskBuffer[0]; |
584 | 0 | } |
585 | | |
586 | 0 | else // no NaN in this band, the common case |
587 | 0 | { |
588 | 0 | if (iBand > 0 && MasksDiffer(pByteMask, pPrevByteMask, nPix)) |
589 | 0 | bEncMsk = true; |
590 | |
|
591 | 0 | pPrevByteMask = pByteMask; |
592 | 0 | } |
593 | | |
594 | 0 | if (bEncMsk) |
595 | 0 | { |
596 | 0 | if (pByteMask && !Convert(pByteMask, nCols, nRows, bitMask)) |
597 | 0 | return ErrCode::Failed; |
598 | | |
599 | 0 | if (!lerc2.Set(nDepth, nCols, nRows, pByteMask ? bitMask.Bits() : nullptr)) |
600 | 0 | return ErrCode::Failed; |
601 | 0 | } |
602 | | |
603 | 0 | unsigned int nBytes = lerc2.ComputeNumBytesNeededToWrite(arr, maxZErr, bEncMsk); |
604 | 0 | if (nBytes <= 0) |
605 | 0 | return ErrCode::Failed; |
606 | | |
607 | 0 | if ((size_t)numBytesNeeded + nBytes > (size_t)UINT_MAX) // keep total blob size (over all bands) <= 4 GB |
608 | 0 | return ErrCode::DimensionsTooLarge; |
609 | | |
610 | 0 | numBytesNeeded += nBytes; |
611 | |
|
612 | 0 | if (pBuffer) |
613 | 0 | { |
614 | 0 | if ((size_t)(pDst - pBuffer) + nBytes > numBytesBuffer) // check we have enough space left |
615 | 0 | return ErrCode::BufferTooSmall; |
616 | | |
617 | 0 | if (!lerc2.Encode(arr, &pDst)) |
618 | 0 | return ErrCode::Failed; |
619 | 0 | } |
620 | 0 | } // iBand |
621 | | |
622 | 0 | numBytesWritten = (unsigned int)(pDst - pBuffer); |
623 | 0 | return ErrCode::Ok; |
624 | 0 | } Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<signed char>(signed char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<unsigned char>(unsigned char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<short>(short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<unsigned short>(unsigned short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<int>(int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<unsigned int>(unsigned int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<float>(float const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal_v5<double>(double const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&) |
625 | | |
626 | | // -------------------------------------------------------------------------- ; |
627 | | |
628 | | template<class T> |
629 | | ErrCode Lerc::EncodeInternal(const T* pData, int version, int nDepth, int nCols, int nRows, int nBands, |
630 | | int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded, |
631 | | Byte* pBuffer, unsigned int numBytesBuffer, unsigned int& numBytesWritten, |
632 | | const unsigned char* pUsesNoData, const double* noDataValues) |
633 | 0 | { |
634 | 0 | numBytesNeeded = 0; |
635 | 0 | numBytesWritten = 0; |
636 | |
|
637 | 0 | if (version >= 0 && version <= 5) |
638 | 0 | return ErrCode::WrongParam; |
639 | | |
640 | 0 | Lerc2 lerc2; |
641 | |
|
642 | | #ifdef ENCODE_VERIFY |
643 | | Lerc2 lerc2Verify; |
644 | | #endif |
645 | |
|
646 | 0 | if (version >= 0 && !lerc2.SetEncoderToOldVersion(version)) |
647 | 0 | return ErrCode::WrongParam; |
648 | | |
649 | 0 | if (pUsesNoData && !noDataValues) |
650 | 0 | for (int i = 0; i < nBands; i++) |
651 | 0 | if (pUsesNoData[i]) |
652 | 0 | return ErrCode::WrongParam; |
653 | | |
654 | 0 | Byte* pDst = pBuffer; |
655 | |
|
656 | 0 | const size_t nPix = (size_t)nCols * nRows; |
657 | 0 | const size_t nElem = nPix * nDepth; |
658 | |
|
659 | 0 | const Byte* pPrevByteMask = nullptr; |
660 | 0 | vector<T> dataBuffer; |
661 | 0 | vector<Byte> maskBuffer, prevMaskBuffer; |
662 | 0 | BitMask bitMask; |
663 | | |
664 | | // allocate buffer for 1 band |
665 | 0 | if (!Resize(dataBuffer, nElem) || !Resize(maskBuffer, nPix)) |
666 | 0 | return ErrCode::Failed; |
667 | | |
668 | 0 | bool bIsFltOrDbl = (typeid(T) == typeid(float) || typeid(T) == typeid(double)); |
669 | 0 | bool bAnyMaskModified = false; |
670 | 0 | ErrCode errCode = ErrCode::Ok; |
671 | | |
672 | | // loop over the bands |
673 | 0 | for (int iBand = 0; iBand < nBands; iBand++) |
674 | 0 | { |
675 | 0 | bool bEncMsk = (iBand == 0); |
676 | | |
677 | | // get the data and mask for this band |
678 | 0 | const T* arrOrig = pData + nElem * iBand; |
679 | 0 | const Byte* pByteMaskOrig = (nMasks > 0) ? (pValidBytes + ((nMasks > 1) ? nPix * iBand : 0)) : nullptr; |
680 | | |
681 | | // copy to buffer so we can modify it |
682 | 0 | memcpy(&dataBuffer[0], arrOrig, nElem * sizeof(T)); |
683 | 0 | pByteMaskOrig ? memcpy(&maskBuffer[0], pByteMaskOrig, nPix) : memset(&maskBuffer[0], 1, nPix); |
684 | |
|
685 | 0 | double maxZErrL = maxZErr; // maxZErrL can get modified in the filter functions below |
686 | |
|
687 | 0 | bool bPassNoDataValue = (pUsesNoData && (pUsesNoData[iBand] > 0)); |
688 | 0 | const double noDataOrig = bPassNoDataValue ? noDataValues[iBand] : 0; |
689 | |
|
690 | 0 | double noDataL = noDataOrig; // noDataL can get modified in the filter functions below |
691 | |
|
692 | 0 | bool bIsFltDblAllInt = false; // are the flt numbers all integer really? Double can be used for int numbers beyond 32 bit range |
693 | 0 | bool bModifiedMask = false; // can turn true if NaN or noData found at valid pixels |
694 | 0 | bool bNeedNoData = false; // can only turn true for nDepth > 1, and mix of valid and invalid values at the same pixel (special case) |
695 | 0 | errCode = ErrCode::Ok; |
696 | |
|
697 | 0 | double minVal(+1), maxVal(-1); |
698 | 0 | lerc2.ClearMinMax(); |
699 | |
|
700 | 0 | if (bIsFltOrDbl) // if flt type, filter out NaN and / or noData values and update the mask if possible |
701 | 0 | { |
702 | 0 | errCode = FilterNoDataAndNaN(dataBuffer, maskBuffer, nDepth, nCols, nRows, maxZErrL, bPassNoDataValue, noDataL, |
703 | 0 | bModifiedMask, bNeedNoData, bIsFltDblAllInt, minVal, maxVal); |
704 | 0 | } |
705 | 0 | else if (bPassNoDataValue) // if int type (no NaN), and no noData value specified, nothing to do |
706 | 0 | { |
707 | 0 | errCode = FilterNoData(dataBuffer, maskBuffer, nDepth, nCols, nRows, maxZErrL, bPassNoDataValue, noDataL, |
708 | 0 | bModifiedMask, bNeedNoData, minVal, maxVal); |
709 | 0 | } |
710 | |
|
711 | 0 | if (errCode != ErrCode::Ok) |
712 | 0 | return errCode; |
713 | | |
714 | 0 | if (bModifiedMask) |
715 | 0 | bAnyMaskModified = true; |
716 | |
|
717 | 0 | bool bCompareMasks = (nMasks > 1) || bAnyMaskModified; |
718 | |
|
719 | 0 | if (bCompareMasks && (iBand > 0) && MasksDiffer(&maskBuffer[0], pPrevByteMask, nPix)) |
720 | 0 | bEncMsk = true; |
721 | |
|
722 | 0 | if (nBands > 1 && iBand < nBands - 1) |
723 | 0 | { |
724 | | // keep current mask as new previous band mask |
725 | 0 | prevMaskBuffer = maskBuffer; |
726 | 0 | pPrevByteMask = &prevMaskBuffer[0]; |
727 | 0 | } |
728 | |
|
729 | 0 | const T* arrL = &dataBuffer[0]; |
730 | 0 | const Byte* pByteMaskL = &maskBuffer[0]; |
731 | |
|
732 | 0 | if (bEncMsk) |
733 | 0 | { |
734 | 0 | bool bAllValid = !memchr(pByteMaskL, 0, nPix); |
735 | |
|
736 | 0 | if (!bAllValid && !Convert(pByteMaskL, nCols, nRows, bitMask)) |
737 | 0 | return ErrCode::Failed; |
738 | | |
739 | 0 | if (!lerc2.Set(nDepth, nCols, nRows, !bAllValid ? bitMask.Bits() : nullptr)) |
740 | 0 | return ErrCode::Failed; |
741 | 0 | } |
742 | | |
743 | | // set other flags |
744 | 0 | if ( !lerc2.SetNoDataValues(bNeedNoData, noDataL, noDataOrig) |
745 | 0 | || !lerc2.SetNumBlobsMoreToCome(nBands - 1 - iBand) |
746 | 0 | || !lerc2.SetIsAllInt(bIsFltDblAllInt)) |
747 | 0 | return ErrCode::Failed; |
748 | | |
749 | 0 | if (nDepth == 1 && (maxVal >= minVal) |
750 | 0 | && !lerc2.SetMinMax(nDepth, minVal, maxVal)) |
751 | 0 | return ErrCode::Failed; |
752 | | |
753 | 0 | unsigned int nBytes = lerc2.ComputeNumBytesNeededToWrite(arrL, maxZErrL, bEncMsk); |
754 | 0 | if (nBytes <= 0) |
755 | 0 | return ErrCode::Failed; |
756 | | |
757 | 0 | if ((size_t)numBytesNeeded + nBytes > (size_t)UINT_MAX) // keep total blob size (over all bands) <= 4 GB |
758 | 0 | return ErrCode::DimensionsTooLarge; |
759 | | |
760 | 0 | numBytesNeeded += nBytes; |
761 | |
|
762 | 0 | if (pBuffer) |
763 | 0 | { |
764 | 0 | if ((size_t)(pDst - pBuffer) + nBytes > numBytesBuffer) // check we have enough space left |
765 | 0 | return ErrCode::BufferTooSmall; |
766 | | |
767 | | #ifdef ENCODE_VERIFY |
768 | | const Byte* pDst0 = pDst; |
769 | | #endif |
770 | | |
771 | 0 | if (!lerc2.Encode(arrL, &pDst)) |
772 | 0 | return ErrCode::Failed; |
773 | |
|
774 | | #ifdef ENCODE_VERIFY |
775 | | size_t blobSize = pDst - pDst0; |
776 | | |
777 | | if (!DecodeAndCompareToInput(pDst0, blobSize, maxZErrL, lerc2Verify, arrL, pByteMaskL, |
778 | | arrOrig, pByteMaskOrig, bPassNoDataValue, noDataOrig, bModifiedMask)) |
779 | | { |
780 | | return ErrCode::Failed; |
781 | | } |
782 | | #endif |
783 | |
|
784 | 0 | } |
785 | 0 | } // iBand |
786 | | |
787 | 0 | numBytesWritten = (unsigned int)(pDst - pBuffer); |
788 | 0 | return ErrCode::Ok; |
789 | 0 | } Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<signed char>(signed char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<unsigned char>(unsigned char const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<short>(short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<unsigned short>(unsigned short const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<int>(int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<unsigned int>(unsigned int const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<float>(float const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::EncodeInternal<double>(double const*, int, int, int, int, int, int, unsigned char const*, double, unsigned int&, unsigned char*, unsigned int, unsigned int&, unsigned char const*, double const*) |
790 | | |
791 | | // -------------------------------------------------------------------------- ; |
792 | | |
793 | | #ifdef HAVE_LERC1_DECODE |
794 | | template<class T> |
795 | | bool Lerc::Convert(const CntZImage& zImg, T* arr, Byte* pByteMask, bool bMustFillMask) |
796 | 0 | { |
797 | 0 | if (!arr || !zImg.getSize()) |
798 | 0 | return false; |
799 | | |
800 | 0 | const bool fltPnt = (typeid(*arr) == typeid(double)) || (typeid(*arr) == typeid(float)); |
801 | |
|
802 | 0 | int h = zImg.getHeight(); |
803 | 0 | int w = zImg.getWidth(); |
804 | |
|
805 | 0 | const CntZ* srcPtr = zImg.getData(); |
806 | 0 | T* dstPtr = arr; |
807 | 0 | int num = w * h; |
808 | |
|
809 | 0 | if (pByteMask) |
810 | 0 | { |
811 | 0 | memset(pByteMask, 0, num); |
812 | |
|
813 | 0 | for (int k = 0; k < num; k++) |
814 | 0 | { |
815 | 0 | if (srcPtr->cnt > 0) |
816 | 0 | { |
817 | 0 | *dstPtr = fltPnt ? (T)srcPtr->z : (T)floor(srcPtr->z + 0.5); |
818 | 0 | pByteMask[k] = 1; |
819 | 0 | } |
820 | |
|
821 | 0 | srcPtr++; |
822 | 0 | dstPtr++; |
823 | 0 | } |
824 | 0 | } |
825 | 0 | else |
826 | 0 | { |
827 | 0 | for (int k = 0; k < num; k++) |
828 | 0 | { |
829 | 0 | if (srcPtr->cnt > 0) |
830 | 0 | { |
831 | 0 | *dstPtr = fltPnt ? (T)srcPtr->z : (T)floor(srcPtr->z + 0.5); |
832 | 0 | } |
833 | 0 | else if (bMustFillMask) |
834 | 0 | return false; |
835 | | |
836 | 0 | srcPtr++; |
837 | 0 | dstPtr++; |
838 | 0 | } |
839 | 0 | } |
840 | | |
841 | 0 | return true; |
842 | 0 | } Unexecuted instantiation: bool LercNS::Lerc::Convert<signed char>(LercNS::CntZImage const&, signed char*, unsigned char*, bool) Unexecuted instantiation: bool LercNS::Lerc::Convert<unsigned char>(LercNS::CntZImage const&, unsigned char*, unsigned char*, bool) Unexecuted instantiation: bool LercNS::Lerc::Convert<short>(LercNS::CntZImage const&, short*, unsigned char*, bool) Unexecuted instantiation: bool LercNS::Lerc::Convert<unsigned short>(LercNS::CntZImage const&, unsigned short*, unsigned char*, bool) Unexecuted instantiation: bool LercNS::Lerc::Convert<int>(LercNS::CntZImage const&, int*, unsigned char*, bool) Unexecuted instantiation: bool LercNS::Lerc::Convert<unsigned int>(LercNS::CntZImage const&, unsigned int*, unsigned char*, bool) Unexecuted instantiation: bool LercNS::Lerc::Convert<float>(LercNS::CntZImage const&, float*, unsigned char*, bool) Unexecuted instantiation: bool LercNS::Lerc::Convert<double>(LercNS::CntZImage const&, double*, unsigned char*, bool) |
843 | | #endif |
844 | | |
845 | | // -------------------------------------------------------------------------- ; |
846 | | |
847 | | template<class T> |
848 | | ErrCode Lerc::ConvertToDoubleTempl(const T* pDataIn, size_t nDataValues, double* pDataOut) |
849 | 0 | { |
850 | 0 | if (!pDataIn || !nDataValues || !pDataOut) |
851 | 0 | return ErrCode::WrongParam; |
852 | | |
853 | 0 | for (size_t k = 0; k < nDataValues; k++) |
854 | 0 | pDataOut[k] = pDataIn[k]; |
855 | |
|
856 | 0 | return ErrCode::Ok; |
857 | 0 | } Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<signed char>(signed char const*, unsigned long, double*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<unsigned char>(unsigned char const*, unsigned long, double*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<short>(short const*, unsigned long, double*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<unsigned short>(unsigned short const*, unsigned long, double*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<int>(int const*, unsigned long, double*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<unsigned int>(unsigned int const*, unsigned long, double*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::ConvertToDoubleTempl<float>(float const*, unsigned long, double*) |
858 | | |
859 | | // -------------------------------------------------------------------------- ; |
860 | | |
861 | | template<class T> ErrCode Lerc::CheckForNaN(const T* arr, int nDepth, int nCols, int nRows, const Byte* pByteMask) |
862 | 0 | { |
863 | 0 | if (!arr || nDepth <= 0 || nCols <= 0 || nRows <= 0) |
864 | 0 | return ErrCode::WrongParam; |
865 | | |
866 | 0 | if (typeid(T) != typeid(double) && typeid(T) != typeid(float)) |
867 | 0 | return ErrCode::Ok; |
868 | | |
869 | 0 | for (size_t k = 0, i = 0; i < (size_t)nRows; i++) |
870 | 0 | { |
871 | 0 | bool bFoundNaN = false; |
872 | 0 | const T* rowArr = &(arr[i * nCols * nDepth]); |
873 | |
|
874 | 0 | if (!pByteMask) // all valid |
875 | 0 | { |
876 | 0 | size_t num = (size_t)nCols * nDepth; |
877 | 0 | for (size_t m = 0; m < num; m++) |
878 | 0 | if (std::isnan((double)rowArr[m])) |
879 | 0 | bFoundNaN = true; |
880 | 0 | } |
881 | 0 | else // not all valid |
882 | 0 | { |
883 | 0 | for (size_t n = 0, j = 0; j < (size_t)nCols; j++, k++, n += nDepth) |
884 | 0 | if (pByteMask[k]) |
885 | 0 | { |
886 | 0 | for (int m = 0; m < nDepth; m++) |
887 | 0 | if (std::isnan((double)rowArr[n + m])) |
888 | 0 | bFoundNaN = true; |
889 | 0 | } |
890 | 0 | } |
891 | |
|
892 | 0 | if (bFoundNaN) |
893 | 0 | return ErrCode::NaN; |
894 | 0 | } |
895 | | |
896 | 0 | return ErrCode::Ok; |
897 | 0 | } Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<signed char>(signed char const*, int, int, int, unsigned char const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<unsigned char>(unsigned char const*, int, int, int, unsigned char const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<short>(short const*, int, int, int, unsigned char const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<unsigned short>(unsigned short const*, int, int, int, unsigned char const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<int>(int const*, int, int, int, unsigned char const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<unsigned int>(unsigned int const*, int, int, int, unsigned char const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<float>(float const*, int, int, int, unsigned char const*) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::CheckForNaN<double>(double const*, int, int, int, unsigned char const*) |
898 | | |
899 | | // -------------------------------------------------------------------------- ; |
900 | | |
901 | | template<class T> bool Lerc::ReplaceNaNValues(std::vector<T>& dataBuffer, std::vector<Byte>& maskBuffer, int nDepth, int nCols, int nRows) |
902 | 0 | { |
903 | 0 | if (nDepth <= 0 || nCols <= 0 || nRows <= 0 || dataBuffer.size() != (size_t)nDepth * nCols * nRows || maskBuffer.size() != (size_t)nCols * nRows) |
904 | 0 | return false; |
905 | | |
906 | 0 | T noDataValue = 0; |
907 | 0 | { |
908 | | #if defined _WIN32 |
909 | | #pragma warning(disable: 4756) // would trigger build warning in linux |
910 | | #endif |
911 | |
|
912 | 0 | noDataValue = (T)((typeid(T) == typeid(float)) ? -FLT_MAX : -DBL_MAX); |
913 | 0 | } |
914 | |
|
915 | 0 | for (size_t k = 0, i = 0; i < (size_t)nRows; i++) |
916 | 0 | { |
917 | 0 | T* rowArr = &(dataBuffer[i * nCols * nDepth]); |
918 | |
|
919 | 0 | for (size_t n = 0, j = 0; j < (size_t)nCols; j++, k++, n += nDepth) |
920 | 0 | { |
921 | 0 | if (maskBuffer[k]) |
922 | 0 | { |
923 | 0 | int cntNaN = 0; |
924 | |
|
925 | 0 | for (int m = 0; m < nDepth; m++) |
926 | 0 | if (std::isnan((double)rowArr[n + m])) |
927 | 0 | { |
928 | 0 | cntNaN++; |
929 | 0 | rowArr[n + m] = noDataValue; |
930 | 0 | } |
931 | |
|
932 | 0 | if (cntNaN == nDepth) |
933 | 0 | maskBuffer[k] = 0; |
934 | 0 | } |
935 | 0 | } |
936 | 0 | } |
937 | |
|
938 | 0 | return true; |
939 | 0 | } Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<signed char>(std::__1::vector<signed char, std::__1::allocator<signed char> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int) Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<unsigned char>(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int) Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<short>(std::__1::vector<short, std::__1::allocator<short> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int) Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<unsigned short>(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int) Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<int>(std::__1::vector<int, std::__1::allocator<int> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int) Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<unsigned int>(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int) Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<float>(std::__1::vector<float, std::__1::allocator<float> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int) Unexecuted instantiation: bool LercNS::Lerc::ReplaceNaNValues<double>(std::__1::vector<double, std::__1::allocator<double> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int) |
940 | | |
941 | | // -------------------------------------------------------------------------- ; |
942 | | |
943 | | template<class T> bool Lerc::Resize(std::vector<T>& buffer, size_t nElem) |
944 | 0 | { |
945 | 0 | try |
946 | 0 | { |
947 | 0 | buffer.resize(nElem); |
948 | 0 | } |
949 | 0 | catch (...) |
950 | 0 | { |
951 | 0 | return false; |
952 | 0 | } |
953 | | |
954 | 0 | return (buffer.size() == nElem); |
955 | 0 | } Unexecuted instantiation: bool LercNS::Lerc::Resize<signed char>(std::__1::vector<signed char, std::__1::allocator<signed char> >&, unsigned long) Unexecuted instantiation: bool LercNS::Lerc::Resize<unsigned char>(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, unsigned long) Unexecuted instantiation: bool LercNS::Lerc::Resize<short>(std::__1::vector<short, std::__1::allocator<short> >&, unsigned long) Unexecuted instantiation: bool LercNS::Lerc::Resize<unsigned short>(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> >&, unsigned long) Unexecuted instantiation: bool LercNS::Lerc::Resize<int>(std::__1::vector<int, std::__1::allocator<int> >&, unsigned long) Unexecuted instantiation: bool LercNS::Lerc::Resize<unsigned int>(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, unsigned long) Unexecuted instantiation: bool LercNS::Lerc::Resize<float>(std::__1::vector<float, std::__1::allocator<float> >&, unsigned long) Unexecuted instantiation: bool LercNS::Lerc::Resize<double>(std::__1::vector<double, std::__1::allocator<double> >&, unsigned long) |
956 | | |
957 | | // -------------------------------------------------------------------------- ; |
958 | | |
959 | | bool Lerc::Convert(const Byte* pByteMask, int nCols, int nRows, BitMask& bitMask) |
960 | 0 | { |
961 | 0 | if (!pByteMask || nCols <= 0 || nRows <= 0) |
962 | 0 | return false; |
963 | | |
964 | 0 | if (!bitMask.SetSize(nCols, nRows)) |
965 | 0 | return false; |
966 | | |
967 | 0 | bitMask.SetAllValid(); |
968 | |
|
969 | 0 | for (int k = 0, i = 0; i < nRows; i++) |
970 | 0 | for (int j = 0; j < nCols; j++, k++) |
971 | 0 | if (!pByteMask[k]) |
972 | 0 | bitMask.SetInvalid(k); |
973 | |
|
974 | 0 | return true; |
975 | 0 | } |
976 | | |
977 | | // -------------------------------------------------------------------------- ; |
978 | | |
979 | | bool Lerc::Convert(const BitMask& bitMask, Byte* pByteMask) |
980 | 0 | { |
981 | 0 | int nCols = bitMask.GetWidth(); |
982 | 0 | int nRows = bitMask.GetHeight(); |
983 | |
|
984 | 0 | if (nCols <= 0 || nRows <= 0 || !pByteMask) |
985 | 0 | return false; |
986 | | |
987 | 0 | memset(pByteMask, 0, (size_t)nCols * nRows); |
988 | |
|
989 | 0 | for (int k = 0, i = 0; i < nRows; i++) |
990 | 0 | for (int j = 0; j < nCols; j++, k++) |
991 | 0 | if (bitMask.IsValid(k)) |
992 | 0 | pByteMask[k] = 1; |
993 | |
|
994 | 0 | return true; |
995 | 0 | } |
996 | | |
997 | | // -------------------------------------------------------------------------- ; |
998 | | |
999 | | bool Lerc::MasksDiffer(const Byte* p0, const Byte* p1, size_t n) |
1000 | 0 | { |
1001 | 0 | if (p0 == p1) |
1002 | 0 | return false; |
1003 | | |
1004 | 0 | if (!p0) // means all valid |
1005 | 0 | return memchr(p1, 0, n); // any invalid? |
1006 | 0 | else if (!p1) |
1007 | 0 | return memchr(p0, 0, n); |
1008 | 0 | else |
1009 | 0 | return memcmp(p0, p1, n); |
1010 | 0 | } |
1011 | | |
1012 | | // -------------------------------------------------------------------------- ; |
1013 | | |
1014 | | ErrCode Lerc::GetRanges(const Byte* pLercBlob, unsigned int numBytesBlob, int iBand, |
1015 | | const struct Lerc2::HeaderInfo& lerc2Info, double* pMins, double* pMaxs, size_t nElem) |
1016 | 0 | { |
1017 | 0 | const int nDepth = lerc2Info.nDepth; |
1018 | |
|
1019 | 0 | if (nDepth <= 0 || iBand < 0 || !pMins || !pMaxs) |
1020 | 0 | return ErrCode::WrongParam; |
1021 | | |
1022 | 0 | if (nElem < ((size_t)iBand + 1) * (size_t)nDepth) |
1023 | 0 | return ErrCode::BufferTooSmall; |
1024 | | |
1025 | 0 | if (nDepth == 1) |
1026 | 0 | { |
1027 | 0 | pMins[iBand] = lerc2Info.zMin; |
1028 | 0 | pMaxs[iBand] = lerc2Info.zMax; |
1029 | 0 | } |
1030 | 0 | else |
1031 | 0 | { |
1032 | 0 | if (lerc2Info.bPassNoDataValues) // for nDepth > 1, and mix of valid and invalid values at same pixel, better fail |
1033 | 0 | return ErrCode::HasNoData; // than return min or max values that contain noData (to be fixed in next codec version) |
1034 | | |
1035 | | // read header, mask, ranges, and copy them out |
1036 | 0 | Lerc2 lerc2; |
1037 | 0 | if (!lerc2.GetRanges(pLercBlob, numBytesBlob, &pMins[iBand * nDepth], &pMaxs[iBand * nDepth])) |
1038 | 0 | return ErrCode::Failed; |
1039 | 0 | } |
1040 | | |
1041 | 0 | return ErrCode::Ok; |
1042 | 0 | } |
1043 | | |
1044 | | // -------------------------------------------------------------------------- ; |
1045 | | |
1046 | | template<class T> |
1047 | | bool Lerc::RemapNoData(T* data, const BitMask& bitMask, const struct Lerc2::HeaderInfo& lerc2Info) |
1048 | 0 | { |
1049 | 0 | int nCols = lerc2Info.nCols; |
1050 | 0 | int nRows = lerc2Info.nRows; |
1051 | 0 | int nDepth = lerc2Info.nDepth; |
1052 | |
|
1053 | 0 | if (!data || nCols <= 0 || nRows <= 0 || nDepth <= 0) |
1054 | 0 | return false; |
1055 | | |
1056 | 0 | const T noDataOld = (T)lerc2Info.noDataVal; |
1057 | 0 | const T noDataNew = (T)lerc2Info.noDataValOrig; |
1058 | |
|
1059 | 0 | if (noDataNew != noDataOld) |
1060 | 0 | { |
1061 | 0 | bool bUseMask = (bitMask.GetWidth() == nCols) && (bitMask.GetHeight() == nRows); |
1062 | |
|
1063 | 0 | for (long k = 0, i = 0; i < nRows; i++) |
1064 | 0 | { |
1065 | 0 | T* rowArr = &(data[i * nCols * nDepth]); |
1066 | |
|
1067 | 0 | for (long n = 0, j = 0; j < nCols; j++, k++, n += nDepth) |
1068 | 0 | if (!bUseMask || bitMask.IsValid(k)) |
1069 | 0 | for (long m = 0; m < nDepth; m++) |
1070 | 0 | if (rowArr[n + m] == noDataOld) |
1071 | 0 | rowArr[n + m] = noDataNew; |
1072 | 0 | } |
1073 | 0 | } |
1074 | |
|
1075 | 0 | return true; |
1076 | 0 | } Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<signed char>(signed char*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&) Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<unsigned char>(unsigned char*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&) Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<short>(short*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&) Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<unsigned short>(unsigned short*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&) Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<int>(int*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&) Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<unsigned int>(unsigned int*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&) Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<float>(float*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&) Unexecuted instantiation: bool LercNS::Lerc::RemapNoData<double>(double*, LercNS::BitMask const&, LercNS::Lerc2::HeaderInfo const&) |
1077 | | |
1078 | | // -------------------------------------------------------------------------- ; |
1079 | | |
1080 | | template<class T> |
1081 | | bool Lerc::DecodeAndCompareToInput(const Byte* pLercBlob, size_t blobSize, double maxZErr, Lerc2& lerc2Verify, |
1082 | | const T* pData, const Byte* pByteMask, const T* pDataOrig, const Byte* pByteMaskOrig, |
1083 | | bool bInputHasNoData, double origNoDataA, bool bModifiedMask) |
1084 | | { |
1085 | | if (!pLercBlob || !pData || !pDataOrig) |
1086 | | return false; |
1087 | | |
1088 | | const Byte* bytePtr = pLercBlob; |
1089 | | size_t nBytesRemaining = blobSize; |
1090 | | |
1091 | | bool bHasMask(false); |
1092 | | Lerc2::HeaderInfo hd; |
1093 | | if (!Lerc2::GetHeaderInfo(bytePtr, nBytesRemaining, hd, bHasMask)) |
1094 | | return false; |
1095 | | |
1096 | | std::vector<T> arrDec; |
1097 | | try |
1098 | | { |
1099 | | arrDec.assign(hd.nRows * hd.nCols * hd.nDepth, 0); |
1100 | | } |
1101 | | catch (...) |
1102 | | { |
1103 | | return false; |
1104 | | } |
1105 | | |
1106 | | BitMask bitMaskDec; |
1107 | | if (!bitMaskDec.SetSize(hd.nCols, hd.nRows)) |
1108 | | return false; |
1109 | | |
1110 | | bitMaskDec.SetAllInvalid(); |
1111 | | |
1112 | | if (!lerc2Verify.Decode(&bytePtr, nBytesRemaining, &arrDec[0], bitMaskDec.Bits())) |
1113 | | return false; |
1114 | | |
1115 | | // compare decoded bit mask and data array against the input to lerc encode (as after that orig input had the noData value remapped, NaN removed, bit mask altered) |
1116 | | { |
1117 | | bool bHasMaskBug(false); |
1118 | | double maxDelta = 0; |
1119 | | |
1120 | | for (int k = 0, i = 0; i < hd.nRows; i++) |
1121 | | for (int j = 0; j < hd.nCols; j++, k++) |
1122 | | if (bitMaskDec.IsValid(k)) |
1123 | | { |
1124 | | if (pByteMask && !pByteMask[k]) |
1125 | | bHasMaskBug = true; |
1126 | | |
1127 | | for (int n = k * hd.nDepth, m = 0; m < hd.nDepth; m++, n++) |
1128 | | { |
1129 | | double d = fabs((double)arrDec[n] - (double)pData[n]); |
1130 | | if (d > maxDelta) |
1131 | | maxDelta = d; |
1132 | | } |
1133 | | } |
1134 | | else if (!pByteMask || pByteMask[k]) |
1135 | | bHasMaskBug = true; |
1136 | | |
1137 | | if (bHasMaskBug || maxDelta > maxZErr * 1.1) // consider float rounding errors |
1138 | | return false; |
1139 | | } |
1140 | | |
1141 | | if (!bInputHasNoData && !bModifiedMask) // any NaN in the input means either modify the mask or replace it by noData value |
1142 | | return true; |
1143 | | |
1144 | | const bool bIsFltOrDbl = (typeid(T) == typeid(double) || typeid(T) == typeid(float)); |
1145 | | const bool bHaveNoDataVal = (hd.version >= 6 && hd.bPassNoDataValues && hd.nDepth > 1); |
1146 | | |
1147 | | if (bHaveNoDataVal && hd.noDataValOrig != origNoDataA) |
1148 | | return false; |
1149 | | |
1150 | | if (bHaveNoDataVal && hd.noDataVal != hd.noDataValOrig) |
1151 | | { |
1152 | | // remap the noData value from internal to orig |
1153 | | if (!RemapNoData(&arrDec[0], bitMaskDec, hd)) |
1154 | | return false; |
1155 | | } |
1156 | | |
1157 | | // compare the final result to orig bit mask and data array as it was handed to the Compress() function |
1158 | | { |
1159 | | T noDataOrig = (T)origNoDataA; |
1160 | | double maxDelta = 0; |
1161 | | bool bHasBug(false); |
1162 | | |
1163 | | for (int k = 0, i = 0; i < hd.nRows; i++) |
1164 | | for (int j = 0; j < hd.nCols; j++, k++) |
1165 | | if (!pByteMaskOrig || pByteMaskOrig[k]) |
1166 | | { |
1167 | | if (!bitMaskDec.IsValid(k)) // then the orig data values must be noData or NaN |
1168 | | { |
1169 | | for (int n = k * hd.nDepth, m = 0; m < hd.nDepth; m++, n++) |
1170 | | { |
1171 | | T zOrig = pDataOrig[n]; |
1172 | | bool bIsNoData = (bInputHasNoData && zOrig == noDataOrig) || (bIsFltOrDbl && std::isnan((double)zOrig)); |
1173 | | |
1174 | | if (!bIsNoData) |
1175 | | bHasBug = true; |
1176 | | } |
1177 | | } |
1178 | | else // valid pixel |
1179 | | { |
1180 | | for (int n = k * hd.nDepth, m = 0; m < hd.nDepth; m++, n++) |
1181 | | { |
1182 | | T zOrig = pDataOrig[n]; |
1183 | | T z = arrDec[n]; |
1184 | | |
1185 | | if (z == zOrig) // valid value or noData |
1186 | | continue; |
1187 | | |
1188 | | if (bIsFltOrDbl && std::isnan((double)zOrig)) |
1189 | | zOrig = noDataOrig; |
1190 | | |
1191 | | if (bInputHasNoData && (z == noDataOrig || zOrig == noDataOrig) && (z != zOrig)) |
1192 | | bHasBug = true; |
1193 | | |
1194 | | if (!bHaveNoDataVal || z != noDataOrig) // is valid |
1195 | | { |
1196 | | double d = fabs((double)z - (double)zOrig); |
1197 | | if (d > maxDelta) |
1198 | | maxDelta = d; |
1199 | | } |
1200 | | } |
1201 | | } |
1202 | | } |
1203 | | else if (bitMaskDec.IsValid(k)) |
1204 | | bHasBug = true; |
1205 | | |
1206 | | if (bHasBug || maxDelta > maxZErr * 1.1) // consider float rounding errors |
1207 | | return false; |
1208 | | } |
1209 | | |
1210 | | return true; |
1211 | | } |
1212 | | |
1213 | | // -------------------------------------------------------------------------- ; |
1214 | | |
1215 | | template<class T> |
1216 | | bool Lerc::GetTypeRange(const T, std::pair<double, double>& range) |
1217 | 0 | { |
1218 | 0 | range.first = 0; |
1219 | |
|
1220 | 0 | if (typeid(T) == typeid(Byte)) |
1221 | 0 | range.second = UCHAR_MAX; |
1222 | 0 | else if (typeid(T) == typeid(unsigned short)) |
1223 | 0 | range.second = USHRT_MAX; |
1224 | 0 | else if (typeid(T) == typeid(unsigned int) || typeid(T) == typeid(unsigned long)) |
1225 | 0 | range.second = UINT_MAX; |
1226 | | |
1227 | 0 | else if (typeid(T) == typeid(signed char)) |
1228 | 0 | range = std::pair<double, double>(CHAR_MIN, CHAR_MAX); |
1229 | 0 | else if (typeid(T) == typeid(short)) |
1230 | 0 | range = std::pair<double, double>(SHRT_MIN, SHRT_MAX); |
1231 | 0 | else if (typeid(T) == typeid(int) || typeid(T) == typeid(long)) |
1232 | 0 | range = std::pair<double, double>(INT_MIN, INT_MAX); |
1233 | 0 | else |
1234 | 0 | return false; |
1235 | | |
1236 | 0 | return true; |
1237 | 0 | } Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<signed char>(signed char, std::__1::pair<double, double>&) Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<unsigned char>(unsigned char, std::__1::pair<double, double>&) Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<short>(short, std::__1::pair<double, double>&) Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<unsigned short>(unsigned short, std::__1::pair<double, double>&) Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<int>(int, std::__1::pair<double, double>&) Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<unsigned int>(unsigned int, std::__1::pair<double, double>&) Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<float>(float, std::__1::pair<double, double>&) Unexecuted instantiation: bool LercNS::Lerc::GetTypeRange<double>(double, std::__1::pair<double, double>&) |
1238 | | |
1239 | | // -------------------------------------------------------------------------- ; |
1240 | | |
1241 | | template<class T> |
1242 | | ErrCode Lerc::FilterNoData(std::vector<T>& dataBuffer, std::vector<Byte>& maskBuffer, int nDepth, int nCols, int nRows, |
1243 | | double& maxZError, bool bPassNoDataValue, double& noDataValue, bool& bModifiedMask, bool& bNeedNoData, |
1244 | | double& minValA, double& maxValA) |
1245 | 0 | { |
1246 | 0 | if (nDepth <= 0 || nCols <= 0 || nRows <= 0 || maxZError < 0) |
1247 | 0 | return ErrCode::WrongParam; |
1248 | | |
1249 | 0 | if ((dataBuffer.size() != (size_t)nDepth * nCols * nRows) || (maskBuffer.size() != (size_t)nCols * nRows)) |
1250 | 0 | return ErrCode::Failed; |
1251 | | |
1252 | 0 | bModifiedMask = false; |
1253 | 0 | bNeedNoData = false; |
1254 | |
|
1255 | 0 | if (!bPassNoDataValue) // nothing to do |
1256 | 0 | return ErrCode::Ok; |
1257 | | |
1258 | 0 | std::pair<double, double> typeRange; |
1259 | 0 | if (!GetTypeRange(dataBuffer[0], typeRange)) |
1260 | 0 | return ErrCode::Failed; |
1261 | | |
1262 | 0 | if (noDataValue < typeRange.first || noDataValue > typeRange.second) |
1263 | 0 | return ErrCode::WrongParam; |
1264 | | |
1265 | 0 | T origNoData = (T)noDataValue; |
1266 | |
|
1267 | 0 | double minVal = DBL_MAX; |
1268 | 0 | double maxVal = -DBL_MAX; |
1269 | | |
1270 | | // check for noData in valid pixels |
1271 | 0 | for (int k = 0, i = 0; i < nRows; i++) |
1272 | 0 | { |
1273 | 0 | T* rowArr = &(dataBuffer[(size_t)i * nCols * nDepth]); |
1274 | |
|
1275 | 0 | for (int n = 0, j = 0; j < nCols; j++, k++, n += nDepth) |
1276 | 0 | if (maskBuffer[k]) |
1277 | 0 | { |
1278 | 0 | int cntInvalid = 0; |
1279 | |
|
1280 | 0 | for (int m = 0; m < nDepth; m++) |
1281 | 0 | { |
1282 | 0 | T z = rowArr[n + m]; |
1283 | |
|
1284 | 0 | if (z == origNoData) |
1285 | 0 | cntInvalid++; |
1286 | 0 | else |
1287 | 0 | { |
1288 | 0 | if (z < minVal) |
1289 | 0 | minVal = z; |
1290 | 0 | if (z > maxVal) |
1291 | 0 | maxVal = z; |
1292 | 0 | } |
1293 | 0 | } |
1294 | |
|
1295 | 0 | if (cntInvalid == nDepth) |
1296 | 0 | { |
1297 | 0 | maskBuffer[k] = 0; |
1298 | 0 | bModifiedMask = true; |
1299 | 0 | } |
1300 | 0 | else if (cntInvalid > 0) // found mix of valid and invalid values at the same pixel |
1301 | 0 | bNeedNoData = true; |
1302 | 0 | } |
1303 | 0 | } |
1304 | |
|
1305 | 0 | double maxZErrL = (std::max)(0.5, floor(maxZError)); // same mapping for int types as in Lerc2.cpp |
1306 | 0 | double dist = floor(maxZErrL); |
1307 | |
|
1308 | 0 | if (minVal == DBL_MAX && maxVal == -DBL_MAX) // if the tile has no valid data |
1309 | 0 | { |
1310 | 0 | minValA = maxValA = 0; |
1311 | 0 | maxZError = 0.5; |
1312 | 0 | return ErrCode::Ok; |
1313 | 0 | } |
1314 | | |
1315 | 0 | minValA = minVal; |
1316 | 0 | maxValA = maxVal; |
1317 | | |
1318 | | // check the orig noData value is far enough away from the valid range |
1319 | 0 | if ((origNoData >= minVal - dist) && (origNoData <= maxVal + dist)) |
1320 | 0 | { |
1321 | 0 | maxZError = 0.5; // fall back to int lossless |
1322 | 0 | return ErrCode::Ok; |
1323 | 0 | } |
1324 | | |
1325 | 0 | if (bNeedNoData) |
1326 | 0 | { |
1327 | 0 | double minDist = floor(maxZErrL) + 1; |
1328 | 0 | double remapVal = minVal - minDist; |
1329 | 0 | T newNoData = origNoData; |
1330 | |
|
1331 | 0 | if (remapVal >= typeRange.first) |
1332 | 0 | { |
1333 | 0 | newNoData = (T)remapVal; |
1334 | 0 | } |
1335 | 0 | else |
1336 | 0 | { |
1337 | 0 | maxZErrL = 0.5; // repeat with int lossless |
1338 | 0 | remapVal = minVal - 1; |
1339 | |
|
1340 | 0 | if (remapVal >= typeRange.first) |
1341 | 0 | { |
1342 | 0 | newNoData = (T)remapVal; |
1343 | 0 | } |
1344 | 0 | else |
1345 | 0 | { |
1346 | 0 | remapVal = maxVal + 1; // try to map closer to valid range from top |
1347 | |
|
1348 | 0 | if ((remapVal <= typeRange.second) && (remapVal < origNoData)) |
1349 | 0 | newNoData = (T)remapVal; |
1350 | 0 | } |
1351 | 0 | } |
1352 | |
|
1353 | 0 | if (newNoData != origNoData) |
1354 | 0 | { |
1355 | 0 | for (int k = 0, i = 0; i < nRows; i++) |
1356 | 0 | { |
1357 | 0 | T* rowArr = &(dataBuffer[(size_t)i * nCols * nDepth]); |
1358 | |
|
1359 | 0 | for (int n = 0, j = 0; j < nCols; j++, k++, n += nDepth) |
1360 | 0 | if (maskBuffer[k]) |
1361 | 0 | for (int m = 0; m < nDepth; m++) |
1362 | 0 | if (rowArr[n + m] == origNoData) |
1363 | 0 | rowArr[n + m] = newNoData; |
1364 | 0 | } |
1365 | |
|
1366 | 0 | noDataValue = newNoData; |
1367 | 0 | } |
1368 | 0 | } |
1369 | |
|
1370 | 0 | if (maxZError != maxZErrL) |
1371 | 0 | maxZError = maxZErrL; |
1372 | |
|
1373 | 0 | return ErrCode::Ok; |
1374 | 0 | } Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<signed char>(std::__1::vector<signed char, std::__1::allocator<signed char> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<unsigned char>(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<short>(std::__1::vector<short, std::__1::allocator<short> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<unsigned short>(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<int>(std::__1::vector<int, std::__1::allocator<int> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<unsigned int>(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<float>(std::__1::vector<float, std::__1::allocator<float> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoData<double>(std::__1::vector<double, std::__1::allocator<double> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, double&, double&) |
1375 | | |
1376 | | // -------------------------------------------------------------------------- ; |
1377 | | |
1378 | | template<class T> |
1379 | | ErrCode Lerc::FilterNoDataAndNaN(std::vector<T>& dataBuffer, std::vector<Byte>& maskBuffer, int nDepth, int nCols, int nRows, |
1380 | | double& maxZError, bool bPassNoDataValue, double& noDataValue, bool& bModifiedMask, bool& bNeedNoData, bool& bIsFltDblAllInt, |
1381 | | double& minValA, double& maxValA) |
1382 | 0 | { |
1383 | 0 | if (nDepth <= 0 || nCols <= 0 || nRows <= 0 || maxZError < 0) |
1384 | 0 | return ErrCode::WrongParam; |
1385 | | |
1386 | 0 | if ((dataBuffer.size() != (size_t)nDepth * nCols * nRows) || (maskBuffer.size() != (size_t)nCols * nRows)) |
1387 | 0 | return ErrCode::Failed; |
1388 | | |
1389 | 0 | if (typeid(T) != typeid(double) && typeid(T) != typeid(float)) // only for float or double |
1390 | 0 | return ErrCode::Failed; |
1391 | | |
1392 | 0 | bModifiedMask = false; |
1393 | 0 | bNeedNoData = false; |
1394 | 0 | bIsFltDblAllInt = false; |
1395 | |
|
1396 | 0 | bool bHasNoDataValuesLeft = false; |
1397 | 0 | bool bIsFloat4 = (typeid(T) == typeid(float)); |
1398 | 0 | bool bAllInt = true; |
1399 | 0 | bool bHasNaN = false; |
1400 | |
|
1401 | 0 | T origNoData(0); |
1402 | |
|
1403 | 0 | if (bPassNoDataValue) |
1404 | 0 | { |
1405 | 0 | if (bIsFloat4 && (noDataValue < -FLT_MAX || noDataValue > FLT_MAX)) |
1406 | 0 | return ErrCode::WrongParam; |
1407 | | |
1408 | 0 | origNoData = (T)noDataValue; |
1409 | 0 | } |
1410 | 0 | else |
1411 | 0 | origNoData = (T)(bIsFloat4 ? -FLT_MAX : -DBL_MAX); |
1412 | | |
1413 | | // only treat int values as int's if within this range, incl orig noData |
1414 | 0 | const double lowIntLimit = (double)(bIsFloat4 ? -((long)1 << 23) : -((int64_t)1 << 53)); |
1415 | 0 | const double highIntLimit = (double)(bIsFloat4 ? ((long)1 << 23) : ((int64_t)1 << 53)); |
1416 | |
|
1417 | 0 | double minVal = DBL_MAX; |
1418 | 0 | double maxVal = -DBL_MAX; |
1419 | | |
1420 | | // check for NaN or noData in valid pixels |
1421 | 0 | for (int k = 0, i = 0; i < nRows; i++) |
1422 | 0 | { |
1423 | 0 | T* rowArr = &(dataBuffer[(size_t)i * nCols * nDepth]); |
1424 | |
|
1425 | 0 | for (int n = 0, j = 0; j < nCols; j++, k++, n += nDepth) |
1426 | 0 | if (maskBuffer[k]) |
1427 | 0 | { |
1428 | 0 | int cntInvalidValues = 0; |
1429 | |
|
1430 | 0 | for (int m = 0; m < nDepth; m++) |
1431 | 0 | { |
1432 | 0 | T& zVal = rowArr[n + m]; |
1433 | |
|
1434 | 0 | if (std::isnan((double)zVal)) |
1435 | 0 | { |
1436 | 0 | bHasNaN = true; |
1437 | 0 | cntInvalidValues++; |
1438 | |
|
1439 | 0 | if (bPassNoDataValue && nDepth > 1) |
1440 | 0 | zVal = origNoData; // replace NaN |
1441 | 0 | else if (nDepth == 1) |
1442 | 0 | zVal = 0; |
1443 | 0 | } |
1444 | 0 | else if (bPassNoDataValue && zVal == origNoData) |
1445 | 0 | { |
1446 | 0 | cntInvalidValues++; |
1447 | 0 | } |
1448 | 0 | else |
1449 | 0 | { |
1450 | 0 | if (zVal < minVal) |
1451 | 0 | minVal = zVal; |
1452 | 0 | if (zVal > maxVal) |
1453 | 0 | maxVal = zVal; |
1454 | |
|
1455 | 0 | if (bAllInt && !IsInt(zVal)) |
1456 | 0 | bAllInt = false; |
1457 | 0 | } |
1458 | 0 | } |
1459 | |
|
1460 | 0 | if (cntInvalidValues == nDepth) |
1461 | 0 | { |
1462 | 0 | maskBuffer[k] = 0; |
1463 | 0 | bModifiedMask = true; |
1464 | 0 | } |
1465 | 0 | else if (cntInvalidValues > 0) // found mix of valid and invalid values at the same pixel |
1466 | 0 | bHasNoDataValuesLeft = true; |
1467 | 0 | } |
1468 | 0 | } |
1469 | |
|
1470 | 0 | if (minVal == DBL_MAX && maxVal == -DBL_MAX) // if the tile has no valid data |
1471 | 0 | { |
1472 | 0 | minValA = maxValA = 0; |
1473 | 0 | maxZError = 0; |
1474 | 0 | return ErrCode::Ok; |
1475 | 0 | } |
1476 | | |
1477 | 0 | minValA = minVal; |
1478 | 0 | maxValA = maxVal; |
1479 | 0 | bNeedNoData = bHasNoDataValuesLeft; |
1480 | |
|
1481 | 0 | if (bHasNaN && nDepth > 1 && bHasNoDataValuesLeft && !bPassNoDataValue) |
1482 | 0 | { |
1483 | 0 | return ErrCode::NaN; // Lerc cannot handle this case, cannot pick a noData value on the tile level |
1484 | 0 | } |
1485 | | |
1486 | | // now NaN's are gone, either moved to the mask or replaced by noData value |
1487 | | |
1488 | 0 | double maxZErrL = maxZError; |
1489 | |
|
1490 | 0 | if (bAllInt) |
1491 | 0 | { |
1492 | 0 | bAllInt &= (minVal >= lowIntLimit) && (minVal <= highIntLimit) |
1493 | 0 | && (maxVal >= lowIntLimit) && (maxVal <= highIntLimit); |
1494 | |
|
1495 | 0 | if (bHasNoDataValuesLeft) |
1496 | 0 | bAllInt &= IsInt(origNoData) && (origNoData >= lowIntLimit) && (origNoData <= highIntLimit); |
1497 | |
|
1498 | 0 | if (bAllInt) |
1499 | 0 | maxZErrL = (std::max)(0.5, floor(maxZError)); // same mapping for int types as in Lerc2.cpp |
1500 | 0 | } |
1501 | |
|
1502 | 0 | bIsFltDblAllInt = bAllInt; |
1503 | |
|
1504 | 0 | if (maxZErrL == 0) // if flt lossless, we are done |
1505 | 0 | return ErrCode::Ok; |
1506 | | |
1507 | 0 | if (bPassNoDataValue) |
1508 | 0 | { |
1509 | | // check the orig noData value is far enough away from the valid range |
1510 | 0 | double dist = bAllInt ? floor(maxZErrL) : 2 * maxZErrL; |
1511 | |
|
1512 | 0 | if ((origNoData >= minVal - dist) && (origNoData <= maxVal + dist)) |
1513 | 0 | { |
1514 | 0 | maxZError = bAllInt ? 0.5 : 0; // fall back to lossless |
1515 | 0 | return ErrCode::Ok; |
1516 | 0 | } |
1517 | 0 | } |
1518 | | |
1519 | 0 | if (bHasNoDataValuesLeft) // try to remap noData to new noData just below the global minimum |
1520 | 0 | { |
1521 | 0 | T remapVal = origNoData; |
1522 | 0 | bool bRemapNoData = FindNewNoDataBelowValidMin(minVal, maxZErrL, bAllInt, lowIntLimit, remapVal); |
1523 | |
|
1524 | 0 | if (bRemapNoData) |
1525 | 0 | { |
1526 | 0 | if (remapVal != origNoData) |
1527 | 0 | { |
1528 | 0 | for (int k = 0, i = 0; i < nRows; i++) |
1529 | 0 | { |
1530 | 0 | T* rowArr = &(dataBuffer[(size_t)i * nCols * nDepth]); |
1531 | |
|
1532 | 0 | for (int n = 0, j = 0; j < nCols; j++, k++, n += nDepth) |
1533 | 0 | if (maskBuffer[k]) |
1534 | 0 | for (int m = 0; m < nDepth; m++) |
1535 | 0 | if (rowArr[n + m] == origNoData) |
1536 | 0 | rowArr[n + m] = remapVal; |
1537 | 0 | } |
1538 | |
|
1539 | 0 | noDataValue = remapVal; |
1540 | 0 | } |
1541 | 0 | } |
1542 | 0 | else if ((double)origNoData >= minVal) // sufficient distance of origNoData to valid range has been checked above |
1543 | 0 | { |
1544 | 0 | maxZErrL = bAllInt ? 0.5 : 0; // need lossless if noData cannot be mapped below valid range |
1545 | 0 | } |
1546 | 0 | } |
1547 | |
|
1548 | 0 | if (maxZError != maxZErrL) |
1549 | 0 | maxZError = maxZErrL; |
1550 | |
|
1551 | 0 | return ErrCode::Ok; |
1552 | 0 | } Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<signed char>(std::__1::vector<signed char, std::__1::allocator<signed char> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<unsigned char>(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<short>(std::__1::vector<short, std::__1::allocator<short> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<unsigned short>(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<int>(std::__1::vector<int, std::__1::allocator<int> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<unsigned int>(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<float>(std::__1::vector<float, std::__1::allocator<float> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&) Unexecuted instantiation: LercNS::ErrCode LercNS::Lerc::FilterNoDataAndNaN<double>(std::__1::vector<double, std::__1::allocator<double> >&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, int, int, int, double&, bool, double&, bool&, bool&, bool&, double&, double&) |
1553 | | |
1554 | | // -------------------------------------------------------------------------- ; |
1555 | | |
1556 | | template<class T> |
1557 | | bool Lerc::FindNewNoDataBelowValidMin(double minVal, double maxZErr, bool bAllInt, double lowIntLimit, T& newNoDataVal) |
1558 | 0 | { |
1559 | 0 | if (bAllInt) |
1560 | 0 | { |
1561 | 0 | std::vector<T> noDataCandVec; |
1562 | |
|
1563 | 0 | { // collect dist candidates |
1564 | 0 | std::vector<double> distCandVec = { 4 * maxZErr, 1, 10, 100, 1000, 10000 }; // only int candidates |
1565 | |
|
1566 | 0 | for (double dist : distCandVec) |
1567 | 0 | noDataCandVec.push_back((T)(minVal - dist)); |
1568 | |
|
1569 | 0 | double candForLargeMinVal = (minVal > 0 ? floor(minVal / 2) : minVal * 2); // also int |
1570 | 0 | noDataCandVec.push_back((T)candForLargeMinVal); |
1571 | 0 | } |
1572 | | |
1573 | | // sort them in descending order |
1574 | 0 | std::sort(noDataCandVec.begin(), noDataCandVec.end(), std::greater<double>()); |
1575 | | |
1576 | | // take the first one that satisfies the condition |
1577 | 0 | for (T noDataVal : noDataCandVec) |
1578 | 0 | { |
1579 | 0 | if ((noDataVal > (T)lowIntLimit) && (noDataVal < (T)(minVal - 2 * maxZErr)) && IsInt(noDataVal)) |
1580 | 0 | { |
1581 | 0 | newNoDataVal = noDataVal; |
1582 | 0 | return true; |
1583 | 0 | } |
1584 | 0 | } |
1585 | 0 | } |
1586 | 0 | else |
1587 | 0 | { |
1588 | 0 | std::vector<T> noDataCandVec; |
1589 | |
|
1590 | 0 | { // dist candidates |
1591 | 0 | std::vector<double> distCandVec = { 4 * maxZErr, 0.0001, 0.001, 0.01, 0.1, 1, 10, 100, 1000, 10000 }; |
1592 | |
|
1593 | 0 | for (double dist : distCandVec) |
1594 | 0 | noDataCandVec.push_back((T)(minVal - dist)); |
1595 | |
|
1596 | 0 | double candForLargeMinVal = (minVal > 0 ? minVal / 2 : minVal * 2); |
1597 | 0 | noDataCandVec.push_back((T)candForLargeMinVal); |
1598 | 0 | } |
1599 | | |
1600 | | // sort them in descending order |
1601 | 0 | std::sort(noDataCandVec.begin(), noDataCandVec.end(), std::greater<double>()); |
1602 | |
|
1603 | 0 | bool bIsFloat4 = (typeid(T) == typeid(float)); |
1604 | 0 | T lowestVal = (T)(bIsFloat4 ? -FLT_MAX : -DBL_MAX); |
1605 | | |
1606 | | // take the first one that satisfies the condition |
1607 | 0 | for (T noDataVal : noDataCandVec) |
1608 | 0 | { |
1609 | 0 | if ((noDataVal > lowestVal) && (noDataVal < (T)(minVal - 2 * maxZErr))) |
1610 | 0 | { |
1611 | 0 | newNoDataVal = noDataVal; |
1612 | 0 | return true; |
1613 | 0 | } |
1614 | 0 | } |
1615 | 0 | } |
1616 | | |
1617 | 0 | return false; |
1618 | 0 | } Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<signed char>(double, double, bool, double, signed char&) Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<unsigned char>(double, double, bool, double, unsigned char&) Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<short>(double, double, bool, double, short&) Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<unsigned short>(double, double, bool, double, unsigned short&) Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<int>(double, double, bool, double, int&) Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<unsigned int>(double, double, bool, double, unsigned int&) Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<float>(double, double, bool, double, float&) Unexecuted instantiation: bool LercNS::Lerc::FindNewNoDataBelowValidMin<double>(double, double, bool, double, double&) |
1619 | | |
1620 | | // -------------------------------------------------------------------------- ; |
1621 | | |
1622 | | bool Lerc::CheckDimensions(int nDepth, int nCols, int nRows, size_t sizeOfDataElement) |
1623 | 0 | { |
1624 | | // here we guard against too large input dimensions that might cause a possible int32 overflow later; |
1625 | | // we limit the size of input data per band to 2 GB, so any product [height * width * depth * sizeof(data element)] <= INT_MAX; |
1626 | | // (see the corresponding size and dimension checks in Lerc2::ReadHeader(...)); |
1627 | |
|
1628 | 0 | if (nDepth <= 0 || nCols <= 0 || nRows <= 0) |
1629 | 0 | return false; |
1630 | | |
1631 | 0 | const uint64_t numPixel = (uint64_t)nRows * nCols; |
1632 | 0 | const uint64_t maxint32 = (uint64_t)INT_MAX; |
1633 | 0 | const uint64_t nbpp = sizeOfDataElement; |
1634 | |
|
1635 | 0 | if (numPixel > maxint32 || nbpp > maxint32 || nbpp * nDepth > maxint32 || nbpp * nDepth * numPixel > maxint32) |
1636 | 0 | return false; |
1637 | | |
1638 | 0 | return true; |
1639 | 0 | } |
1640 | | |
1641 | | // -------------------------------------------------------------------------- ; |