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