Line data Source code
1 : /*
2 : Copyright 2013-2021 Esri
3 : Licensed under the Apache License, Version 2.0 (the "License");
4 : you may not use this file except in compliance with the License.
5 : You may obtain a copy of the License at
6 : http://www.apache.org/licenses/LICENSE-2.0
7 : Unless required by applicable law or agreed to in writing, software
8 : distributed under the License is distributed on an "AS IS" BASIS,
9 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 : See the License for the specific language governing permissions and
11 : limitations under the License.
12 : A local copy of the license and additional notices are located with the
13 : source distribution at:
14 : http://github.com/Esri/lerc/
15 :
16 : LERC band implementation
17 : LERC page compression and decompression functions
18 :
19 : Authors: Lucian Plesea
20 : */
21 :
22 : #include "marfa.h"
23 : #include <algorithm>
24 : #include <vector>
25 : #include "LERCV1/Lerc1Image.h"
26 :
27 : #include "gdal_priv_templates.hpp"
28 : #include "gdal_openinfo.h"
29 :
30 : // Requires lerc at least 2v4, where the c_api changed, but there is no good way
31 : // to check
32 : #include <Lerc_c_api.h>
33 : #include <Lerc_types.h>
34 :
35 : #ifndef LERC_AT_LEAST_VERSION
36 : #define LERC_AT_LEAST_VERSION(maj, min, patch) 0
37 : #endif
38 :
39 : // name of internal or external libLerc namespace
40 : #if defined(USING_NAMESPACE_LERC)
41 : #define L2NS GDAL_LercNS
42 : #else
43 : // External lerc
44 : #define L2NS LercNS
45 : #endif
46 :
47 : USING_NAMESPACE_LERC1
48 : NAMESPACE_MRF_START
49 :
50 : // Read an unaligned 4 byte little endian int from location p, advances pointer
51 160 : static void READ_GINT32(int &X, const char *&p)
52 : {
53 160 : memcpy(&X, p, sizeof(GInt32));
54 160 : p += sizeof(GInt32);
55 160 : }
56 :
57 16 : static void READ_FLOAT(float &X, const char *&p)
58 : {
59 16 : memcpy(&X, p, sizeof(float));
60 16 : p += sizeof(float);
61 16 : }
62 :
63 : //
64 : // Check that a buffer contains a supported Lerc1 blob, the type supported by
65 : // MRF Can't really check everything without decoding, this just checks the main
66 : // structure returns actual size if it is Lerc1 with size < sz returns 0 if
67 : // format doesn't match returns -1 if Lerc1 but size can't be determined
68 : //
69 : // returns -<actual size> if actual size > sz
70 :
71 16 : static int checkV1(const char *s, size_t sz)
72 : {
73 : GInt32 nBytesMask, nBytesData;
74 :
75 : // Header is 34 bytes
76 : // band header is 16, first mask band then data band
77 16 : if (sz < static_cast<size_t>(
78 16 : Lerc1Image::computeNumBytesNeededToWriteVoidImage()))
79 0 : return 0;
80 : // First ten bytes are ASCII signature
81 16 : if (!STARTS_WITH(s, "CntZImage "))
82 0 : return 0;
83 16 : s += 10;
84 :
85 : // Version 11
86 : int i;
87 16 : READ_GINT32(i, s);
88 16 : if (i != 11)
89 0 : return 0;
90 :
91 : // Type 8 is CntZ
92 16 : READ_GINT32(i, s);
93 16 : if (i != 8)
94 0 : return 0;
95 :
96 : // Height
97 16 : READ_GINT32(i, s); // Arbitrary number in Lerc1Image::read()
98 16 : if (i > 20000 || i <= 0)
99 0 : return 0;
100 :
101 : // Width
102 16 : READ_GINT32(i, s);
103 16 : if (i > 20000 || i <= 0)
104 0 : return 0;
105 :
106 : // Skip the max val stored as double
107 16 : s += sizeof(double);
108 :
109 : // First header should be the mask, which mean 0 blocks
110 : // Height
111 16 : READ_GINT32(i, s);
112 16 : if (i != 0)
113 0 : return 0;
114 :
115 : // WIDTH
116 16 : READ_GINT32(i, s);
117 16 : if (i != 0)
118 0 : return 0;
119 :
120 16 : READ_GINT32(nBytesMask, s);
121 16 : if (nBytesMask < 0)
122 0 : return 0;
123 :
124 : // mask max value, 0 or 1 as float
125 : float val;
126 16 : READ_FLOAT(val, s);
127 16 : if (val != 0.0f && val != 1.0f)
128 0 : return 0;
129 :
130 : // If data header can't be read the actual size is unknown
131 16 : if (nBytesMask > INT_MAX - 66 || static_cast<size_t>(66 + nBytesMask) >= sz)
132 : {
133 0 : return -1;
134 : }
135 :
136 16 : s += nBytesMask;
137 :
138 : // Data Band header
139 16 : READ_GINT32(i,
140 : s); // number of full height blocks, never single pixel blocks
141 16 : if (i <= 0 || i > 10000)
142 0 : return 0;
143 :
144 16 : READ_GINT32(i,
145 : s); // number of full width blocks, never single pixel blocks
146 16 : if (i <= 0 || i > 10000)
147 0 : return 0;
148 :
149 16 : READ_GINT32(nBytesData, s);
150 16 : if (nBytesData < 0)
151 0 : return 0;
152 :
153 : // Actual LERC blob size
154 16 : if (66 + nBytesMask > INT_MAX - nBytesData)
155 0 : return -1;
156 16 : int size = static_cast<int>(66 + nBytesMask + nBytesData);
157 16 : return (static_cast<size_t>(size) > sz) ? -size : size;
158 : }
159 :
160 : // Load a buffer of type T into a LERC1 zImg, with a given stride
161 : template <typename T>
162 12 : static void Lerc1ImgFill(Lerc1Image &zImg, T *src, const ILImage &img,
163 : GInt32 stride)
164 : {
165 12 : int w = img.pagesize.x;
166 12 : int h = img.pagesize.y;
167 12 : zImg.resize(w, h);
168 12 : const float ndv = static_cast<float>(img.hasNoData ? img.NoDataValue : 0);
169 12 : if (stride == 1)
170 : {
171 4617 : for (int row = 0; row < h; row++)
172 2363904 : for (int col = 0; col < w; col++)
173 : {
174 2359296 : float val = static_cast<float>(*src++);
175 2359296 : zImg(row, col) = val;
176 2359296 : zImg.SetMask(row, col, !CPLIsEqual(ndv, val));
177 : }
178 9 : return;
179 : }
180 1539 : for (int row = 0; row < h; row++)
181 787968 : for (int col = 0; col < w; col++)
182 : {
183 786432 : float val = static_cast<float>(*src);
184 786432 : src += stride;
185 786432 : zImg(row, col) = val;
186 786432 : zImg.SetMask(row, col, !CPLIsEqual(ndv, val));
187 : }
188 : }
189 :
190 : // Unload LERC1 zImg into a type T buffer
191 : template <typename T>
192 16 : static bool Lerc1ImgUFill(Lerc1Image &zImg, T *dst, const ILImage &img,
193 : GInt32 stride)
194 : {
195 14 : const T ndv =
196 14 : static_cast<T>(img.hasNoData && GDALIsValueInRange<T>(img.NoDataValue)
197 10 : ? img.NoDataValue
198 : : 0);
199 16 : if (img.pagesize.y != zImg.getHeight() || img.pagesize.x != zImg.getWidth())
200 0 : return false;
201 16 : int w = img.pagesize.x;
202 16 : int h = img.pagesize.y;
203 16 : if (1 == stride)
204 : {
205 6672 : for (int row = 0; row < h; row++)
206 : {
207 3417610 : for (int col = 0; col < w; col++)
208 : {
209 3410950 : if (zImg.IsValid(row, col))
210 : {
211 27592 : GDALCopyWord(zImg(row, col), *dst);
212 : }
213 : else
214 : {
215 3383350 : *dst = ndv;
216 : }
217 3410950 : ++dst;
218 : }
219 : }
220 13 : return true;
221 : }
222 1539 : for (int row = 0; row < h; row++)
223 : {
224 787968 : for (int col = 0; col < w; col++)
225 : {
226 786432 : if (zImg.IsValid(row, col))
227 : {
228 239713 : GDALCopyWord(zImg(row, col), *dst);
229 : }
230 : else
231 : {
232 546719 : *dst = ndv;
233 : }
234 786432 : dst += stride;
235 : }
236 : }
237 3 : return true;
238 : }
239 :
240 10 : static CPLErr CompressLERC1(buf_mgr &dst, buf_mgr &src, const ILImage &img,
241 : double precision)
242 : {
243 20 : Lerc1Image zImg;
244 10 : GInt32 stride = img.pagesize.c;
245 10 : Lerc1NS::Byte *ptr = reinterpret_cast<Lerc1NS::Byte *>(dst.buffer);
246 :
247 22 : for (int c = 0; c < stride; c++)
248 : {
249 : #define FILL(T) \
250 : Lerc1ImgFill(zImg, reinterpret_cast<T *>(src.buffer) + c, img, stride)
251 12 : switch (img.dt)
252 : {
253 5 : case GDT_Byte:
254 5 : FILL(GByte);
255 5 : break;
256 1 : case GDT_UInt16:
257 1 : FILL(GUInt16);
258 1 : break;
259 1 : case GDT_Int16:
260 1 : FILL(GInt16);
261 1 : break;
262 1 : case GDT_Int32:
263 1 : FILL(GInt32);
264 1 : break;
265 1 : case GDT_UInt32:
266 1 : FILL(GUInt32);
267 1 : break;
268 2 : case GDT_Float32:
269 2 : FILL(float);
270 2 : break;
271 1 : case GDT_Float64:
272 1 : FILL(double);
273 1 : break;
274 0 : default:
275 0 : break;
276 : }
277 : #undef FILL
278 12 : if (!zImg.write(&ptr, precision))
279 : {
280 0 : CPLError(CE_Failure, CPLE_AppDefined,
281 : "MRF: Error during LERC compression");
282 0 : return CE_Failure;
283 : }
284 : }
285 :
286 : // write changes the value of the pointer, we can find the size by testing
287 : // how far it moved Add a couple of bytes, to avoid buffer overflow on
288 : // reading
289 10 : dst.size = reinterpret_cast<char *>(ptr) - dst.buffer + PADDING_BYTES;
290 10 : CPLDebug("MRF_LERC", "LERC Compressed to %d\n", (int)dst.size);
291 10 : return CE_None;
292 : }
293 :
294 : // LERC 1 Decompression
295 14 : static CPLErr DecompressLERC1(buf_mgr &dst, const buf_mgr &src,
296 : const ILImage &img)
297 : {
298 28 : Lerc1Image zImg;
299 :
300 : // need to add the padding bytes so that out-of-buffer-access
301 14 : size_t nRemainingBytes = src.size + PADDING_BYTES;
302 14 : Lerc1NS::Byte *ptr = reinterpret_cast<Lerc1NS::Byte *>(src.buffer);
303 14 : GInt32 stride = img.pagesize.c;
304 30 : for (int c = 0; c < stride; c++)
305 : {
306 : // Check that input passes snicker test
307 16 : if (checkV1(reinterpret_cast<char *>(ptr), nRemainingBytes) <= 0)
308 : {
309 0 : CPLError(CE_Failure, CPLE_AppDefined,
310 : "MRF: LERC1 tile format error");
311 0 : return CE_Failure;
312 : }
313 :
314 16 : if (!zImg.read(&ptr, nRemainingBytes, 1e12))
315 : {
316 0 : CPLError(CE_Failure, CPLE_AppDefined,
317 : "MRF: Error during LERC decompression");
318 0 : return CE_Failure;
319 : }
320 :
321 : // Unpack from zImg to dst buffer, calling the right type
322 16 : bool success = false;
323 : #define UFILL(T) \
324 : success = Lerc1ImgUFill(zImg, reinterpret_cast<T *>(dst.buffer) + c, img, \
325 : stride)
326 16 : switch (img.dt)
327 : {
328 7 : case GDT_Byte:
329 7 : UFILL(GByte);
330 7 : break;
331 0 : case GDT_Int8:
332 0 : UFILL(GInt8);
333 0 : break;
334 1 : case GDT_UInt16:
335 1 : UFILL(GUInt16);
336 1 : break;
337 1 : case GDT_Int16:
338 1 : UFILL(GInt16);
339 1 : break;
340 1 : case GDT_Int32:
341 1 : UFILL(GInt32);
342 1 : break;
343 1 : case GDT_UInt32:
344 1 : UFILL(GUInt32);
345 1 : break;
346 4 : case GDT_Float32:
347 4 : UFILL(float);
348 4 : break;
349 1 : case GDT_Float64:
350 1 : UFILL(double);
351 1 : break;
352 0 : default:
353 0 : break;
354 : }
355 : #undef UFILL
356 16 : if (!success)
357 : {
358 0 : CPLError(CE_Failure, CPLE_AppDefined,
359 : "MRF: Error during LERC decompression");
360 0 : return CE_Failure;
361 : }
362 : }
363 :
364 14 : return CE_None;
365 : }
366 :
367 : // Lerc2
368 :
369 1 : static GDALDataType L2toGDT(L2NS::DataType L2type)
370 : {
371 : GDALDataType dt;
372 1 : switch (L2type)
373 : {
374 0 : case L2NS::DataType::dt_short:
375 0 : dt = GDT_Int16;
376 0 : break;
377 0 : case L2NS::DataType::dt_ushort:
378 0 : dt = GDT_UInt16;
379 0 : break;
380 0 : case L2NS::DataType::dt_int:
381 0 : dt = GDT_Int32;
382 0 : break;
383 0 : case L2NS::DataType::dt_uint:
384 0 : dt = GDT_UInt32;
385 0 : break;
386 0 : case L2NS::DataType::dt_float:
387 0 : dt = GDT_Float32;
388 0 : break;
389 0 : case L2NS::DataType::dt_double:
390 0 : dt = GDT_Float64;
391 0 : break;
392 0 : case L2NS::DataType::dt_char:
393 0 : dt = GDT_Int8;
394 0 : break;
395 1 : default: // Unsigned byte
396 1 : dt = GDT_Byte;
397 : }
398 1 : return dt;
399 : }
400 :
401 6424 : static L2NS::DataType GDTtoL2(GDALDataType dt)
402 : {
403 : L2NS::DataType L2dt;
404 6424 : switch (dt)
405 : {
406 2 : case GDT_Int16:
407 2 : L2dt = L2NS::DataType::dt_short;
408 2 : break;
409 2 : case GDT_UInt16:
410 2 : L2dt = L2NS::DataType::dt_ushort;
411 2 : break;
412 2 : case GDT_Int32:
413 2 : L2dt = L2NS::DataType::dt_int;
414 2 : break;
415 2 : case GDT_UInt32:
416 2 : L2dt = L2NS::DataType::dt_uint;
417 2 : break;
418 2 : case GDT_Float32:
419 2 : L2dt = L2NS::DataType::dt_float;
420 2 : break;
421 4 : case GDT_Float64:
422 4 : L2dt = L2NS::DataType::dt_double;
423 4 : break;
424 6410 : default:
425 6410 : L2dt = L2NS::DataType::dt_uchar;
426 : }
427 6424 : return L2dt;
428 : }
429 :
430 : // Populate a LERC2 bitmask based on comparison with the image no data value
431 : // Returns the number of NoData values found
432 : template <typename T>
433 1 : static size_t MaskFill(std::vector<Lerc1NS::Byte> &bm, const T *src,
434 : const ILImage &img)
435 : {
436 1 : size_t w = static_cast<size_t>(img.pagesize.x);
437 1 : size_t h = static_cast<size_t>(img.pagesize.y);
438 1 : size_t stride = static_cast<size_t>(img.pagesize.c);
439 1 : size_t nndv = 0;
440 :
441 1 : bm.resize(w * h);
442 :
443 1 : T ndv = static_cast<T>(img.NoDataValue);
444 1 : if (!img.hasNoData)
445 0 : ndv = 0; // It really doesn't get called when img doesn't have
446 : // NoDataValue
447 262145 : for (size_t i = 0; i < bm.size(); i++)
448 : {
449 262144 : if (ndv == src[i * stride])
450 : {
451 57 : bm[i] = 0;
452 57 : nndv++;
453 : }
454 : else
455 : {
456 262087 : bm[i] = 1;
457 : }
458 : }
459 :
460 1 : return nndv;
461 : }
462 :
463 : // Fill in no data values based on a LERC2 bitmask
464 : template <typename T>
465 1 : static void UnMask(std::vector<Lerc1NS::Byte> &bm, T *data, const ILImage &img)
466 : {
467 1 : size_t w = static_cast<size_t>(img.pagesize.x);
468 1 : size_t h = static_cast<size_t>(img.pagesize.y);
469 1 : size_t stride = static_cast<size_t>(img.pagesize.c);
470 :
471 1 : if (bm.size() != w * h)
472 0 : return;
473 :
474 1 : T ndv = T(img.NoDataValue);
475 1 : if (stride == 1)
476 : {
477 262145 : for (size_t i = 0; i < w * h; i++)
478 262144 : if (!bm[i])
479 0 : data[i] = ndv;
480 : }
481 : else
482 : {
483 0 : for (size_t i = 0; i < w * h; i++)
484 0 : if (!bm[i])
485 0 : for (size_t c = 0; c < stride; c++)
486 0 : data[i * stride + c] = ndv;
487 : }
488 : }
489 :
490 4812 : static CPLErr CompressLERC2(buf_mgr &dst, buf_mgr &src, const ILImage &img,
491 : double precision, int l2ver)
492 : {
493 4812 : auto w = static_cast<int>(img.pagesize.x);
494 4812 : auto h = static_cast<int>(img.pagesize.y);
495 4812 : auto stride = static_cast<int>(img.pagesize.c);
496 :
497 : // build a mask
498 9624 : std::vector<Lerc1NS::Byte> bm;
499 4812 : size_t nndv = 0;
500 4812 : if (img.hasNoData)
501 : { // Only build a bitmask if no data value is defined
502 1 : switch (img.dt)
503 : {
504 :
505 : #define MASK(T) nndv = MaskFill(bm, reinterpret_cast<T *>(src.buffer), img)
506 :
507 1 : case GDT_Byte:
508 1 : MASK(GByte);
509 1 : break;
510 0 : case GDT_UInt16:
511 0 : MASK(GUInt16);
512 0 : break;
513 0 : case GDT_Int16:
514 0 : MASK(GInt16);
515 0 : break;
516 0 : case GDT_Int32:
517 0 : MASK(GInt32);
518 0 : break;
519 0 : case GDT_UInt32:
520 0 : MASK(GUInt32);
521 0 : break;
522 0 : case GDT_Float32:
523 0 : MASK(float);
524 0 : break;
525 0 : case GDT_Float64:
526 0 : MASK(double);
527 0 : break;
528 0 : default:
529 0 : break;
530 :
531 : #undef MASK
532 : }
533 : }
534 :
535 4812 : unsigned int sz = 0;
536 4812 : auto pbm = bm.data();
537 4812 : if (!bm.empty() && nndv != bm.size())
538 1 : pbm = nullptr;
539 14436 : auto status = lerc_encodeForVersion(
540 4812 : reinterpret_cast<void *>(src.buffer), l2ver,
541 4812 : static_cast<unsigned int>(GDTtoL2(img.dt)), stride, w, h, 1,
542 : #if LERC_AT_LEAST_VERSION(3, 0, 0)
543 : pbm ? 1 : 0,
544 : #endif
545 4812 : pbm, precision, reinterpret_cast<Lerc1NS::Byte *>(dst.buffer),
546 4812 : static_cast<unsigned int>(dst.size), &sz);
547 :
548 4812 : if (L2NS::ErrCode::Ok != static_cast<L2NS::ErrCode>(status) ||
549 4812 : sz > (dst.size - PADDING_BYTES))
550 : {
551 0 : CPLError(CE_Failure, CPLE_AppDefined,
552 : "MRF: Error during LERC2 compression");
553 0 : return CE_Failure;
554 : }
555 :
556 4812 : dst.size = static_cast<size_t>(sz) + PADDING_BYTES;
557 4812 : return CE_None;
558 : }
559 :
560 : // LERC1 splits of early, so this is mostly LERC2
561 1626 : CPLErr LERC_Band::Decompress(buf_mgr &dst, buf_mgr &src)
562 : {
563 2693 : if (src.size >= Lerc1Image::computeNumBytesNeededToWriteVoidImage() &&
564 1067 : IsLerc1(src.buffer))
565 14 : return DecompressLERC1(dst, src, img);
566 :
567 : // Can only be LERC2 here, verify
568 1612 : if (src.size < 50 || !IsLerc2(src.buffer))
569 : {
570 0 : CPLError(CE_Failure, CPLE_AppDefined, "MRF: Not a lerc tile");
571 0 : return CE_Failure;
572 : }
573 :
574 1612 : auto w = static_cast<int>(img.pagesize.x);
575 1612 : auto h = static_cast<int>(img.pagesize.y);
576 1612 : auto stride = static_cast<int>(img.pagesize.c);
577 :
578 3224 : std::vector<Lerc1NS::Byte> bm;
579 1612 : if (img.hasNoData)
580 1 : bm.resize(static_cast<size_t>(w) * static_cast<size_t>(h));
581 1612 : auto pbm = bm.data();
582 1612 : if (bm.empty())
583 1611 : pbm = nullptr;
584 :
585 : // Decoding may fail for many different reasons, including input not
586 : // matching tile expectations
587 : auto status =
588 3224 : lerc_decode(reinterpret_cast<Lerc1NS::Byte *>(src.buffer),
589 1612 : static_cast<unsigned int>(src.size),
590 : #if LERC_AT_LEAST_VERSION(3, 0, 0)
591 : pbm ? 1 : 0,
592 : #endif
593 : pbm, stride, w, h, 1,
594 1612 : static_cast<unsigned int>(GDTtoL2(img.dt)), dst.buffer);
595 1612 : if (L2NS::ErrCode::Ok != static_cast<L2NS::ErrCode>(status))
596 : {
597 0 : CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error decoding Lerc");
598 0 : return CE_Failure;
599 : }
600 :
601 : // No mask means we're done
602 1612 : if (bm.empty())
603 1611 : return CE_None;
604 :
605 : // Fill in no data values
606 1 : switch (img.dt)
607 : {
608 : #define UNMASK(T) UnMask(bm, reinterpret_cast<T *>(dst.buffer), img)
609 1 : case GDT_Byte:
610 1 : UNMASK(GByte);
611 1 : break;
612 0 : case GDT_UInt16:
613 0 : UNMASK(GUInt16);
614 0 : break;
615 0 : case GDT_Int16:
616 0 : UNMASK(GInt16);
617 0 : break;
618 0 : case GDT_Int32:
619 0 : UNMASK(GInt32);
620 0 : break;
621 0 : case GDT_UInt32:
622 0 : UNMASK(GUInt32);
623 0 : break;
624 0 : case GDT_Float32:
625 0 : UNMASK(float);
626 0 : break;
627 0 : case GDT_Float64:
628 0 : UNMASK(double);
629 0 : break;
630 0 : default:
631 0 : break;
632 : #undef DECODE
633 : }
634 1 : return CE_None;
635 : }
636 :
637 4822 : CPLErr LERC_Band::Compress(buf_mgr &dst, buf_mgr &src)
638 : {
639 4822 : if (version == 2)
640 4812 : return CompressLERC2(dst, src, img, precision, l2ver);
641 : else
642 10 : return CompressLERC1(dst, src, img, precision);
643 : }
644 :
645 6 : CPLXMLNode *LERC_Band::GetMRFConfig(GDALOpenInfo *poOpenInfo)
646 : {
647 : // Header of Lerc2 takes 58 bytes, an empty area 62 or more, depending on
648 : // the subversion. Size of Lerc1 empty file is 67 Anything under 50 bytes
649 : // can't be lerc
650 6 : if (poOpenInfo->eAccess != GA_ReadOnly ||
651 6 : poOpenInfo->pszFilename == nullptr ||
652 6 : poOpenInfo->pabyHeader == nullptr ||
653 6 : strlen(poOpenInfo->pszFilename) < 1 || poOpenInfo->nHeaderBytes < 50)
654 0 : return nullptr;
655 :
656 : // Check the header too
657 6 : char *psz = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
658 12 : CPLString sHeader;
659 6 : sHeader.assign(psz, psz + poOpenInfo->nHeaderBytes);
660 6 : if (!(IsLerc1(sHeader) || IsLerc2(sHeader)))
661 0 : return nullptr;
662 :
663 6 : GDALDataType dt = GDT_Unknown; // Use this as a validity flag
664 :
665 : // Use this structure to fetch width and height
666 6 : ILSize size(-1, -1, 1, 1, 1);
667 :
668 11 : if (IsLerc1(sHeader) &&
669 5 : sHeader.size() >= Lerc1Image::computeNumBytesNeededToWriteVoidImage())
670 : {
671 5 : if (Lerc1Image::getwh(reinterpret_cast<Lerc1NS::Byte *>(psz),
672 5 : poOpenInfo->nHeaderBytes, size.x, size.y))
673 5 : dt = GDALGetDataTypeByName(CSLFetchNameValueDef(
674 5 : poOpenInfo->papszOpenOptions, "DATATYPE", "Byte"));
675 : }
676 1 : else if (IsLerc2(sHeader))
677 : {
678 : // getBlobInfo will fail without the whole LERC blob
679 : // Wasteful, but that's the only choice given by the LERC C API
680 : // This will only work if the Lerc2 file is under the constant defined
681 : // here
682 : static const GIntBig MAX_L2SIZE(10 * 1024 * 1024); // 10MB
683 1 : GByte *buffer = nullptr;
684 : vsi_l_offset l2size;
685 :
686 : #define INFOIDX(T) static_cast<size_t>(L2NS::InfoArrOrder::T)
687 :
688 1 : if (VSIIngestFile(nullptr, poOpenInfo->pszFilename, &buffer, &l2size,
689 1 : MAX_L2SIZE))
690 : {
691 : //! Info returned in infoArray is { version, dataType, nDim, nCols,
692 : //! nRows, nBands, nValidPixels... }, see Lerc_types.h .
693 2 : std::vector<unsigned int> info(INFOIDX(nValidPixels) + 1);
694 : auto status =
695 1 : lerc_getBlobInfo(reinterpret_cast<Lerc1NS::Byte *>(buffer),
696 : static_cast<unsigned int>(l2size), info.data(),
697 1 : nullptr, static_cast<int>(info.size()), 0);
698 1 : VSIFree(buffer);
699 2 : if (L2NS::ErrCode::Ok == static_cast<L2NS::ErrCode>(status) &&
700 1 : 1 == info[INFOIDX(nBands)])
701 : {
702 1 : size.x = info[INFOIDX(nCols)];
703 1 : size.y = info[INFOIDX(nRows)];
704 1 : if (info[INFOIDX(version)] > 3) // Single band before version 4
705 0 : size.c = info[INFOIDX(nDim)];
706 1 : dt = L2toGDT(
707 1 : static_cast<L2NS::DataType>(info[INFOIDX(dataType)]));
708 : }
709 : }
710 : }
711 :
712 6 : if (size.x <= 0 || size.y <= 0 || dt == GDT_Unknown)
713 0 : return nullptr;
714 :
715 : // Build and return the MRF configuration for a single tile reader
716 6 : CPLXMLNode *config = CPLCreateXMLNode(nullptr, CXT_Element, "MRF_META");
717 6 : CPLXMLNode *raster = CPLCreateXMLNode(config, CXT_Element, "Raster");
718 6 : XMLSetAttributeVal(raster, "Size", size, "%.0f");
719 6 : XMLSetAttributeVal(raster, "PageSize", size, "%.0f");
720 6 : CPLCreateXMLElementAndValue(raster, "Compression", CompName(IL_LERC));
721 6 : CPLCreateXMLElementAndValue(raster, "DataType", GDALGetDataTypeName(dt));
722 6 : CPLCreateXMLElementAndValue(raster, "DataFile", poOpenInfo->pszFilename);
723 : // Set a magic index file name to prevent the driver from attempting to open
724 : // it
725 6 : CPLCreateXMLElementAndValue(raster, "IndexFile", "(null)");
726 : // The NDV could be passed as an open option
727 : const char *pszNDV =
728 6 : CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "NDV", "");
729 6 : if (strlen(pszNDV) > 0)
730 : {
731 : CPLXMLNode *values =
732 4 : CPLCreateXMLNode(raster, CXT_Element, "DataValues");
733 4 : XMLSetAttributeVal(values, "NoData", pszNDV);
734 : }
735 6 : return config;
736 : }
737 :
738 75 : LERC_Band::LERC_Band(MRFDataset *pDS, const ILImage &image, int b, int level)
739 75 : : MRFRasterBand(pDS, image, b, level)
740 : {
741 : // Lerc doesn't handle 64bit int types
742 75 : if (image.dt == GDT_UInt64 || image.dt == GDT_Int64)
743 : {
744 0 : CPLError(CE_Failure, CPLE_NotSupported,
745 : "Lerc compression of 64 bit integers is not supported");
746 0 : return;
747 : }
748 :
749 : // Pick 1/1000 for floats and 0.5 losless for integers.
750 75 : if (eDataType == GDT_Float32 || eDataType == GDT_Float64)
751 17 : precision = strtod(GetOptionValue("LERC_PREC", ".001"), nullptr);
752 : else
753 58 : precision =
754 58 : std::max(0.5, strtod(GetOptionValue("LERC_PREC", ".5"), nullptr));
755 :
756 : // Encode in V2 by default.
757 75 : version = GetOptlist().FetchBoolean("V1", FALSE) ? 1 : 2;
758 : // For LERC 2 there are multiple versions too, -1 means use the library
759 : // default Use v2.2 for single band encoding
760 150 : l2ver = atoi(GetOptlist().FetchNameValueDef(
761 75 : "L2_VER", (img.pagesize.c == 1) ? "2" : "-1"));
762 :
763 75 : if (image.pageSizeBytes > INT_MAX / 4)
764 : {
765 0 : CPLError(CE_Failure, CPLE_AppDefined, "LERC page too large");
766 0 : return;
767 : }
768 : // Enlarge the page buffer, LERC may expand data.
769 75 : pDS->SetPBufferSize(2 * image.pageSizeBytes);
770 : }
771 :
772 150 : LERC_Band::~LERC_Band()
773 : {
774 150 : }
775 :
776 : NAMESPACE_MRF_END
|