Line data Source code
1 : /*
2 : * Copyright (c) 2002-2012, California Institute of Technology.
3 : * All rights reserved. Based on Government Sponsored Research under contracts
4 : * NAS7-1407 and/or NAS7-03001.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions are met:
8 : * 1. Redistributions of source code must retain the above copyright notice,
9 : * this list of conditions and the following disclaimer.
10 : * 2. Redistributions in binary form must reproduce the above copyright
11 : * notice, this list of conditions and the following disclaimer in the
12 : * documentation and/or other materials provided with the distribution.
13 : * 3. Neither the name of the California Institute of Technology (Caltech),
14 : * its operating division the Jet Propulsion Laboratory (JPL), the National
15 : * Aeronautics and Space Administration (NASA), nor the names of its
16 : * contributors may be used to endorse or promote products derived from this
17 : * software without specific prior written permission.
18 : *
19 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 : * ARE DISCLAIMED. IN NO EVENT SHALL THE CALIFORNIA INSTITUTE OF TECHNOLOGY BE
23 : * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 : * POSSIBILITY OF SUCH DAMAGE.
30 : *
31 : * Copyright 2014-2021 Esri
32 : *
33 : * Licensed under the Apache License, Version 2.0 (the "License");
34 : * you may not use this file except in compliance with the License.
35 : * You may obtain a copy of the License at
36 : *
37 : * http://www.apache.org/licenses/LICENSE-2.0
38 : *
39 : * Unless required by applicable law or agreed to in writing, software
40 : * distributed under the License is distributed on an "AS IS" BASIS,
41 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
42 : * See the License for the specific language governing permissions and
43 : * limitations under the License.
44 : *
45 : * Functions used by the driver, should have prototypes in the header file
46 : *
47 : * Author: Lucian Plesea
48 : */
49 :
50 : #include "marfa.h"
51 : #include <zlib.h>
52 : #include <algorithm>
53 : #include <limits>
54 : #include "mrfdrivercore.h"
55 : #include "gdal_frmts.h"
56 :
57 : // LERC and QB3 only work on little endian machines
58 : #if defined(WORDS_BIGENDIAN)
59 : #undef LERC
60 : #undef QB3_SUPPORT
61 : #endif
62 :
63 : NAMESPACE_MRF_START
64 :
65 : // These have to be positionally in sync with the enums in marfa.h
66 : static const char *const ILC_N[] = {
67 : #ifdef HAVE_PNG
68 : "PNG", "PPNG",
69 : #endif
70 : #ifdef HAVE_JPEG
71 : "JPEG",
72 : #endif
73 : #if defined(HAVE_PNG) && defined(HAVE_JPEG)
74 : "JPNG",
75 : #endif
76 : "NONE", "DEFLATE", "TIF",
77 : #if defined(LERC)
78 : "LERC",
79 : #endif
80 : #if defined(ZSTD_SUPPORT)
81 : "ZSTD",
82 : #endif
83 : #if defined(QB3_SUPPORT)
84 : "QB3",
85 : #endif
86 : "Unknown"};
87 :
88 : static const char *const ILC_E[] = {
89 : #ifdef HAVE_PNG
90 : ".ppg", ".ppg",
91 : #endif
92 : #ifdef HAVE_JPEG
93 : ".pjg",
94 : #endif
95 : #if defined(HAVE_PNG) && defined(HAVE_JPEG)
96 : ".pjp",
97 : #endif
98 : ".til", ".pzp", ".ptf",
99 : #if defined(LERC)
100 : ".lrc",
101 : #endif
102 : #if defined(ZSTD_SUPPORT)
103 : ".pzs",
104 : #endif
105 : #if defined(QB3_SUPPORT)
106 : ".pq3",
107 : #endif
108 : ""};
109 :
110 : static const char *const ILO_N[] = {"PIXEL", "BAND", "LINE", "Unknown"};
111 :
112 : char const *const *ILComp_Name = ILC_N;
113 : char const *const *ILComp_Ext = ILC_E;
114 : char const *const *ILOrder_Name = ILO_N;
115 :
116 : /**
117 : * Get the string for a compression type
118 : */
119 567 : const char *CompName(ILCompression comp)
120 : {
121 567 : if (comp >= IL_ERR_COMP)
122 0 : return ILComp_Name[IL_ERR_COMP];
123 567 : return ILComp_Name[comp];
124 : }
125 :
126 : /**
127 : * Get the string for an order type
128 : */
129 367 : const char *OrderName(ILOrder val)
130 : {
131 367 : if (val >= IL_ERR_ORD)
132 0 : return ILOrder_Name[IL_ERR_ORD];
133 367 : return ILOrder_Name[val];
134 : }
135 :
136 463 : ILCompression CompToken(const char *opt, ILCompression def)
137 : {
138 : int i;
139 463 : if (nullptr == opt)
140 0 : return def;
141 2458 : for (i = 0; ILCompression(i) < IL_ERR_COMP; i++)
142 2458 : if (EQUAL(opt, ILComp_Name[i]))
143 463 : break;
144 463 : if (IL_ERR_COMP == ILCompression(i))
145 0 : return def;
146 463 : return ILCompression(i);
147 : }
148 :
149 : /**
150 : * Find a compression token
151 : */
152 496 : ILOrder OrderToken(const char *opt, ILOrder def)
153 : {
154 : int i;
155 496 : if (nullptr == opt)
156 0 : return def;
157 638 : for (i = 0; ILOrder(i) < IL_ERR_ORD; i++)
158 638 : if (EQUAL(opt, ILOrder_Name[i]))
159 496 : break;
160 496 : if (IL_ERR_ORD == ILOrder(i))
161 0 : return def;
162 496 : return ILOrder(i);
163 : }
164 :
165 : //
166 : // Inserters for ILSize and ILIdx types
167 : //
168 0 : std::ostream &operator<<(std::ostream &out, const ILSize &sz)
169 : {
170 0 : out << "X=" << sz.x << ",Y=" << sz.y << ",Z=" << sz.z << ",C=" << sz.c
171 0 : << ",L=" << sz.l;
172 0 : return out;
173 : }
174 :
175 0 : std::ostream &operator<<(std::ostream &out, const ILIdx &t)
176 : {
177 0 : out << "offset=" << t.offset << ",size=" << t.size;
178 0 : return out;
179 : }
180 :
181 : // Define PPMW to enable this handy debug function
182 : #ifdef PPMW
183 : void ppmWrite(const char *fname, const char *data, const ILSize &sz)
184 : {
185 : FILE *fp = fopen(fname, "wb");
186 : switch (sz.c)
187 : {
188 : case 4: // Strip the alpha
189 : fprintf(fp, "P6 %d %d 255\n", sz.x, sz.y);
190 : {
191 : char *d = (char *)data;
192 : for (int i = sz.x * sz.y; i; i--)
193 : {
194 : fwrite(d, 3, 1, fp);
195 : d += 4;
196 : }
197 : }
198 : break;
199 : case 3:
200 : fprintf(fp, "P6 %d %d 255\n", sz.x, sz.y);
201 : fwrite(data, sz.x * sz.y, 3, fp);
202 : break;
203 : case 1:
204 : fprintf(fp, "P5 %d %d 255\n", sz.x, sz.y);
205 : fwrite(data, sz.x, sz.y, fp);
206 : break;
207 : default:
208 : fprintf(stderr, "Can't write ppm file with %d bands\n", /*ok*/
209 : sz.c);
210 : }
211 : fclose(fp);
212 : return;
213 : }
214 : #endif
215 :
216 : // Returns the size of the index for image and overlays
217 : // If scale is zero, only base image
218 314 : GIntBig IdxSize(const ILImage &full, const int scale)
219 : {
220 628 : ILImage img = full;
221 314 : img.pagecount = pcount(img.size, img.pagesize);
222 314 : GIntBig sz = img.pagecount.l;
223 353 : while (scale != 0 && 1 != img.pagecount.x * img.pagecount.y)
224 : {
225 39 : img.size.x = pcount(img.size.x, scale);
226 39 : img.size.y = pcount(img.size.y, scale);
227 39 : img.pagecount = pcount(img.size, img.pagesize);
228 39 : sz += img.pagecount.l;
229 : }
230 :
231 314 : if (sz >
232 314 : std::numeric_limits<GIntBig>::max() / static_cast<int>(sizeof(ILIdx)))
233 : {
234 0 : CPLError(CE_Failure, CPLE_AppDefined, "IdxSize: integer overflow");
235 0 : return 0;
236 : }
237 314 : return sz * sizeof(ILIdx);
238 : }
239 :
240 876 : ILImage::ILImage()
241 : : dataoffset(0), idxoffset(0), quality(85), pageSizeBytes(0),
242 : size(ILSize(1, 1, 1, 1, 0)), pagesize(ILSize(384, 384, 1, 1, 0)),
243 876 : pagecount(pcount(size, pagesize)),
244 : #ifdef HAVE_PNG
245 : comp(IL_PNG),
246 : #else
247 : comp(IL_NONE),
248 : #endif
249 : order(IL_Interleaved), nbo(false), hasNoData(FALSE), NoDataValue(0.0),
250 1752 : dt(GDT_Unknown), ci(GCI_Undefined)
251 : {
252 876 : }
253 :
254 : /**
255 : *\brief Get a file name by replacing the extension.
256 : * pass the data file name and the default extension starting with .
257 : * If name length is not sufficient, it returns the extension
258 : * If the input name is curl with parameters, the base file extension gets
259 : *changed and parameters are preserved.
260 : */
261 :
262 1712 : CPLString getFname(const CPLString &in, const char *ext)
263 : {
264 1712 : if (strlen(in) < strlen(ext))
265 0 : return CPLString(ext);
266 :
267 3424 : CPLString ret(in);
268 : // Is it a web file with parameters?
269 1712 : size_t extlen = strlen(ext);
270 1712 : size_t qmark = ret.find_first_of('?');
271 1712 : if (!(qmark != std::string::npos && 0 == in.find("/vsicurl/http") &&
272 : qmark >= extlen))
273 1712 : qmark = ret.size();
274 1712 : return ret.replace(qmark - extlen, extlen, ext);
275 : }
276 :
277 : /**
278 : *\brief Get a file name, either from the configuration or from the default file
279 : *name If the token is not defined by CPLGetXMLValue, if the extension of the in
280 : *name is .xml, it returns the token with the extension changed to defext.
281 : * Otherwise it returns the token itself
282 : * It is pretty hard to separate local vs remote due to the gdal file name
283 : *ornaments Absolute file names start with: ?:/ or /
284 : *
285 : */
286 :
287 732 : CPLString getFname(CPLXMLNode *node, const char *token, const CPLString &in,
288 : const char *def)
289 : {
290 1464 : CPLString fn = CPLGetXMLValue(node, token, "");
291 732 : if (fn.empty()) // Not provided
292 720 : return getFname(in, def);
293 12 : size_t slashPos = fn.find_first_of("\\/");
294 :
295 : // Does it look like an absolute path or we won't find the basename of 'in'
296 12 : if (slashPos == 0 // Starts with slash
297 6 : || (slashPos == 2 && fn[1] == ':') // Starts with disk letter column
298 : // Does not start with dots then slash
299 6 : || (slashPos != fn.npos && slashPos != fn.find_first_not_of('.')) ||
300 6 : EQUALN(in, "<MRF_META>", 10) // XML string input
301 18 : || in.find_first_of("\\/") ==
302 : in.npos) // We can't get a basename from 'in'
303 6 : return fn;
304 :
305 : // Relative path, prepend the path from the in file name
306 12 : return in.substr(0, in.find_last_of("\\/") + 1) + fn;
307 : }
308 :
309 : /**
310 : *\brief Extracts a numerical value from a XML node
311 : * It works like CPLGetXMLValue except for the default value being
312 : * a number instead of a string
313 : */
314 :
315 4607 : double getXMLNum(CPLXMLNode *node, const char *pszPath, double def)
316 : {
317 4607 : const char *textval = CPLGetXMLValue(node, pszPath, nullptr);
318 4607 : if (textval)
319 2996 : return atof(textval);
320 1611 : return def;
321 : }
322 :
323 : //
324 : // Calculate offset of index, pos is in pages
325 : //
326 :
327 9000 : GIntBig IdxOffset(const ILSize &pos, const ILImage &img)
328 : {
329 9000 : return img.idxoffset +
330 9000 : sizeof(ILIdx) *
331 9000 : (pos.c +
332 9000 : img.pagecount.c *
333 9000 : (pos.x + img.pagecount.x *
334 9000 : (pos.y + img.pagecount.y *
335 9000 : static_cast<GIntBig>(pos.z))));
336 : }
337 :
338 : // Is compression type endianness dependent?
339 8016 : bool is_Endianness_Dependent(GDALDataType dt, ILCompression comp)
340 : {
341 : // Add here all endianness dependent compressions
342 8016 : if (IL_ZLIB == comp || IL_NONE == comp)
343 672 : if (GDALGetDataTypeSizeBytes(dt) > 1)
344 454 : return true;
345 7562 : return false;
346 : }
347 :
348 556 : MRFRasterBand *newMRFRasterBand(MRFDataset *pDS, const ILImage &image, int b,
349 : int level)
350 : {
351 556 : MRFRasterBand *bnd = nullptr;
352 556 : CPLErrorReset();
353 556 : switch (pDS->current.comp)
354 : {
355 : #ifdef HAVE_PNG
356 159 : case IL_PPNG: // Uses the PNG code, just has a palette in each PNG
357 : case IL_PNG:
358 159 : bnd = new PNG_Band(pDS, image, b, level);
359 159 : break;
360 : #endif
361 : #ifdef HAVE_JPEG
362 49 : case IL_JPEG:
363 49 : bnd = new JPEG_Band(pDS, image, b, level);
364 49 : break;
365 : #endif
366 : #if defined(HAVE_PNG) && defined(HAVE_JPEG)
367 0 : case IL_JPNG:
368 0 : bnd = new JPNG_Band(pDS, image, b, level);
369 0 : break;
370 : #endif
371 137 : case IL_NONE:
372 137 : bnd = new Raw_Band(pDS, image, b, level);
373 137 : break;
374 : #if defined(LERC)
375 75 : case IL_LERC:
376 75 : bnd = new LERC_Band(pDS, image, b, level);
377 75 : break;
378 : #endif
379 : #if defined(QB3_SUPPORT)
380 53 : case IL_QB3:
381 53 : bnd = new QB3_Band(pDS, image, b, level);
382 53 : break;
383 : #endif
384 : // ZLIB is just raw + deflate
385 26 : case IL_ZLIB:
386 26 : bnd = new Raw_Band(pDS, image, b, level);
387 26 : bnd->SetDeflate(1);
388 26 : break;
389 : // Same for ZSTD
390 : #if defined(ZSTD_SUPPORT)
391 42 : case IL_ZSTD:
392 42 : bnd = new Raw_Band(pDS, image, b, level);
393 42 : bnd->SetZstd(1);
394 42 : break;
395 : #endif
396 15 : case IL_TIF:
397 15 : if (image.pageSizeBytes > INT_MAX - 1024)
398 0 : return nullptr;
399 15 : bnd = new TIF_Band(pDS, image, b, level);
400 15 : break;
401 0 : default:
402 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
403 : "Unsupported MRF compression");
404 0 : return nullptr;
405 : }
406 :
407 : // If something was flagged during band creation
408 556 : if (CPLGetLastErrorNo() != CE_None)
409 : {
410 52 : delete bnd;
411 52 : return nullptr;
412 : }
413 :
414 : // Copy the RW mode from the dataset
415 504 : bnd->SetAccess(pDS->eAccess);
416 504 : return bnd;
417 : }
418 :
419 : /**
420 : *\brief log in a given base
421 : */
422 99 : double logbase(double val, double base)
423 : {
424 99 : return log(val) / log(base);
425 : }
426 :
427 : /**
428 : *\brief Is logbase(val, base) an integer?
429 : *
430 : */
431 33 : int IsPower(double value, double base)
432 : {
433 33 : double v = logbase(value, base);
434 33 : return CPLIsEqual(v, int(v + 0.5));
435 : }
436 :
437 : /************************************************************************/
438 : /* SearchXMLSiblings() */
439 : /************************************************************************/
440 :
441 : /**
442 : *\brief Search for a sibling of the root node with a given name.
443 : *
444 : * Searches only the next siblings of the node passed in for the named element
445 : *or attribute. If the first character of the pszElement is '=', the search
446 : *includes the psRoot node
447 : *
448 : * @param psRoot the root node to search. This should be a node of type
449 : * CXT_Element. NULL is safe.
450 : *
451 : * @param pszElement the name of the element or attribute to search for.
452 : *
453 : * @return The first matching node or NULL on failure.
454 : */
455 :
456 256 : CPLXMLNode *SearchXMLSiblings(CPLXMLNode *psRoot, const char *pszElement)
457 : {
458 256 : if (psRoot == nullptr || pszElement == nullptr)
459 0 : return nullptr;
460 :
461 : // If the strings starts with '=', skip it and test the root
462 : // If not, start testing with the next sibling
463 256 : if (pszElement[0] == '=')
464 0 : pszElement++;
465 : else
466 256 : psRoot = psRoot->psNext;
467 :
468 256 : for (; psRoot != nullptr; psRoot = psRoot->psNext)
469 255 : if ((psRoot->eType == CXT_Element || psRoot->eType == CXT_Attribute) &&
470 255 : EQUAL(pszElement, psRoot->pszValue))
471 255 : return psRoot;
472 1 : return nullptr;
473 : }
474 :
475 : //
476 : // Print a double so it can be read with strod while preserving precision
477 : // Unfortunately this is not quite possible or portable enough at this time
478 : //
479 3528 : CPLString PrintDouble(double d, const char *frmt)
480 : {
481 7056 : CPLString res;
482 3528 : res.FormatC(d, nullptr);
483 3528 : if (CPLStrtod(res.c_str(), nullptr) == d)
484 3510 : return res;
485 :
486 : // This would be the right code with a C99 compiler that supports %a
487 : // readback in strod()
488 : // return CPLString().Printf("%a",d);
489 :
490 36 : return CPLString().FormatC(d, frmt);
491 : }
492 :
493 3360 : void XMLSetAttributeVal(CPLXMLNode *parent, const char *pszName,
494 : const char *pszVal)
495 : {
496 3360 : CPLCreateXMLNode(parent, CXT_Attribute, pszName);
497 3360 : CPLSetXMLValue(parent, pszName, pszVal);
498 3360 : }
499 :
500 3356 : void XMLSetAttributeVal(CPLXMLNode *parent, const char *pszName,
501 : const double val, const char *frmt)
502 : {
503 3356 : XMLSetAttributeVal(parent, pszName, PrintDouble(val, frmt));
504 3356 : }
505 :
506 680 : CPLXMLNode *XMLSetAttributeVal(CPLXMLNode *parent, const char *pszName,
507 : const ILSize &sz, const char *frmt)
508 : {
509 680 : CPLXMLNode *node = CPLCreateXMLNode(parent, CXT_Element, pszName);
510 680 : XMLSetAttributeVal(node, "x", sz.x, frmt);
511 680 : XMLSetAttributeVal(node, "y", sz.y, frmt);
512 680 : if (sz.z != 1)
513 0 : XMLSetAttributeVal(node, "z", sz.z, frmt);
514 680 : XMLSetAttributeVal(node, "c", sz.c, frmt);
515 680 : return node;
516 : }
517 :
518 : //
519 : // Prints a vector of doubles into a string and sets that string as the value of
520 : // an XML attribute If all values are the same, it only prints one
521 : //
522 129 : void XMLSetAttributeVal(CPLXMLNode *parent, const char *pszName,
523 : std::vector<double> const &values)
524 : {
525 129 : if (values.empty())
526 59 : return;
527 :
528 140 : CPLString value;
529 70 : double val = values[0];
530 70 : int single_val = true;
531 140 : for (int i = 0; i < int(values.size()); i++)
532 : {
533 70 : if (val != values[i])
534 0 : single_val = false;
535 70 : value.append(PrintDouble(values[i]) + " ");
536 : }
537 70 : value.pop_back(); // Cut the last space
538 70 : if (single_val)
539 70 : value = PrintDouble(values[0]);
540 70 : CPLCreateXMLNode(parent, CXT_Attribute, pszName);
541 70 : CPLSetXMLValue(parent, pszName, value);
542 : }
543 :
544 : /**
545 : *\brief Verify or make a file that big
546 : *
547 : * @return true if size is OK or if extend succeeded
548 : */
549 :
550 188 : int CheckFileSize(const char *fname, GIntBig sz, GDALAccess eAccess)
551 : {
552 :
553 : VSIStatBufL statb;
554 188 : if (VSIStatL(fname, &statb))
555 0 : return false;
556 188 : if (statb.st_size >= sz)
557 84 : return true;
558 :
559 : // Don't change anything unless updating
560 104 : if (eAccess != GA_Update)
561 0 : return false;
562 :
563 : // There is no ftruncate in VSI, only truncate()
564 104 : VSILFILE *ifp = VSIFOpenL(fname, "r+b");
565 104 : if (ifp == nullptr)
566 0 : return false;
567 :
568 104 : int ret = VSIFTruncateL(ifp, sz);
569 104 : VSIFCloseL(ifp);
570 104 : return !ret;
571 : }
572 :
573 : NAMESPACE_MRF_END
574 :
575 : /************************************************************************/
576 : /* GDALRegister_MRF() */
577 : /************************************************************************/
578 :
579 : USING_NAMESPACE_MRF
580 :
581 2038 : void GDALRegister_MRF()
582 : {
583 2038 : if (GDALGetDriverByName(DRIVER_NAME) != nullptr)
584 283 : return;
585 :
586 1755 : GDALDriver *driver = new GDALDriver();
587 1755 : MRFDriverSetCommonMetadata(driver);
588 :
589 1755 : driver->SetMetadataItem(
590 : GDAL_DMD_CREATIONOPTIONLIST,
591 : "<CreationOptionList>"
592 : " <Option name='COMPRESS' type='string-select' "
593 : #ifdef HAVE_PNG
594 : "default='PNG' description='PPNG = Palette PNG; DEFLATE = zlib '>"
595 : #else
596 : "default='NONE' description='DEFLATE = zlib '>"
597 : #endif
598 : #ifdef HAVE_JPEG
599 : " <Value>JPEG</Value>"
600 : #endif
601 : #ifdef HAVE_PNG
602 : " <Value>PNG</Value>"
603 : " <Value>PPNG</Value>"
604 : #endif
605 : #if defined(HAVE_JPEG) && defined(HAVE_PNG)
606 : " <Value>JPNG</Value>"
607 : #endif
608 : " <Value>TIF</Value>"
609 : " <Value>DEFLATE</Value>"
610 : " <Value>NONE</Value>"
611 : #if defined(LERC)
612 : " <Value>LERC</Value>"
613 : #endif
614 : #if defined(ZSTD_SUPPORT)
615 : " <Value>ZSTD</Value>"
616 : #endif
617 : #if defined(QB3_SUPPORT)
618 : " <Value>QB3</Value>"
619 : #endif
620 : " </Option>"
621 : " <Option name='INTERLEAVE' type='string-select' default='PIXEL'>"
622 : " <Value>PIXEL</Value>"
623 : " <Value>BAND</Value>"
624 : " </Option>\n"
625 : " <Option name='ZSIZE' type='int' description='Third dimension size' "
626 : "default='1'/>"
627 : " <Option name='QUALITY' type='int' description='Compression "
628 : "dependent control value, for JPEG best=99, bad=0, default=85'/>\n"
629 : " <Option name='BLOCKSIZE' type='int' description='Block size, both "
630 : "x and y, default 512'/>\n"
631 : " <Option name='BLOCKXSIZE' type='int' description='Block x size, "
632 : "default=512'/>\n"
633 : " <Option name='BLOCKYSIZE' type='int' description='Block y size, "
634 : "default=512'/>\n"
635 : " <Option name='NETBYTEORDER' type='boolean' "
636 : "description='Force endian for certain compress options, default is "
637 : "host order'/>\n"
638 : " <Option name='CACHEDSOURCE' type='string' "
639 : "description='The source raster, if this is a cache'/>\n"
640 : " <Option name='UNIFORM_SCALE' type='int' description='Scale of "
641 : "overlays in MRF, usually 2'/>\n"
642 : " <Option name='NOCOPY' type='boolean' description='Leave created "
643 : "MRF empty, default=no'/>\n"
644 : " <Option name='DATANAME' type='string' description='Data file "
645 : "name'/>\n"
646 : " <Option name='INDEXNAME' type='string' description='Index file "
647 : "name'/>\n"
648 : " <Option name='SPACING' type='int' "
649 : "description='Leave this many unused bytes before each tile, "
650 : "default=0'/>\n"
651 : " <Option name='PHOTOMETRIC' type='string-select' default='DEFAULT' "
652 : "description='Band interpretation, may affect block encoding'>\n"
653 : " <Value>MULTISPECTRAL</Value>"
654 : " <Value>RGB</Value>"
655 : " <Value>YCC</Value>"
656 : " </Option>\n"
657 : " <Option name='OPTIONS' type='string' description='\n"
658 : " Compression dependent parameters, space separated:\n"
659 : #if defined(ZSTD_SUPPORT)
660 : " ZSTD - boolean, enable libzstd as final stage, preferred over "
661 : "DEFLATE\n"
662 : #endif
663 : " DEFLATE - boolean, enable zlib as final stage\n"
664 : " GZ - boolean, for DEFLATE enable gzip headers instead of zlib "
665 : "ones when using zlib\n"
666 : " RAWZ - boolean, for DEFLATE disable all zlib headers\n"
667 : " Z_STRATEGY - Z_HUFFMAN_ONLY | Z_FILTERED | Z_RLE | Z_FIXED: "
668 : "restricts DEFLATE and PNG strategy\n"
669 : #if defined(LERC)
670 : " LERC_PREC - numeric, set LERC precision, defaults to 0.5 for "
671 : "int and 0.001 for float\n"
672 : " V1 - boolean, use LERC V1 (older) format\n"
673 : " L2_VER - numeric, encode specific version of Lerc, default is "
674 : "library default\n"
675 : " except for single band or INTERLEAVE=BAND, when it "
676 : "defaults to 2\n"
677 : #endif
678 : " OPTIMIZE - boolean, for JPEG, enables Huffman table "
679 : "optimization\n"
680 : #if defined(BRUNSLI)
681 : " JFIF - boolean, for JPEG, disable brunsli encoding\n"
682 : #endif
683 : "'/>"
684 1755 : "</CreationOptionList>\n");
685 :
686 1755 : driver->pfnOpen = MRFDataset::Open;
687 1755 : driver->pfnCreateCopy = MRFDataset::CreateCopy;
688 1755 : driver->pfnCreate = MRFDataset::Create;
689 1755 : driver->pfnDelete = MRFDataset::Delete;
690 1755 : GetGDALDriverManager()->RegisterDriver(driver);
691 : }
|