1 /*
2 Copyright 2015 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 <typeinfo>
28 #include <limits>
29
30 #ifdef HAVE_LERC1_DECODE
31 #include "Lerc1Decode/CntZImage.h"
32 #endif
33
34 using namespace std;
35 USING_NAMESPACE_LERC
36
37 // -------------------------------------------------------------------------- ;
38
ComputeCompressedSize(const void * pData,int version,DataType dt,int nDim,int nCols,int nRows,int nBands,int nMasks,const Byte * pValidBytes,double maxZErr,unsigned int & numBytesNeeded)39 ErrCode Lerc::ComputeCompressedSize(const void* pData, int version, DataType dt, int nDim, int nCols, int nRows, int nBands,
40 int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded)
41 {
42 switch (dt)
43 {
44 case DT_Char: return ComputeCompressedSizeTempl((const signed char*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
45 case DT_Byte: return ComputeCompressedSizeTempl((const Byte*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
46 case DT_Short: return ComputeCompressedSizeTempl((const short*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
47 case DT_UShort: return ComputeCompressedSizeTempl((const unsigned short*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
48 case DT_Int: return ComputeCompressedSizeTempl((const int*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
49 case DT_UInt: return ComputeCompressedSizeTempl((const unsigned int*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
50 case DT_Float: return ComputeCompressedSizeTempl((const float*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
51 case DT_Double: return ComputeCompressedSizeTempl((const double*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, numBytesNeeded);
52
53 default:
54 return ErrCode::WrongParam;
55 }
56 }
57
58 // -------------------------------------------------------------------------- ;
59
Encode(const void * pData,int version,DataType dt,int nDim,int nCols,int nRows,int nBands,int nMasks,const Byte * pValidBytes,double maxZErr,Byte * pBuffer,unsigned int numBytesBuffer,unsigned int & numBytesWritten)60 ErrCode Lerc::Encode(const void* pData, int version, DataType dt, int nDim, int nCols, int nRows, int nBands,
61 int nMasks, const Byte* pValidBytes, double maxZErr, Byte* pBuffer, unsigned int numBytesBuffer, unsigned int& numBytesWritten)
62 {
63 switch (dt)
64 {
65 case DT_Char: return EncodeTempl((const signed char*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
66 case DT_Byte: return EncodeTempl((const Byte*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
67 case DT_Short: return EncodeTempl((const short*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
68 case DT_UShort: return EncodeTempl((const unsigned short*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
69 case DT_Int: return EncodeTempl((const int*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
70 case DT_UInt: return EncodeTempl((const unsigned int*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
71 case DT_Float: return EncodeTempl((const float*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
72 case DT_Double: return EncodeTempl((const double*)pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr, pBuffer, numBytesBuffer, numBytesWritten);
73
74 default:
75 return ErrCode::WrongParam;
76 }
77 }
78
79 // -------------------------------------------------------------------------- ;
80
GetLercInfo(const Byte * pLercBlob,unsigned int numBytesBlob,struct LercInfo & lercInfo)81 ErrCode Lerc::GetLercInfo(const Byte* pLercBlob, unsigned int numBytesBlob, struct LercInfo& lercInfo)
82 {
83 lercInfo.RawInit();
84
85 // first try Lerc2
86 struct Lerc2::HeaderInfo lerc2Info;
87 bool bHasMask = false;
88 int nMasks = 0;
89
90 if (Lerc2::GetHeaderInfo(pLercBlob, numBytesBlob, lerc2Info, bHasMask))
91 {
92 lercInfo.version = lerc2Info.version;
93 lercInfo.nDim = lerc2Info.nDim;
94 lercInfo.nCols = lerc2Info.nCols;
95 lercInfo.nRows = lerc2Info.nRows;
96 lercInfo.numValidPixel = lerc2Info.numValidPixel; // for 1st band
97 lercInfo.nBands = 1;
98 lercInfo.blobSize = lerc2Info.blobSize;
99 lercInfo.dt = (DataType)lerc2Info.dt;
100 lercInfo.zMin = lerc2Info.zMin;
101 lercInfo.zMax = lerc2Info.zMax;
102 lercInfo.maxZError = lerc2Info.maxZError;
103
104 if (bHasMask || lercInfo.numValidPixel == 0)
105 nMasks = 1;
106
107 if (lercInfo.blobSize > (int)numBytesBlob) // truncated blob, we won't be able to read this band
108 return ErrCode::BufferTooSmall;
109
110 struct Lerc2::HeaderInfo hdInfo;
111 while (Lerc2::GetHeaderInfo(pLercBlob + lercInfo.blobSize, numBytesBlob - lercInfo.blobSize, hdInfo, bHasMask))
112 {
113 if (hdInfo.nDim != lercInfo.nDim
114 || hdInfo.nCols != lercInfo.nCols
115 || hdInfo.nRows != lercInfo.nRows
116 || (int)hdInfo.dt != (int)lercInfo.dt)
117 //|| hdInfo.maxZError != lercInfo.maxZError) // with the new bitplane compression, maxZError can vary between bands
118 {
119 return ErrCode::Failed;
120 }
121
122 if (bHasMask || hdInfo.numValidPixel != lercInfo.numValidPixel) // support mask per band
123 nMasks = 2;
124
125 if (lercInfo.blobSize > std::numeric_limits<int>::max() - hdInfo.blobSize)
126 return ErrCode::Failed;
127
128 lercInfo.blobSize += hdInfo.blobSize;
129
130 if (lercInfo.blobSize > (int)numBytesBlob) // truncated blob, we won't be able to read this band
131 return ErrCode::BufferTooSmall;
132
133 lercInfo.nBands++;
134 lercInfo.zMin = min(lercInfo.zMin, hdInfo.zMin);
135 lercInfo.zMax = max(lercInfo.zMax, hdInfo.zMax);
136 lercInfo.maxZError = max(lercInfo.maxZError, hdInfo.maxZError); // with the new bitplane compression, maxZError can vary between bands
137 }
138
139 lercInfo.nMasks = nMasks > 1 ? lercInfo.nBands : nMasks;
140
141 return ErrCode::Ok;
142 }
143
144
145 #ifdef HAVE_LERC1_DECODE
146 // only if not Lerc2, try legacy Lerc1
147 unsigned int numBytesHeaderBand0 = CntZImage::computeNumBytesNeededToReadHeader(false);
148 unsigned int numBytesHeaderBand1 = CntZImage::computeNumBytesNeededToReadHeader(true);
149 Byte* pByte = const_cast<Byte*>(pLercBlob);
150
151 lercInfo.zMin = FLT_MAX;
152 lercInfo.zMax = -FLT_MAX;
153
154 CntZImage cntZImg;
155 if (numBytesHeaderBand0 <= numBytesBlob && cntZImg.read(&pByte, 1e12, true)) // read just the header
156 {
157 size_t nBytesRead = pByte - pLercBlob;
158 size_t nBytesNeeded = 10 + 4 * sizeof(int) + 1 * sizeof(double);
159
160 if (nBytesRead < nBytesNeeded)
161 return ErrCode::Failed;
162
163 Byte* ptr = const_cast<Byte*>(pLercBlob);
164 ptr += 10 + 2 * sizeof(int);
165
166 int height(0), width(0);
167 memcpy(&height, ptr, sizeof(int)); ptr += sizeof(int);
168 memcpy(&width, ptr, sizeof(int)); ptr += sizeof(int);
169 double maxZErrorInFile(0);
170 memcpy(&maxZErrorInFile, ptr, sizeof(double));
171
172 if (height > 20000 || width > 20000) // guard against bogus numbers; size limitation for old Lerc1
173 return ErrCode::Failed;
174
175 lercInfo.nDim = 1;
176 lercInfo.nCols = width;
177 lercInfo.nRows = height;
178 lercInfo.dt = Lerc::DT_Float;
179 lercInfo.maxZError = maxZErrorInFile;
180
181 Byte* pByte = const_cast<Byte*>(pLercBlob);
182 bool onlyZPart = false;
183
184 while (lercInfo.blobSize + numBytesHeaderBand1 < numBytesBlob) // means there could be another band
185 {
186 if (!cntZImg.read(&pByte, 1e12, false, onlyZPart))
187 return (lercInfo.nBands > 0) ? ErrCode::Ok : ErrCode::Failed; // no other band, we are done
188
189 onlyZPart = true;
190
191 lercInfo.nBands++;
192 lercInfo.blobSize = (int)(pByte - pLercBlob);
193
194 // now that we have decoded it, we can go the extra mile and collect some extra info
195 int numValidPixels = 0;
196 float zMin = FLT_MAX;
197 float zMax = -FLT_MAX;
198
199 for (int i = 0; i < height; i++)
200 {
201 for (int j = 0; j < width; j++)
202 if (cntZImg(i, j).cnt > 0)
203 {
204 numValidPixels++;
205 float z = cntZImg(i, j).z;
206 zMax = max(zMax, z);
207 zMin = min(zMin, z);
208 }
209 }
210
211 lercInfo.numValidPixel = numValidPixels;
212 lercInfo.zMin = std::min(lercInfo.zMin, (double)zMin);
213 lercInfo.zMax = std::max(lercInfo.zMax, (double)zMax);
214 lercInfo.nMasks = numValidPixels < width * height ? 1 : 0;
215 }
216
217 return ErrCode::Ok;
218 }
219 #endif
220
221 return ErrCode::Failed;
222 }
223
224 // -------------------------------------------------------------------------- ;
225
Decode(const Byte * pLercBlob,unsigned int numBytesBlob,int nMasks,Byte * pValidBytes,int nDim,int nCols,int nRows,int nBands,DataType dt,void * pData)226 ErrCode Lerc::Decode(const Byte* pLercBlob, unsigned int numBytesBlob, int nMasks, Byte* pValidBytes,
227 int nDim, int nCols, int nRows, int nBands, DataType dt, void* pData)
228 {
229 switch (dt)
230 {
231 case DT_Char: return DecodeTempl((signed char*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
232 case DT_Byte: return DecodeTempl((Byte*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
233 case DT_Short: return DecodeTempl((short*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
234 case DT_UShort: return DecodeTempl((unsigned short*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
235 case DT_Int: return DecodeTempl((int*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
236 case DT_UInt: return DecodeTempl((unsigned int*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
237 case DT_Float: return DecodeTempl((float*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
238 case DT_Double: return DecodeTempl((double*)pData, pLercBlob, numBytesBlob, nDim, nCols, nRows, nBands, nMasks, pValidBytes);
239
240 default:
241 return ErrCode::WrongParam;
242 }
243 }
244
245 // -------------------------------------------------------------------------- ;
246
ConvertToDouble(const void * pDataIn,DataType dt,size_t nDataValues,double * pDataOut)247 ErrCode Lerc::ConvertToDouble(const void* pDataIn, DataType dt, size_t nDataValues, double* pDataOut)
248 {
249 switch (dt)
250 {
251 case DT_Char: return ConvertToDoubleTempl((const signed char*)pDataIn, nDataValues, pDataOut);
252 case DT_Byte: return ConvertToDoubleTempl((const Byte*)pDataIn, nDataValues, pDataOut);
253 case DT_Short: return ConvertToDoubleTempl((const short*)pDataIn, nDataValues, pDataOut);
254 case DT_UShort: return ConvertToDoubleTempl((const unsigned short*)pDataIn, nDataValues, pDataOut);
255 case DT_Int: return ConvertToDoubleTempl((const int*)pDataIn, nDataValues, pDataOut);
256 case DT_UInt: return ConvertToDoubleTempl((const unsigned int*)pDataIn, nDataValues, pDataOut);
257 case DT_Float: return ConvertToDoubleTempl((const float*)pDataIn, nDataValues, pDataOut);
258 //case DT_Double: no convert double to double
259
260 default:
261 return ErrCode::WrongParam;
262 }
263 }
264
265 // -------------------------------------------------------------------------- ;
266 // -------------------------------------------------------------------------- ;
267
268 template<class T>
ComputeCompressedSizeTempl(const T * pData,int version,int nDim,int nCols,int nRows,int nBands,int nMasks,const Byte * pValidBytes,double maxZErr,unsigned int & numBytesNeeded)269 ErrCode Lerc::ComputeCompressedSizeTempl(const T* pData, int version, int nDim, int nCols, int nRows, int nBands,
270 int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded)
271 {
272 numBytesNeeded = 0;
273
274 if (!pData || nDim <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || maxZErr < 0)
275 return ErrCode::WrongParam;
276
277 if (!(nMasks == 0 || nMasks == 1 || nMasks == nBands) || (nMasks > 0 && !pValidBytes))
278 return ErrCode::WrongParam;
279
280 unsigned int numBytesWritten = 0;
281
282 return EncodeInternal(pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr,
283 numBytesNeeded, nullptr, 0, numBytesWritten);
284 }
285
286 // -------------------------------------------------------------------------- ;
287
288 template<class T>
EncodeTempl(const T * pData,int version,int nDim,int nCols,int nRows,int nBands,int nMasks,const Byte * pValidBytes,double maxZErr,Byte * pBuffer,unsigned int numBytesBuffer,unsigned int & numBytesWritten)289 ErrCode Lerc::EncodeTempl(const T* pData, int version, int nDim, int nCols, int nRows, int nBands,
290 int nMasks, const Byte* pValidBytes, double maxZErr, Byte* pBuffer, unsigned int numBytesBuffer, unsigned int& numBytesWritten)
291 {
292 numBytesWritten = 0;
293
294 if (!pData || nDim <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || maxZErr < 0 || !pBuffer || !numBytesBuffer)
295 return ErrCode::WrongParam;
296
297 if (!(nMasks == 0 || nMasks == 1 || nMasks == nBands) || (nMasks > 0 && !pValidBytes))
298 return ErrCode::WrongParam;
299
300 unsigned int numBytesNeeded = 0;
301
302 return EncodeInternal(pData, version, nDim, nCols, nRows, nBands, nMasks, pValidBytes, maxZErr,
303 numBytesNeeded, pBuffer, numBytesBuffer, numBytesWritten);
304 }
305
306 // -------------------------------------------------------------------------- ;
307
308 template<class T>
DecodeTempl(T * pData,const Byte * pLercBlob,unsigned int numBytesBlob,int nDim,int nCols,int nRows,int nBands,int nMasks,Byte * pValidBytes)309 ErrCode Lerc::DecodeTempl(T* pData, const Byte* pLercBlob, unsigned int numBytesBlob,
310 int nDim, int nCols, int nRows, int nBands, int nMasks, Byte* pValidBytes)
311 {
312 if (!pData || nDim <= 0 || nCols <= 0 || nRows <= 0 || nBands <= 0 || !pLercBlob || !numBytesBlob)
313 return ErrCode::WrongParam;
314
315 if (!(nMasks == 0 || nMasks == 1 || nMasks == nBands) || (nMasks > 0 && !pValidBytes))
316 return ErrCode::WrongParam;
317
318 const Byte* pByte = pLercBlob;
319 Lerc2::HeaderInfo hdInfo;
320 bool bHasMask = false;
321
322 if (Lerc2::GetHeaderInfo(pByte, numBytesBlob, hdInfo, bHasMask) && hdInfo.version >= 1) // if Lerc2
323 {
324 LercInfo lercInfo;
325 ErrCode errCode = GetLercInfo(pLercBlob, numBytesBlob, lercInfo); // fast for Lerc2
326 if (errCode != ErrCode::Ok)
327 return errCode;
328
329 const int nMasksEncoded = lercInfo.nMasks; // 0, 1, or nBands
330
331 if (nMasks < nMasksEncoded)
332 return ErrCode::WrongParam;
333
334 size_t nBytesRemaining = numBytesBlob;
335 Lerc2 lerc2;
336 BitMask bitMask;
337
338 for (int iBand = 0; iBand < nBands; iBand++)
339 {
340 if (((size_t)(pByte - pLercBlob) < numBytesBlob) && Lerc2::GetHeaderInfo(pByte, nBytesRemaining, hdInfo, bHasMask))
341 {
342 if (hdInfo.nDim != nDim || hdInfo.nCols != nCols || hdInfo.nRows != nRows)
343 return ErrCode::Failed;
344
345 if ((pByte - pLercBlob) + (size_t)hdInfo.blobSize > numBytesBlob)
346 return ErrCode::BufferTooSmall;
347
348 size_t nPix = (size_t)iBand * nRows * nCols;
349 T* arr = pData + nPix * nDim;
350
351 bool bGetMask = iBand < nMasks;
352
353 if (bGetMask && !bitMask.SetSize(nCols, nRows))
354 return ErrCode::Failed;
355
356 if (!lerc2.Decode(&pByte, nBytesRemaining, arr, bGetMask ? bitMask.Bits() : nullptr))
357 return ErrCode::Failed;
358
359 if (bGetMask && !Convert(bitMask, pValidBytes + nPix))
360 return ErrCode::Failed;
361 }
362 } // iBand
363 } // Lerc2
364
365 else // might be old Lerc1
366 {
367 #ifdef HAVE_LERC1_DECODE
368 unsigned int numBytesHeaderBand0 = CntZImage::computeNumBytesNeededToReadHeader(false);
369 unsigned int numBytesHeaderBand1 = CntZImage::computeNumBytesNeededToReadHeader(true);
370 Byte* pByte1 = const_cast<Byte*>(pLercBlob);
371 CntZImage zImg;
372
373 for (int iBand = 0; iBand < nBands; iBand++)
374 {
375 unsigned int numBytesHeader = iBand == 0 ? numBytesHeaderBand0 : numBytesHeaderBand1;
376 if ((size_t)(pByte - pLercBlob) + numBytesHeader > numBytesBlob)
377 return ErrCode::BufferTooSmall;
378
379 bool onlyZPart = iBand > 0;
380 if (!zImg.read(&pByte1, 1e12, false, onlyZPart))
381 return ErrCode::Failed;
382
383 if (zImg.getWidth() != nCols || zImg.getHeight() != nRows)
384 return ErrCode::Failed;
385
386 size_t nPix = (size_t)iBand * nRows * nCols;
387 T* arr = pData + nPix;
388 Byte* pDst = iBand < nMasks ? pValidBytes + nPix : nullptr;
389
390 if (!Convert(zImg, arr, pDst, iBand == 0))
391 return ErrCode::Failed;
392 }
393 #else
394 return ErrCode::Failed;
395 #endif
396 }
397
398 return ErrCode::Ok;
399 }
400
401 // -------------------------------------------------------------------------- ;
402 // -------------------------------------------------------------------------- ;
403
404 template<class T>
EncodeInternal(const T * pData,int version,int nDim,int nCols,int nRows,int nBands,int nMasks,const Byte * pValidBytes,double maxZErr,unsigned int & numBytesNeeded,Byte * pBuffer,unsigned int numBytesBuffer,unsigned int & numBytesWritten)405 ErrCode Lerc::EncodeInternal(const T* pData, int version, int nDim, int nCols, int nRows, int nBands,
406 int nMasks, const Byte* pValidBytes, double maxZErr, unsigned int& numBytesNeeded,
407 Byte* pBuffer, unsigned int numBytesBuffer, unsigned int& numBytesWritten)
408 {
409 numBytesNeeded = 0;
410 numBytesWritten = 0;
411
412 Lerc2 lerc2;
413 if (version >= 0 && !lerc2.SetEncoderToOldVersion(version))
414 return ErrCode::WrongParam;
415
416 Byte* pDst = pBuffer;
417
418 const size_t nPix = (size_t)nCols * nRows;
419 const size_t nElem = nPix * nDim;
420
421 const Byte* pPrevByteMask = nullptr;
422 vector<T> dataBuffer;
423 vector<Byte> maskBuffer, prevMaskBuffer;
424 BitMask bitMask;
425
426 // loop over the bands
427 for (int iBand = 0; iBand < nBands; iBand++)
428 {
429 bool bEncMsk = (iBand == 0);
430
431 // using the proper section of valid bytes, check this band for NaN
432 const T* arr = pData + nElem * iBand;
433 const Byte* pByteMask = (nMasks > 0) ? (pValidBytes + ((nMasks > 1) ? nPix * iBand : 0)) : nullptr;
434
435 ErrCode errCode = CheckForNaN(arr, nDim, nCols, nRows, pByteMask);
436 if (errCode != ErrCode::Ok && errCode != ErrCode::NaN)
437 return errCode;
438
439 if (errCode == ErrCode::NaN) // found NaN values
440 {
441 if (!Resize(dataBuffer, nElem) || !Resize(maskBuffer, nPix))
442 return ErrCode::Failed;
443
444 memcpy(&dataBuffer[0], arr, nElem * sizeof(T));
445 pByteMask ? memcpy(&maskBuffer[0], pByteMask, nPix) : memset(&maskBuffer[0], 1, nPix);
446
447 if (!ReplaceNaNValues(dataBuffer, maskBuffer, nDim, nCols, nRows))
448 return ErrCode::Failed;
449
450 if (iBand > 0 && MasksDiffer(&maskBuffer[0], pPrevByteMask, nPix))
451 bEncMsk = true;
452
453 if (iBand < nBands - 1)
454 {
455 // keep current mask as new previous band mask
456 prevMaskBuffer = maskBuffer;
457 pPrevByteMask = &prevMaskBuffer[0];
458 }
459
460 arr = &dataBuffer[0];
461 pByteMask = &maskBuffer[0];
462 }
463
464 else // no NaN in this band, the common case
465 {
466 if (iBand > 0 && MasksDiffer(pByteMask, pPrevByteMask, nPix))
467 bEncMsk = true;
468
469 pPrevByteMask = pByteMask;
470 }
471
472 if (bEncMsk)
473 {
474 if (pByteMask && !Convert(pByteMask, nCols, nRows, bitMask))
475 return ErrCode::Failed;
476
477 if (!lerc2.Set(nDim, nCols, nRows, pByteMask ? bitMask.Bits() : nullptr))
478 return ErrCode::Failed;
479 }
480
481 unsigned int nBytes = lerc2.ComputeNumBytesNeededToWrite(arr, maxZErr, bEncMsk);
482 if (nBytes <= 0)
483 return ErrCode::Failed;
484
485 numBytesNeeded += nBytes;
486
487 if (pBuffer)
488 {
489 if ((size_t)(pDst - pBuffer) + nBytes > numBytesBuffer) // check we have enough space left
490 return ErrCode::BufferTooSmall;
491
492 if (!lerc2.Encode(arr, &pDst))
493 return ErrCode::Failed;
494 }
495 }
496
497 numBytesWritten = (unsigned int)(pDst - pBuffer);
498 return ErrCode::Ok;
499 }
500
501 // -------------------------------------------------------------------------- ;
502
503 #ifdef HAVE_LERC1_DECODE
504 template<class T>
Convert(const CntZImage & zImg,T * arr,Byte * pByteMask,bool bMustFillMask)505 bool Lerc::Convert(const CntZImage& zImg, T* arr, Byte* pByteMask, bool bMustFillMask)
506 {
507 if (!arr || !zImg.getSize())
508 return false;
509
510 const bool fltPnt = (typeid(*arr) == typeid(double)) || (typeid(*arr) == typeid(float));
511
512 int h = zImg.getHeight();
513 int w = zImg.getWidth();
514
515 const CntZ* srcPtr = zImg.getData();
516 T* dstPtr = arr;
517 int num = w * h;
518
519 if (pByteMask)
520 {
521 memset(pByteMask, 0, num);
522
523 for (int k = 0; k < num; k++)
524 {
525 if (srcPtr->cnt > 0)
526 {
527 *dstPtr = fltPnt ? (T)srcPtr->z : (T)floor(srcPtr->z + 0.5);
528 pByteMask[k] = 1;
529 }
530
531 srcPtr++;
532 dstPtr++;
533 }
534 }
535 else
536 {
537 for (int k = 0; k < num; k++)
538 {
539 if (srcPtr->cnt > 0)
540 {
541 *dstPtr = fltPnt ? (T)srcPtr->z : (T)floor(srcPtr->z + 0.5);
542 }
543 else if (bMustFillMask)
544 return false;
545
546 srcPtr++;
547 dstPtr++;
548 }
549 }
550
551 return true;
552 }
553 #endif
554
555 // -------------------------------------------------------------------------- ;
556
557 template<class T>
ConvertToDoubleTempl(const T * pDataIn,size_t nDataValues,double * pDataOut)558 ErrCode Lerc::ConvertToDoubleTempl(const T* pDataIn, size_t nDataValues, double* pDataOut)
559 {
560 if (!pDataIn || !nDataValues || !pDataOut)
561 return ErrCode::WrongParam;
562
563 for (size_t k = 0; k < nDataValues; k++)
564 pDataOut[k] = pDataIn[k];
565
566 return ErrCode::Ok;
567 }
568
569 // -------------------------------------------------------------------------- ;
570
CheckForNaN(const T * arr,int nDim,int nCols,int nRows,const Byte * pByteMask)571 template<class T> ErrCode Lerc::CheckForNaN(const T* arr, int nDim, int nCols, int nRows, const Byte* pByteMask)
572 {
573 if (!arr || nDim <= 0 || nCols <= 0 || nRows <= 0)
574 return ErrCode::WrongParam;
575
576 if (typeid(T) != typeid(double) && typeid(T) != typeid(float))
577 return ErrCode::Ok;
578
579 for (size_t k = 0, i = 0; i < (size_t)nRows; i++)
580 {
581 bool bFoundNaN = false;
582 const T* rowArr = &(arr[i * nCols * nDim]);
583
584 if (!pByteMask) // all valid
585 {
586 size_t num = (size_t)nCols * nDim;
587 for (size_t m = 0; m < num; m++)
588 if (std::isnan((double)rowArr[m]))
589 bFoundNaN = true;
590 }
591 else // not all valid
592 {
593 for (size_t n = 0, j = 0; j < (size_t)nCols; j++, k++, n += nDim)
594 if (pByteMask[k])
595 {
596 for (int m = 0; m < nDim; m++)
597 if (std::isnan((double)rowArr[n + m]))
598 bFoundNaN = true;
599 }
600 }
601
602 if (bFoundNaN)
603 return ErrCode::NaN;
604 }
605
606 return ErrCode::Ok;
607 }
608
609 // -------------------------------------------------------------------------- ;
610
ReplaceNaNValues(std::vector<T> & dataBuffer,std::vector<Byte> & maskBuffer,int nDim,int nCols,int nRows)611 template<class T> bool Lerc::ReplaceNaNValues(std::vector<T>& dataBuffer, std::vector<Byte>& maskBuffer, int nDim, int nCols, int nRows)
612 {
613 if (nDim <= 0 || nCols <= 0 || nRows <= 0 || dataBuffer.size() != (size_t)nDim * nCols * nRows || maskBuffer.size() != (size_t)nCols * nRows)
614 return false;
615
616 bool bIsFloat = (typeid(T) == typeid(float));
617 const T noDataValue = (T)(bIsFloat ? -FLT_MAX : -DBL_MAX);
618
619 for (size_t k = 0, i = 0; i < (size_t)nRows; i++)
620 {
621 T* rowArr = &(dataBuffer[i * nCols * nDim]);
622
623 for (size_t n = 0, j = 0; j < (size_t)nCols; j++, k++, n += nDim)
624 {
625 if (maskBuffer[k])
626 {
627 int cntNaN = 0;
628
629 for (int m = 0; m < nDim; m++)
630 if (std::isnan((double)rowArr[n + m]))
631 {
632 cntNaN++;
633 rowArr[n + m] = noDataValue;
634 }
635
636 if (cntNaN == nDim)
637 maskBuffer[k] = 0;
638 }
639 }
640 }
641
642 return true;
643 }
644
645 // -------------------------------------------------------------------------- ;
646
Resize(std::vector<T> & buffer,size_t nElem)647 template<class T> bool Lerc::Resize(std::vector<T>& buffer, size_t nElem)
648 {
649 try
650 {
651 buffer.resize(nElem);
652 }
653 catch (...)
654 {
655 return false;
656 }
657
658 return true;
659 }
660
661 // -------------------------------------------------------------------------- ;
662
Convert(const Byte * pByteMask,int nCols,int nRows,BitMask & bitMask)663 bool Lerc::Convert(const Byte* pByteMask, int nCols, int nRows, BitMask& bitMask)
664 {
665 if (!pByteMask || nCols <= 0 || nRows <= 0)
666 return false;
667
668 if (!bitMask.SetSize(nCols, nRows))
669 return false;
670
671 bitMask.SetAllValid();
672
673 for (int k = 0, i = 0; i < nRows; i++)
674 for (int j = 0; j < nCols; j++, k++)
675 if (!pByteMask[k])
676 bitMask.SetInvalid(k);
677
678 return true;
679 }
680
681 // -------------------------------------------------------------------------- ;
682
Convert(const BitMask & bitMask,Byte * pByteMask)683 bool Lerc::Convert(const BitMask& bitMask, Byte* pByteMask)
684 {
685 int nCols = bitMask.GetWidth();
686 int nRows = bitMask.GetHeight();
687
688 if (nCols <= 0 || nRows <= 0 || !pByteMask)
689 return false;
690
691 memset(pByteMask, 0, (size_t)nCols * nRows);
692
693 for (int k = 0, i = 0; i < nRows; i++)
694 for (int j = 0; j < nCols; j++, k++)
695 if (bitMask.IsValid(k))
696 pByteMask[k] = 1;
697
698 return true;
699 }
700
701 // -------------------------------------------------------------------------- ;
702
MasksDiffer(const Byte * p0,const Byte * p1,size_t n)703 bool Lerc::MasksDiffer(const Byte* p0, const Byte* p1, size_t n)
704 {
705 if (p0 == p1)
706 return false;
707
708 if (!p0) // means all valid
709 return memchr(p1, 0, n); // any invalid?
710 else if (!p1)
711 return memchr(p0, 0, n);
712 else
713 return memcmp(p0, p1, n);
714 }
715
716 // -------------------------------------------------------------------------- ;
717
718