Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Helper code to implement overview and mask support for many
5 : * drivers with no inherent format support.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2000, 2007, Frank Warmerdam
10 : * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "cpl_port.h"
32 : #include "cpl_multiproc.h"
33 : #include "gdal_priv.h"
34 :
35 : #include <cstdlib>
36 : #include <cstring>
37 :
38 : #include <algorithm>
39 : #include <set>
40 : #include <string>
41 : #include <vector>
42 :
43 : #include "cpl_conv.h"
44 : #include "cpl_error.h"
45 : #include "cpl_progress.h"
46 : #include "cpl_string.h"
47 : #include "cpl_vsi.h"
48 : #include "gdal.h"
49 :
50 : //! @cond Doxygen_Suppress
51 : /************************************************************************/
52 : /* GDALDefaultOverviews() */
53 : /************************************************************************/
54 :
55 115500 : GDALDefaultOverviews::GDALDefaultOverviews()
56 : : poDS(nullptr), poODS(nullptr), bOvrIsAux(false), bCheckedForMask(false),
57 : bOwnMaskDS(false), poMaskDS(nullptr), poBaseDS(nullptr),
58 : bCheckedForOverviews(FALSE), pszInitName(nullptr), bInitNameIsOVR(false),
59 115500 : papszInitSiblingFiles(nullptr)
60 : {
61 115466 : }
62 :
63 : /************************************************************************/
64 : /* ~GDALDefaultOverviews() */
65 : /************************************************************************/
66 :
67 115487 : GDALDefaultOverviews::~GDALDefaultOverviews()
68 :
69 : {
70 115489 : CPLFree(pszInitName);
71 115490 : CSLDestroy(papszInitSiblingFiles);
72 :
73 115489 : CloseDependentDatasets();
74 115488 : }
75 :
76 : /************************************************************************/
77 : /* CloseDependentDatasets() */
78 : /************************************************************************/
79 :
80 133259 : int GDALDefaultOverviews::CloseDependentDatasets()
81 : {
82 133259 : bool bHasDroppedRef = false;
83 133259 : if (poODS != nullptr)
84 : {
85 369 : bHasDroppedRef = true;
86 369 : poODS->FlushCache(true);
87 369 : GDALClose(poODS);
88 367 : poODS = nullptr;
89 : }
90 :
91 133257 : if (poMaskDS != nullptr)
92 : {
93 57 : if (bOwnMaskDS)
94 : {
95 53 : bHasDroppedRef = true;
96 53 : poMaskDS->FlushCache(true);
97 53 : GDALClose(poMaskDS);
98 : }
99 57 : poMaskDS = nullptr;
100 : }
101 :
102 133257 : return bHasDroppedRef;
103 : }
104 :
105 : /************************************************************************/
106 : /* IsInitialized() */
107 : /* */
108 : /* Returns TRUE if we are initialized. */
109 : /************************************************************************/
110 :
111 665140 : int GDALDefaultOverviews::IsInitialized()
112 :
113 : {
114 665140 : OverviewScan();
115 665140 : return poDS != nullptr;
116 : }
117 :
118 : /************************************************************************/
119 : /* Initialize() */
120 : /************************************************************************/
121 :
122 39094 : void GDALDefaultOverviews::Initialize(GDALDataset *poDSIn,
123 : const char *pszBasename,
124 : char **papszSiblingFiles, int bNameIsOVR)
125 :
126 : {
127 39094 : poDS = poDSIn;
128 :
129 : /* -------------------------------------------------------------------- */
130 : /* If we were already initialized, destroy the old overview */
131 : /* file handle. */
132 : /* -------------------------------------------------------------------- */
133 39094 : if (poODS != nullptr)
134 : {
135 0 : GDALClose(poODS);
136 0 : poODS = nullptr;
137 :
138 0 : CPLDebug("GDAL", "GDALDefaultOverviews::Initialize() called twice - "
139 : "this is odd and perhaps dangerous!");
140 : }
141 :
142 : /* -------------------------------------------------------------------- */
143 : /* Store the initialization information for later use in */
144 : /* OverviewScan() */
145 : /* -------------------------------------------------------------------- */
146 39094 : bCheckedForOverviews = FALSE;
147 :
148 39094 : CPLFree(pszInitName);
149 39080 : pszInitName = nullptr;
150 39080 : if (pszBasename != nullptr)
151 38930 : pszInitName = CPLStrdup(pszBasename);
152 39104 : bInitNameIsOVR = CPL_TO_BOOL(bNameIsOVR);
153 :
154 39090 : CSLDestroy(papszInitSiblingFiles);
155 39087 : papszInitSiblingFiles = nullptr;
156 39087 : if (papszSiblingFiles != nullptr)
157 12336 : papszInitSiblingFiles = CSLDuplicate(papszSiblingFiles);
158 39087 : }
159 :
160 : /************************************************************************/
161 : /* TransferSiblingFiles() */
162 : /* */
163 : /* Contrary to Initialize(), this sets papszInitSiblingFiles but */
164 : /* without duplicating the passed list. Which must be */
165 : /* "de-allocatable" with CSLDestroy() */
166 : /************************************************************************/
167 :
168 10583 : void GDALDefaultOverviews::TransferSiblingFiles(char **papszSiblingFiles)
169 : {
170 10583 : CSLDestroy(papszInitSiblingFiles);
171 10583 : papszInitSiblingFiles = papszSiblingFiles;
172 10583 : }
173 :
174 : namespace
175 : {
176 : // Prevent infinite recursion.
177 : struct AntiRecursionStructDefaultOvr
178 : {
179 : int nRecLevel = 0;
180 : std::set<CPLString> oSetFiles{};
181 : };
182 : } // namespace
183 :
184 343 : static void FreeAntiRecursionDefaultOvr(void *pData)
185 : {
186 343 : delete static_cast<AntiRecursionStructDefaultOvr *>(pData);
187 343 : }
188 :
189 10356 : static AntiRecursionStructDefaultOvr &GetAntiRecursionDefaultOvr()
190 : {
191 10356 : static AntiRecursionStructDefaultOvr dummy;
192 10356 : int bMemoryErrorOccurred = false;
193 : void *pData =
194 10356 : CPLGetTLSEx(CTLS_GDALDEFAULTOVR_ANTIREC, &bMemoryErrorOccurred);
195 10356 : if (bMemoryErrorOccurred)
196 : {
197 0 : return dummy;
198 : }
199 10356 : if (pData == nullptr)
200 : {
201 405 : auto pAntiRecursion = new AntiRecursionStructDefaultOvr();
202 405 : CPLSetTLSWithFreeFuncEx(CTLS_GDALDEFAULTOVR_ANTIREC, pAntiRecursion,
203 : FreeAntiRecursionDefaultOvr,
204 : &bMemoryErrorOccurred);
205 405 : if (bMemoryErrorOccurred)
206 : {
207 0 : delete pAntiRecursion;
208 0 : return dummy;
209 : }
210 405 : return *pAntiRecursion;
211 : }
212 9951 : return *static_cast<AntiRecursionStructDefaultOvr *>(pData);
213 : }
214 :
215 : /************************************************************************/
216 : /* OverviewScan() */
217 : /* */
218 : /* This is called to scan for overview files when a first */
219 : /* request is made with regard to overviews. It uses the */
220 : /* pszInitName, bInitNameIsOVR and papszInitSiblingFiles */
221 : /* information that was stored at Initialization() time. */
222 : /************************************************************************/
223 :
224 665140 : void GDALDefaultOverviews::OverviewScan()
225 :
226 : {
227 665140 : if (bCheckedForOverviews || poDS == nullptr)
228 654784 : return;
229 :
230 10356 : bCheckedForOverviews = true;
231 10356 : if (pszInitName == nullptr)
232 12 : pszInitName = CPLStrdup(poDS->GetDescription());
233 :
234 10356 : AntiRecursionStructDefaultOvr &antiRec = GetAntiRecursionDefaultOvr();
235 : // 32 should be enough to handle a .ovr.ovr.ovr...
236 10356 : if (antiRec.nRecLevel == 32)
237 0 : return;
238 10356 : if (antiRec.oSetFiles.find(pszInitName) != antiRec.oSetFiles.end())
239 0 : return;
240 10356 : antiRec.oSetFiles.insert(pszInitName);
241 10356 : ++antiRec.nRecLevel;
242 :
243 10356 : CPLDebug("GDAL", "GDALDefaultOverviews::OverviewScan()");
244 :
245 : /* -------------------------------------------------------------------- */
246 : /* Open overview dataset if it exists. */
247 : /* -------------------------------------------------------------------- */
248 20540 : if (!EQUAL(pszInitName, ":::VIRTUAL:::") &&
249 10184 : GDALCanFileAcceptSidecarFile(pszInitName))
250 : {
251 10182 : if (bInitNameIsOVR)
252 0 : osOvrFilename = pszInitName;
253 : else
254 10182 : osOvrFilename.Printf("%s.ovr", pszInitName);
255 :
256 20364 : std::vector<char> achOvrFilename;
257 10182 : achOvrFilename.resize(osOvrFilename.size() + 1);
258 10182 : memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
259 10182 : osOvrFilename.size() + 1);
260 10182 : bool bExists = CPL_TO_BOOL(
261 10182 : CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
262 10182 : osOvrFilename = &achOvrFilename[0];
263 :
264 : #if !defined(_WIN32)
265 10182 : if (!bInitNameIsOVR && !bExists && !papszInitSiblingFiles)
266 : {
267 2814 : osOvrFilename.Printf("%s.OVR", pszInitName);
268 2814 : memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
269 2814 : osOvrFilename.size() + 1);
270 2814 : bExists = CPL_TO_BOOL(
271 2814 : CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
272 2814 : osOvrFilename = &achOvrFilename[0];
273 2814 : if (!bExists)
274 2814 : osOvrFilename.Printf("%s.ovr", pszInitName);
275 : }
276 : #endif
277 :
278 10182 : if (bExists)
279 : {
280 185 : poODS = GDALDataset::Open(
281 : osOvrFilename,
282 : GDAL_OF_RASTER |
283 185 : (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
284 185 : nullptr, nullptr, papszInitSiblingFiles);
285 : }
286 : }
287 :
288 : /* -------------------------------------------------------------------- */
289 : /* We didn't find that, so try and find a corresponding aux */
290 : /* file. Check that we are the dependent file of the aux */
291 : /* file. */
292 : /* */
293 : /* We only use the .aux file for overviews if they already have */
294 : /* overviews existing, or if USE_RRD is set true. */
295 : /* -------------------------------------------------------------------- */
296 20356 : if (!poODS && !EQUAL(pszInitName, ":::VIRTUAL:::") &&
297 10000 : GDALCanFileAcceptSidecarFile(pszInitName))
298 : {
299 9998 : bool bTryFindAssociatedAuxFile = true;
300 9998 : if (papszInitSiblingFiles)
301 : {
302 14368 : CPLString osAuxFilename = CPLResetExtension(pszInitName, "aux");
303 7184 : int iSibling = CSLFindString(papszInitSiblingFiles,
304 : CPLGetFilename(osAuxFilename));
305 7184 : if (iSibling < 0)
306 : {
307 7180 : osAuxFilename = pszInitName;
308 7180 : osAuxFilename += ".aux";
309 7180 : iSibling = CSLFindString(papszInitSiblingFiles,
310 : CPLGetFilename(osAuxFilename));
311 7180 : if (iSibling < 0)
312 7180 : bTryFindAssociatedAuxFile = false;
313 : }
314 : }
315 :
316 9998 : if (bTryFindAssociatedAuxFile)
317 : {
318 2818 : poODS =
319 2818 : GDALFindAssociatedAuxFile(pszInitName, poDS->GetAccess(), poDS);
320 : }
321 :
322 9998 : if (poODS)
323 : {
324 : const bool bUseRRD =
325 8 : CPLTestBool(CPLGetConfigOption("USE_RRD", "NO"));
326 :
327 8 : bOvrIsAux = true;
328 8 : if (GetOverviewCount(1) == 0 && !bUseRRD)
329 : {
330 1 : bOvrIsAux = false;
331 1 : GDALClose(poODS);
332 1 : poODS = nullptr;
333 : }
334 : else
335 : {
336 7 : osOvrFilename = poODS->GetDescription();
337 : }
338 : }
339 : }
340 :
341 : /* -------------------------------------------------------------------- */
342 : /* If we still don't have an overview, check to see if we have */
343 : /* overview metadata referencing a remote (i.e. proxy) or local */
344 : /* subdataset overview dataset. */
345 : /* -------------------------------------------------------------------- */
346 10356 : if (poODS == nullptr)
347 : {
348 : const char *pszProxyOvrFilename =
349 10165 : poDS->GetMetadataItem("OVERVIEW_FILE", "OVERVIEWS");
350 :
351 10165 : if (pszProxyOvrFilename != nullptr)
352 : {
353 29 : if (STARTS_WITH_CI(pszProxyOvrFilename, ":::BASE:::"))
354 : {
355 0 : const CPLString osPath = CPLGetPath(poDS->GetDescription());
356 :
357 : osOvrFilename =
358 0 : CPLFormFilename(osPath, pszProxyOvrFilename + 10, nullptr);
359 : }
360 : else
361 : {
362 29 : osOvrFilename = pszProxyOvrFilename;
363 : }
364 :
365 29 : CPLPushErrorHandler(CPLQuietErrorHandler);
366 29 : poODS = GDALDataset::Open(
367 : osOvrFilename,
368 : GDAL_OF_RASTER |
369 29 : (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0));
370 29 : CPLPopErrorHandler();
371 : }
372 : }
373 :
374 : /* -------------------------------------------------------------------- */
375 : /* If we have an overview dataset, then mark all the overviews */
376 : /* with the base dataset Used later for finding overviews */
377 : /* masks. Uggg. */
378 : /* -------------------------------------------------------------------- */
379 10356 : if (poODS)
380 : {
381 207 : const int nOverviewCount = GetOverviewCount(1);
382 :
383 498 : for (int iOver = 0; iOver < nOverviewCount; iOver++)
384 : {
385 291 : GDALRasterBand *const poBand = GetOverview(1, iOver);
386 : GDALDataset *const poOverDS =
387 291 : poBand != nullptr ? poBand->GetDataset() : nullptr;
388 :
389 291 : if (poOverDS != nullptr)
390 : {
391 277 : poOverDS->oOvManager.poBaseDS = poDS;
392 277 : poOverDS->oOvManager.poDS = poOverDS;
393 : }
394 : }
395 : }
396 :
397 : // Undo anti recursion protection
398 10356 : antiRec.oSetFiles.erase(pszInitName);
399 10356 : --antiRec.nRecLevel;
400 : }
401 :
402 : /************************************************************************/
403 : /* GetOverviewCount() */
404 : /************************************************************************/
405 :
406 655000 : int GDALDefaultOverviews::GetOverviewCount(int nBand)
407 :
408 : {
409 655000 : if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
410 654047 : return 0;
411 :
412 953 : GDALRasterBand *poBand = poODS->GetRasterBand(nBand);
413 953 : if (poBand == nullptr)
414 0 : return 0;
415 :
416 953 : if (bOvrIsAux)
417 74 : return poBand->GetOverviewCount();
418 :
419 879 : return poBand->GetOverviewCount() + 1;
420 : }
421 :
422 : /************************************************************************/
423 : /* GetOverview() */
424 : /************************************************************************/
425 :
426 1291 : GDALRasterBand *GDALDefaultOverviews::GetOverview(int nBand, int iOverview)
427 :
428 : {
429 1291 : if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
430 272 : return nullptr;
431 :
432 1019 : GDALRasterBand *const poBand = poODS->GetRasterBand(nBand);
433 1019 : if (poBand == nullptr)
434 0 : return nullptr;
435 :
436 1019 : if (bOvrIsAux)
437 63 : return poBand->GetOverview(iOverview);
438 :
439 : // TIFF case, base is overview 0.
440 956 : if (iOverview == 0)
441 717 : return poBand;
442 :
443 239 : if (iOverview - 1 >= poBand->GetOverviewCount())
444 0 : return nullptr;
445 :
446 239 : return poBand->GetOverview(iOverview - 1);
447 : }
448 :
449 : /************************************************************************/
450 : /* GDALOvLevelAdjust() */
451 : /* */
452 : /* Some overview levels cannot be achieved closely enough to be */
453 : /* recognised as the desired overview level. This function */
454 : /* will adjust an overview level to one that is achievable on */
455 : /* the given raster size. */
456 : /* */
457 : /* For instance a 1200x1200 image on which a 256 level overview */
458 : /* is request will end up generating a 5x5 overview. However, */
459 : /* this will appear to the system be a level 240 overview. */
460 : /* This function will adjust 256 to 240 based on knowledge of */
461 : /* the image size. */
462 : /************************************************************************/
463 :
464 0 : int GDALOvLevelAdjust(int nOvLevel, int nXSize)
465 :
466 : {
467 0 : int nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
468 :
469 0 : return static_cast<int>(0.5 + nXSize / static_cast<double>(nOXSize));
470 : }
471 :
472 488 : int GDALOvLevelAdjust2(int nOvLevel, int nXSize, int nYSize)
473 :
474 : {
475 : // Select the larger dimension to have increased accuracy, but
476 : // with a slight preference to x even if (a bit) smaller than y
477 : // in an attempt to behave closer as previous behavior.
478 488 : if (nXSize >= nYSize / 2 && !(nXSize < nYSize && nXSize < nOvLevel))
479 : {
480 391 : const int nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
481 :
482 391 : return static_cast<int>(0.5 + nXSize / static_cast<double>(nOXSize));
483 : }
484 :
485 97 : const int nOYSize = (nYSize + nOvLevel - 1) / nOvLevel;
486 :
487 97 : return static_cast<int>(0.5 + nYSize / static_cast<double>(nOYSize));
488 : }
489 :
490 : /************************************************************************/
491 : /* GDALComputeOvFactor() */
492 : /************************************************************************/
493 :
494 1623 : int GDALComputeOvFactor(int nOvrXSize, int nRasterXSize, int nOvrYSize,
495 : int nRasterYSize)
496 : {
497 : // Select the larger dimension to have increased accuracy, but
498 : // with a slight preference to x even if (a bit) smaller than y
499 : // in an attempt to behave closer as previous behavior.
500 1623 : if (nRasterXSize != 1 && nRasterXSize >= nRasterYSize / 2)
501 : {
502 1511 : return static_cast<int>(0.5 +
503 1511 : nRasterXSize / static_cast<double>(nOvrXSize));
504 : }
505 :
506 112 : return static_cast<int>(0.5 +
507 112 : nRasterYSize / static_cast<double>(nOvrYSize));
508 : }
509 :
510 : /************************************************************************/
511 : /* CleanOverviews() */
512 : /* */
513 : /* Remove all existing overviews. */
514 : /************************************************************************/
515 :
516 7 : CPLErr GDALDefaultOverviews::CleanOverviews()
517 :
518 : {
519 : // Anything to do?
520 7 : if (poODS == nullptr)
521 1 : return CE_None;
522 :
523 : // Delete the overview file(s).
524 6 : GDALDriver *poOvrDriver = poODS->GetDriver();
525 6 : GDALClose(poODS);
526 6 : poODS = nullptr;
527 :
528 : CPLErr eErr =
529 6 : poOvrDriver != nullptr ? poOvrDriver->Delete(osOvrFilename) : CE_None;
530 :
531 : // Reset the saved overview filename.
532 6 : if (!EQUAL(poDS->GetDescription(), ":::VIRTUAL:::"))
533 : {
534 6 : const bool bUseRRD = CPLTestBool(CPLGetConfigOption("USE_RRD", "NO"));
535 :
536 6 : if (bUseRRD)
537 0 : osOvrFilename = CPLResetExtension(poDS->GetDescription(), "aux");
538 : else
539 6 : osOvrFilename.Printf("%s.ovr", poDS->GetDescription());
540 : }
541 : else
542 : {
543 0 : osOvrFilename = "";
544 : }
545 :
546 6 : if (HaveMaskFile() && poMaskDS)
547 : {
548 1 : const CPLErr eErr2 = poMaskDS->BuildOverviews(
549 : nullptr, 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr);
550 1 : if (eErr2 != CE_None)
551 0 : return eErr2;
552 : }
553 :
554 6 : return eErr;
555 : }
556 :
557 : /************************************************************************/
558 : /* BuildOverviewsSubDataset() */
559 : /************************************************************************/
560 :
561 7 : CPLErr GDALDefaultOverviews::BuildOverviewsSubDataset(
562 : const char *pszPhysicalFile, const char *pszResampling, int nOverviews,
563 : const int *panOverviewList, int nBands, const int *panBandList,
564 : GDALProgressFunc pfnProgress, void *pProgressData,
565 : CSLConstList papszOptions)
566 :
567 : {
568 7 : if (osOvrFilename.length() == 0 && nOverviews > 0)
569 : {
570 : VSIStatBufL sStatBuf;
571 :
572 5 : int iSequence = 0; // Used after for.
573 5 : for (iSequence = 0; iSequence < 100; iSequence++)
574 : {
575 5 : osOvrFilename.Printf("%s_%d.ovr", pszPhysicalFile, iSequence);
576 5 : if (VSIStatExL(osOvrFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) != 0)
577 : {
578 10 : CPLString osAdjustedOvrFilename;
579 :
580 5 : if (poDS->GetMOFlags() & GMO_PAM_CLASS)
581 : {
582 : osAdjustedOvrFilename.Printf(
583 : ":::BASE:::%s_%d.ovr", CPLGetFilename(pszPhysicalFile),
584 5 : iSequence);
585 : }
586 : else
587 : {
588 0 : osAdjustedOvrFilename = osOvrFilename;
589 : }
590 :
591 5 : poDS->SetMetadataItem("OVERVIEW_FILE", osAdjustedOvrFilename,
592 5 : "OVERVIEWS");
593 5 : break;
594 : }
595 : }
596 :
597 5 : if (iSequence == 100)
598 0 : osOvrFilename = "";
599 : }
600 :
601 7 : return BuildOverviews(nullptr, pszResampling, nOverviews, panOverviewList,
602 : nBands, panBandList, pfnProgress, pProgressData,
603 7 : papszOptions);
604 : }
605 :
606 : /************************************************************************/
607 : /* GetOptionValue() */
608 : /************************************************************************/
609 :
610 179 : static const char *GetOptionValue(CSLConstList papszOptions,
611 : const char *pszOptionKey,
612 : const char *pszConfigOptionKey)
613 : {
614 : const char *pszVal =
615 179 : pszOptionKey ? CSLFetchNameValue(papszOptions, pszOptionKey) : nullptr;
616 179 : if (pszVal)
617 : {
618 0 : return pszVal;
619 : }
620 179 : pszVal = CSLFetchNameValue(papszOptions, pszConfigOptionKey);
621 179 : if (pszVal)
622 : {
623 2 : return pszVal;
624 : }
625 177 : pszVal = CPLGetConfigOption(pszConfigOptionKey, nullptr);
626 177 : return pszVal;
627 : }
628 :
629 : /************************************************************************/
630 : /* BuildOverviews() */
631 : /************************************************************************/
632 :
633 190 : CPLErr GDALDefaultOverviews::BuildOverviews(
634 : const char *pszBasename, const char *pszResampling, int nOverviews,
635 : const int *panOverviewList, int nBands, const int *panBandList,
636 : GDALProgressFunc pfnProgress, void *pProgressData,
637 : CSLConstList papszOptions)
638 :
639 : {
640 190 : if (pfnProgress == nullptr)
641 0 : pfnProgress = GDALDummyProgress;
642 :
643 190 : if (nOverviews == 0)
644 6 : return CleanOverviews();
645 :
646 : /* -------------------------------------------------------------------- */
647 : /* If we don't already have an overview file, we need to decide */
648 : /* what format to use. */
649 : /* -------------------------------------------------------------------- */
650 184 : if (poODS == nullptr)
651 : {
652 : const char *pszUseRRD =
653 171 : GetOptionValue(papszOptions, nullptr, "USE_RRD");
654 171 : bOvrIsAux = pszUseRRD && CPLTestBool(pszUseRRD);
655 171 : if (bOvrIsAux)
656 : {
657 4 : osOvrFilename = CPLResetExtension(poDS->GetDescription(), "aux");
658 :
659 : VSIStatBufL sStatBuf;
660 4 : if (VSIStatExL(osOvrFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0)
661 0 : osOvrFilename.Printf("%s.aux", poDS->GetDescription());
662 : }
663 : }
664 : /* -------------------------------------------------------------------- */
665 : /* If we already have the overviews open, but they are */
666 : /* read-only, then try and reopen them read-write. */
667 : /* -------------------------------------------------------------------- */
668 13 : else if (poODS->GetAccess() == GA_ReadOnly)
669 : {
670 11 : GDALClose(poODS);
671 11 : poODS =
672 11 : GDALDataset::Open(osOvrFilename, GDAL_OF_RASTER | GDAL_OF_UPDATE);
673 11 : if (poODS == nullptr)
674 0 : return CE_Failure;
675 : }
676 :
677 : /* -------------------------------------------------------------------- */
678 : /* Our TIFF overview support currently only works safely if all */
679 : /* bands are handled at the same time. */
680 : /* -------------------------------------------------------------------- */
681 184 : if (!bOvrIsAux && nBands != poDS->GetRasterCount())
682 : {
683 0 : CPLError(CE_Failure, CPLE_NotSupported,
684 : "Generation of overviews in external TIFF currently only "
685 : "supported when operating on all bands. "
686 : "Operation failed.");
687 0 : return CE_Failure;
688 : }
689 :
690 : /* -------------------------------------------------------------------- */
691 : /* If a basename is provided, use it to override the internal */
692 : /* overview filename. */
693 : /* -------------------------------------------------------------------- */
694 184 : if (pszBasename == nullptr && osOvrFilename.length() == 0)
695 0 : pszBasename = poDS->GetDescription();
696 :
697 184 : if (pszBasename != nullptr)
698 : {
699 1 : if (bOvrIsAux)
700 0 : osOvrFilename.Printf("%s.aux", pszBasename);
701 : else
702 1 : osOvrFilename.Printf("%s.ovr", pszBasename);
703 : }
704 :
705 : /* -------------------------------------------------------------------- */
706 : /* Establish which of the overview levels we already have, and */
707 : /* which are new. We assume that band 1 of the file is */
708 : /* representative. */
709 : /* -------------------------------------------------------------------- */
710 184 : GDALRasterBand *poBand = poDS->GetRasterBand(1);
711 :
712 184 : int nNewOverviews = 0;
713 : int *panNewOverviewList =
714 184 : static_cast<int *>(CPLCalloc(sizeof(int), nOverviews));
715 184 : double dfAreaNewOverviews = 0;
716 184 : double dfAreaRefreshedOverviews = 0;
717 368 : std::vector<bool> abValidLevel(nOverviews, true);
718 184 : std::vector<bool> abRequireRefresh(nOverviews, false);
719 184 : bool bFoundSinglePixelOverview = false;
720 456 : for (int i = 0; i < nOverviews && poBand != nullptr; i++)
721 : {
722 : // If we already have a 1x1 overview and this new one would result
723 : // in it too, then don't create it.
724 304 : if (bFoundSinglePixelOverview &&
725 16 : (poBand->GetXSize() + panOverviewList[i] - 1) /
726 16 : panOverviewList[i] ==
727 288 : 1 &&
728 16 : (poBand->GetYSize() + panOverviewList[i] - 1) /
729 16 : panOverviewList[i] ==
730 : 1)
731 : {
732 16 : abValidLevel[i] = false;
733 16 : continue;
734 : }
735 :
736 277 : for (int j = 0; j < poBand->GetOverviewCount(); j++)
737 : {
738 38 : GDALRasterBand *poOverview = poBand->GetOverview(j);
739 38 : if (poOverview == nullptr)
740 0 : continue;
741 :
742 : int nOvFactor =
743 38 : GDALComputeOvFactor(poOverview->GetXSize(), poBand->GetXSize(),
744 : poOverview->GetYSize(), poBand->GetYSize());
745 :
746 62 : if (nOvFactor == panOverviewList[i] ||
747 24 : nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
748 : poBand->GetXSize(),
749 : poBand->GetYSize()))
750 : {
751 : const auto osNewResampling =
752 34 : GDALGetNormalizedOvrResampling(pszResampling);
753 : const char *pszExistingResampling =
754 17 : poOverview->GetMetadataItem("RESAMPLING");
755 28 : if (pszExistingResampling &&
756 11 : pszExistingResampling != osNewResampling)
757 : {
758 3 : if (auto l_poODS = poOverview->GetDataset())
759 : {
760 3 : if (auto poDriver = l_poODS->GetDriver())
761 : {
762 1 : if (EQUAL(poDriver->GetDescription(), "GTiff"))
763 : {
764 1 : poOverview->SetMetadataItem(
765 1 : "RESAMPLING", osNewResampling.c_str());
766 : }
767 : }
768 : }
769 : }
770 :
771 17 : abRequireRefresh[i] = true;
772 17 : break;
773 : }
774 : }
775 :
776 256 : if (abValidLevel[i])
777 : {
778 256 : const double dfArea =
779 : 1.0 /
780 256 : (static_cast<double>(panOverviewList[i]) * panOverviewList[i]);
781 256 : dfAreaRefreshedOverviews += dfArea;
782 256 : if (!abRequireRefresh[i])
783 : {
784 239 : dfAreaNewOverviews += dfArea;
785 239 : panNewOverviewList[nNewOverviews++] = panOverviewList[i];
786 : }
787 :
788 256 : if ((poBand->GetXSize() + panOverviewList[i] - 1) /
789 256 : panOverviewList[i] ==
790 275 : 1 &&
791 19 : (poBand->GetYSize() + panOverviewList[i] - 1) /
792 19 : panOverviewList[i] ==
793 : 1)
794 : {
795 17 : bFoundSinglePixelOverview = true;
796 : }
797 : }
798 : }
799 :
800 : /* -------------------------------------------------------------------- */
801 : /* Build band list. */
802 : /* -------------------------------------------------------------------- */
803 : GDALRasterBand **pahBands = static_cast<GDALRasterBand **>(
804 184 : CPLCalloc(sizeof(GDALRasterBand *), nBands));
805 478 : for (int i = 0; i < nBands; i++)
806 294 : pahBands[i] = poDS->GetRasterBand(panBandList[i]);
807 :
808 : /* -------------------------------------------------------------------- */
809 : /* Build new overviews - Imagine. Keep existing file open if */
810 : /* we have it. But mark all overviews as in need of */
811 : /* regeneration, since HFAAuxBuildOverviews() doesn't actually */
812 : /* produce the imagery. */
813 : /* -------------------------------------------------------------------- */
814 :
815 184 : CPLErr eErr = CE_None;
816 :
817 184 : void *pScaledOverviewWithoutMask = GDALCreateScaledProgress(
818 184 : 0, (HaveMaskFile() && poMaskDS) ? double(nBands) / (nBands + 1) : 1,
819 : pfnProgress, pProgressData);
820 :
821 184 : void *pScaledProgress = GDALCreateScaledProgress(
822 : 0, dfAreaNewOverviews / dfAreaRefreshedOverviews, GDALScaledProgress,
823 : pScaledOverviewWithoutMask);
824 184 : if (bOvrIsAux)
825 : {
826 8 : if (nNewOverviews == 0)
827 : {
828 : /* if we call HFAAuxBuildOverviews() with nNewOverviews == 0 */
829 : /* because that there's no new, this will wipe existing */
830 : /* overviews (#4831) */
831 : // eErr = CE_None;
832 : }
833 : else
834 : {
835 5 : eErr = HFAAuxBuildOverviews(
836 : osOvrFilename, poDS, &poODS, nBands, panBandList, nNewOverviews,
837 : panNewOverviewList, pszResampling, GDALScaledProgress,
838 : pScaledProgress, papszOptions);
839 : }
840 :
841 : // HFAAuxBuildOverviews doesn't actually generate overviews
842 8 : dfAreaNewOverviews = 0.0;
843 20 : for (int j = 0; j < nOverviews; j++)
844 : {
845 12 : if (abValidLevel[j])
846 12 : abRequireRefresh[j] = true;
847 : }
848 : }
849 :
850 : /* -------------------------------------------------------------------- */
851 : /* Build new overviews - TIFF. Close TIFF files while we */
852 : /* operate on it. */
853 : /* -------------------------------------------------------------------- */
854 : else
855 : {
856 176 : if (poODS != nullptr)
857 : {
858 9 : delete poODS;
859 9 : poODS = nullptr;
860 : }
861 :
862 176 : eErr = GTIFFBuildOverviews(
863 : osOvrFilename, nBands, pahBands, nNewOverviews, panNewOverviewList,
864 : pszResampling, GDALScaledProgress, pScaledProgress, papszOptions);
865 :
866 : // Probe for proxy overview filename.
867 176 : if (eErr == CE_Failure)
868 : {
869 : const char *pszProxyOvrFilename =
870 4 : poDS->GetMetadataItem("FILENAME", "ProxyOverviewRequest");
871 :
872 4 : if (pszProxyOvrFilename != nullptr)
873 : {
874 1 : osOvrFilename = pszProxyOvrFilename;
875 1 : eErr = GTIFFBuildOverviews(osOvrFilename, nBands, pahBands,
876 : nNewOverviews, panNewOverviewList,
877 : pszResampling, GDALScaledProgress,
878 : pScaledProgress, papszOptions);
879 : }
880 : }
881 :
882 176 : if (eErr == CE_None)
883 : {
884 173 : poODS = GDALDataset::Open(osOvrFilename,
885 : GDAL_OF_RASTER | GDAL_OF_UPDATE);
886 173 : if (poODS == nullptr)
887 0 : eErr = CE_Failure;
888 : }
889 : }
890 :
891 184 : GDALDestroyScaledProgress(pScaledProgress);
892 :
893 : /* -------------------------------------------------------------------- */
894 : /* Refresh old overviews that were listed. */
895 : /* -------------------------------------------------------------------- */
896 : GDALRasterBand **papoOverviewBands =
897 184 : static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
898 :
899 475 : for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++)
900 : {
901 291 : poBand = poDS->GetRasterBand(panBandList[iBand]);
902 291 : if (poBand == nullptr)
903 : {
904 0 : eErr = CE_Failure;
905 0 : break;
906 : }
907 :
908 291 : nNewOverviews = 0;
909 582 : std::vector<bool> abAlreadyUsedOverviewBand(poBand->GetOverviewCount(),
910 582 : false);
911 :
912 737 : for (int i = 0; i < nOverviews; i++)
913 : {
914 446 : if (!abValidLevel[i] || !abRequireRefresh[i])
915 417 : continue;
916 :
917 47 : for (int j = 0; j < poBand->GetOverviewCount(); j++)
918 : {
919 47 : if (abAlreadyUsedOverviewBand[j])
920 16 : continue;
921 :
922 31 : GDALRasterBand *poOverview = poBand->GetOverview(j);
923 31 : if (poOverview == nullptr)
924 0 : continue;
925 :
926 31 : int bHasNoData = FALSE;
927 31 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
928 :
929 31 : if (bHasNoData)
930 2 : poOverview->SetNoDataValue(noDataValue);
931 :
932 31 : const int nOvFactor = GDALComputeOvFactor(
933 : poOverview->GetXSize(), poBand->GetXSize(),
934 : poOverview->GetYSize(), poBand->GetYSize());
935 :
936 36 : if (nOvFactor == panOverviewList[i] ||
937 5 : nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
938 : poBand->GetXSize(),
939 : poBand->GetYSize()))
940 : {
941 29 : abAlreadyUsedOverviewBand[j] = true;
942 29 : CPLAssert(nNewOverviews < poBand->GetOverviewCount());
943 29 : papoOverviewBands[nNewOverviews++] = poOverview;
944 29 : break;
945 : }
946 : }
947 : }
948 :
949 291 : if (nNewOverviews > 0)
950 : {
951 19 : const double dfOffset =
952 : dfAreaNewOverviews / dfAreaRefreshedOverviews;
953 19 : const double dfScale = 1.0 - dfOffset;
954 38 : pScaledProgress = GDALCreateScaledProgress(
955 19 : dfOffset + dfScale * iBand / nBands,
956 19 : dfOffset + dfScale * (iBand + 1) / nBands, GDALScaledProgress,
957 : pScaledOverviewWithoutMask);
958 19 : eErr = GDALRegenerateOverviewsEx(
959 : GDALRasterBand::ToHandle(poBand), nNewOverviews,
960 : reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
961 : pszResampling, GDALScaledProgress, pScaledProgress,
962 : papszOptions);
963 19 : GDALDestroyScaledProgress(pScaledProgress);
964 : }
965 : }
966 :
967 : /* -------------------------------------------------------------------- */
968 : /* Cleanup */
969 : /* -------------------------------------------------------------------- */
970 184 : CPLFree(papoOverviewBands);
971 184 : CPLFree(panNewOverviewList);
972 184 : CPLFree(pahBands);
973 184 : GDALDestroyScaledProgress(pScaledOverviewWithoutMask);
974 :
975 : /* -------------------------------------------------------------------- */
976 : /* If we have a mask file, we need to build its overviews too. */
977 : /* -------------------------------------------------------------------- */
978 184 : if (HaveMaskFile() && eErr == CE_None)
979 : {
980 4 : pScaledProgress = GDALCreateScaledProgress(
981 2 : double(nBands) / (nBands + 1), 1.0, pfnProgress, pProgressData);
982 2 : eErr = BuildOverviewsMask(pszResampling, nOverviews, panOverviewList,
983 : GDALScaledProgress, pScaledProgress,
984 : papszOptions);
985 2 : GDALDestroyScaledProgress(pScaledProgress);
986 : }
987 :
988 : /* -------------------------------------------------------------------- */
989 : /* If we have an overview dataset, then mark all the overviews */
990 : /* with the base dataset Used later for finding overviews */
991 : /* masks. Uggg. */
992 : /* -------------------------------------------------------------------- */
993 184 : if (poODS)
994 : {
995 181 : const int nOverviewCount = GetOverviewCount(1);
996 :
997 440 : for (int iOver = 0; iOver < nOverviewCount; iOver++)
998 : {
999 259 : GDALRasterBand *poOtherBand = GetOverview(1, iOver);
1000 : GDALDataset *poOverDS =
1001 259 : poOtherBand != nullptr ? poOtherBand->GetDataset() : nullptr;
1002 :
1003 259 : if (poOverDS != nullptr)
1004 : {
1005 245 : poOverDS->oOvManager.poBaseDS = poDS;
1006 245 : poOverDS->oOvManager.poDS = poOverDS;
1007 : }
1008 : }
1009 : }
1010 :
1011 184 : return eErr;
1012 : }
1013 :
1014 : /************************************************************************/
1015 : /* BuildOverviewsMask() */
1016 : /************************************************************************/
1017 :
1018 4 : CPLErr GDALDefaultOverviews::BuildOverviewsMask(const char *pszResampling,
1019 : int nOverviews,
1020 : const int *panOverviewList,
1021 : GDALProgressFunc pfnProgress,
1022 : void *pProgressData,
1023 : CSLConstList papszOptions)
1024 : {
1025 4 : CPLErr eErr = CE_None;
1026 4 : if (HaveMaskFile() && poMaskDS)
1027 : {
1028 : // Some options are not compatible with mask overviews
1029 : // so unset them, and define more sensible values.
1030 4 : CPLStringList aosMaskOptions(papszOptions);
1031 : const char *pszCompress =
1032 4 : GetOptionValue(papszOptions, "COMPRESS", "COMPRESS_OVERVIEW");
1033 4 : const bool bJPEG = pszCompress && EQUAL(pszCompress, "JPEG");
1034 : const char *pszPhotometric =
1035 4 : GetOptionValue(papszOptions, "PHOTOMETRIC", "PHOTOMETRIC_OVERVIEW");
1036 4 : const bool bPHOTOMETRIC_YCBCR =
1037 4 : pszPhotometric && EQUAL(pszPhotometric, "YCBCR");
1038 4 : if (bJPEG)
1039 0 : aosMaskOptions.SetNameValue("COMPRESS", "DEFLATE");
1040 4 : if (bPHOTOMETRIC_YCBCR)
1041 0 : aosMaskOptions.SetNameValue("PHOTOMETRIC", "MINISBLACK");
1042 :
1043 4 : eErr = poMaskDS->BuildOverviews(
1044 : pszResampling, nOverviews, panOverviewList, 0, nullptr, pfnProgress,
1045 4 : pProgressData, aosMaskOptions.List());
1046 :
1047 4 : if (bOwnMaskDS)
1048 : {
1049 : // Reset the poMask member of main dataset bands, since it
1050 : // will become invalid after poMaskDS closing.
1051 10 : for (int iBand = 1; iBand <= poDS->GetRasterCount(); iBand++)
1052 : {
1053 6 : GDALRasterBand *poOtherBand = poDS->GetRasterBand(iBand);
1054 6 : if (poOtherBand != nullptr)
1055 6 : poOtherBand->InvalidateMaskBand();
1056 : }
1057 :
1058 4 : GDALClose(poMaskDS);
1059 : }
1060 :
1061 : // force next request to reread mask file.
1062 4 : poMaskDS = nullptr;
1063 4 : bOwnMaskDS = false;
1064 4 : bCheckedForMask = false;
1065 : }
1066 :
1067 4 : return eErr;
1068 : }
1069 :
1070 : /************************************************************************/
1071 : /* CreateMaskBand() */
1072 : /************************************************************************/
1073 :
1074 26 : CPLErr GDALDefaultOverviews::CreateMaskBand(int nFlags, int nBand)
1075 :
1076 : {
1077 26 : if (nBand < 1)
1078 17 : nFlags |= GMF_PER_DATASET;
1079 :
1080 : /* -------------------------------------------------------------------- */
1081 : /* ensure existing file gets opened if there is one. */
1082 : /* -------------------------------------------------------------------- */
1083 26 : CPL_IGNORE_RET_VAL(HaveMaskFile());
1084 :
1085 : /* -------------------------------------------------------------------- */
1086 : /* Try creating the mask file. */
1087 : /* -------------------------------------------------------------------- */
1088 26 : if (poMaskDS == nullptr)
1089 : {
1090 : GDALDriver *const poDr =
1091 21 : static_cast<GDALDriver *>(GDALGetDriverByName("GTiff"));
1092 :
1093 21 : if (poDr == nullptr)
1094 0 : return CE_Failure;
1095 :
1096 21 : GDALRasterBand *const poTBand = poDS->GetRasterBand(1);
1097 21 : if (poTBand == nullptr)
1098 0 : return CE_Failure;
1099 :
1100 : const int nBands =
1101 21 : (nFlags & GMF_PER_DATASET) ? 1 : poDS->GetRasterCount();
1102 :
1103 21 : char **papszOpt = CSLSetNameValue(nullptr, "COMPRESS", "DEFLATE");
1104 21 : papszOpt = CSLSetNameValue(papszOpt, "INTERLEAVE", "BAND");
1105 :
1106 21 : int nBX = 0;
1107 21 : int nBY = 0;
1108 21 : poTBand->GetBlockSize(&nBX, &nBY);
1109 :
1110 : // Try to create matching tile size if legal in TIFF.
1111 21 : if ((nBX % 16) == 0 && (nBY % 16) == 0)
1112 : {
1113 2 : papszOpt = CSLSetNameValue(papszOpt, "TILED", "YES");
1114 2 : papszOpt = CSLSetNameValue(papszOpt, "BLOCKXSIZE",
1115 4 : CPLString().Printf("%d", nBX));
1116 2 : papszOpt = CSLSetNameValue(papszOpt, "BLOCKYSIZE",
1117 4 : CPLString().Printf("%d", nBY));
1118 : }
1119 :
1120 21 : CPLString osMskFilename;
1121 21 : osMskFilename.Printf("%s.msk", poDS->GetDescription());
1122 21 : poMaskDS =
1123 21 : poDr->Create(osMskFilename, poDS->GetRasterXSize(),
1124 21 : poDS->GetRasterYSize(), nBands, GDT_Byte, papszOpt);
1125 21 : CSLDestroy(papszOpt);
1126 :
1127 21 : if (poMaskDS == nullptr) // Presumably error already issued.
1128 0 : return CE_Failure;
1129 :
1130 21 : bOwnMaskDS = true;
1131 : }
1132 :
1133 : /* -------------------------------------------------------------------- */
1134 : /* Save the mask flags for this band. */
1135 : /* -------------------------------------------------------------------- */
1136 26 : if (nBand > poMaskDS->GetRasterCount())
1137 : {
1138 1 : CPLError(CE_Failure, CPLE_AppDefined,
1139 : "Attempt to create a mask band for band %d of %s, "
1140 : "but the .msk file has a PER_DATASET mask.",
1141 1 : nBand, poDS->GetDescription());
1142 1 : return CE_Failure;
1143 : }
1144 :
1145 67 : for (int iBand = 0; iBand < poDS->GetRasterCount(); iBand++)
1146 : {
1147 : // we write only the info for this band, unless we are
1148 : // using PER_DATASET in which case we write for all.
1149 42 : if (nBand != iBand + 1 && !(nFlags & GMF_PER_DATASET))
1150 6 : continue;
1151 :
1152 36 : poMaskDS->SetMetadataItem(
1153 72 : CPLString().Printf("INTERNAL_MASK_FLAGS_%d", iBand + 1),
1154 72 : CPLString().Printf("%d", nFlags));
1155 : }
1156 :
1157 25 : return CE_None;
1158 : }
1159 :
1160 : /************************************************************************/
1161 : /* GetMaskBand() */
1162 : /************************************************************************/
1163 :
1164 : // Secret code meaning we don't handle this band.
1165 : constexpr int MISSING_FLAGS = 0x8000;
1166 :
1167 46 : GDALRasterBand *GDALDefaultOverviews::GetMaskBand(int nBand)
1168 :
1169 : {
1170 46 : const int nFlags = GetMaskFlags(nBand);
1171 :
1172 46 : if (poMaskDS == nullptr || nFlags == MISSING_FLAGS)
1173 1 : return nullptr;
1174 :
1175 45 : if (nFlags & GMF_PER_DATASET)
1176 36 : return poMaskDS->GetRasterBand(1);
1177 :
1178 9 : if (nBand > 0)
1179 9 : return poMaskDS->GetRasterBand(nBand);
1180 :
1181 0 : return nullptr;
1182 : }
1183 :
1184 : /************************************************************************/
1185 : /* GetMaskFlags() */
1186 : /************************************************************************/
1187 :
1188 90 : int GDALDefaultOverviews::GetMaskFlags(int nBand)
1189 :
1190 : {
1191 : /* -------------------------------------------------------------------- */
1192 : /* Fetch this band's metadata entry. They are of the form: */
1193 : /* INTERNAL_MASK_FLAGS_n: flags */
1194 : /* -------------------------------------------------------------------- */
1195 90 : if (!HaveMaskFile())
1196 0 : return 0;
1197 :
1198 90 : const char *pszValue = poMaskDS->GetMetadataItem(
1199 180 : CPLString().Printf("INTERNAL_MASK_FLAGS_%d", std::max(nBand, 1)));
1200 :
1201 90 : if (pszValue == nullptr)
1202 1 : return MISSING_FLAGS;
1203 :
1204 89 : return atoi(pszValue);
1205 : }
1206 :
1207 : /************************************************************************/
1208 : /* HaveMaskFile() */
1209 : /* */
1210 : /* Check for a mask file if we haven't already done so. */
1211 : /* Returns TRUE if we have one, otherwise FALSE. */
1212 : /************************************************************************/
1213 :
1214 27764 : int GDALDefaultOverviews::HaveMaskFile(char **papszSiblingFiles,
1215 : const char *pszBasename)
1216 :
1217 : {
1218 : /* -------------------------------------------------------------------- */
1219 : /* Have we already checked for masks? */
1220 : /* -------------------------------------------------------------------- */
1221 27764 : if (bCheckedForMask)
1222 2182 : return poMaskDS != nullptr;
1223 :
1224 25582 : if (papszSiblingFiles == nullptr)
1225 25582 : papszSiblingFiles = papszInitSiblingFiles;
1226 :
1227 : /* -------------------------------------------------------------------- */
1228 : /* Are we an overview? If so we need to find the corresponding */
1229 : /* overview in the base files mask file (if there is one). */
1230 : /* -------------------------------------------------------------------- */
1231 25582 : if (poBaseDS != nullptr && poBaseDS->oOvManager.HaveMaskFile())
1232 : {
1233 4 : GDALRasterBand *const poBaseBand = poBaseDS->GetRasterBand(1);
1234 4 : GDALDataset *poMaskDSTemp = nullptr;
1235 4 : if (poBaseBand != nullptr)
1236 : {
1237 4 : GDALRasterBand *poBaseMask = poBaseBand->GetMaskBand();
1238 4 : if (poBaseMask != nullptr)
1239 : {
1240 4 : const int nOverviewCount = poBaseMask->GetOverviewCount();
1241 6 : for (int iOver = 0; iOver < nOverviewCount; iOver++)
1242 : {
1243 : GDALRasterBand *const poOverBand =
1244 6 : poBaseMask->GetOverview(iOver);
1245 6 : if (poOverBand == nullptr)
1246 0 : continue;
1247 :
1248 10 : if (poOverBand->GetXSize() == poDS->GetRasterXSize() &&
1249 4 : poOverBand->GetYSize() == poDS->GetRasterYSize())
1250 : {
1251 4 : poMaskDSTemp = poOverBand->GetDataset();
1252 4 : break;
1253 : }
1254 : }
1255 : }
1256 : }
1257 :
1258 4 : if (poMaskDSTemp != poDS)
1259 : {
1260 4 : poMaskDS = poMaskDSTemp;
1261 4 : bCheckedForMask = true;
1262 4 : bOwnMaskDS = false;
1263 :
1264 4 : return poMaskDS != nullptr;
1265 : }
1266 : }
1267 :
1268 : /* -------------------------------------------------------------------- */
1269 : /* Are we even initialized? If not, we apparently don't want */
1270 : /* to support overviews and masks. */
1271 : /* -------------------------------------------------------------------- */
1272 25578 : if (poDS == nullptr)
1273 16893 : return FALSE;
1274 :
1275 : /* -------------------------------------------------------------------- */
1276 : /* Check for .msk file. */
1277 : /* -------------------------------------------------------------------- */
1278 8685 : bCheckedForMask = true;
1279 :
1280 8685 : if (pszBasename == nullptr)
1281 8685 : pszBasename = poDS->GetDescription();
1282 :
1283 : // Don't bother checking for masks of masks.
1284 8685 : if (EQUAL(CPLGetExtension(pszBasename), "msk"))
1285 20 : return FALSE;
1286 :
1287 8665 : if (!GDALCanFileAcceptSidecarFile(pszBasename))
1288 0 : return FALSE;
1289 17330 : CPLString osMskFilename;
1290 8665 : osMskFilename.Printf("%s.msk", pszBasename);
1291 :
1292 17330 : std::vector<char> achMskFilename;
1293 8665 : achMskFilename.resize(osMskFilename.size() + 1);
1294 8665 : memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
1295 8665 : osMskFilename.size() + 1);
1296 : bool bExists =
1297 8665 : CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
1298 8665 : osMskFilename = &achMskFilename[0];
1299 :
1300 : #if !defined(_WIN32)
1301 8665 : if (!bExists && !papszSiblingFiles)
1302 : {
1303 2237 : osMskFilename.Printf("%s.MSK", pszBasename);
1304 2237 : memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
1305 2237 : osMskFilename.size() + 1);
1306 : bExists =
1307 2237 : CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
1308 2237 : osMskFilename = &achMskFilename[0];
1309 : }
1310 : #endif
1311 :
1312 8665 : if (!bExists)
1313 8628 : return FALSE;
1314 :
1315 : /* -------------------------------------------------------------------- */
1316 : /* Open the file. */
1317 : /* -------------------------------------------------------------------- */
1318 37 : poMaskDS = GDALDataset::Open(
1319 : osMskFilename,
1320 37 : GDAL_OF_RASTER | (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
1321 37 : nullptr, nullptr, papszInitSiblingFiles);
1322 37 : CPLAssert(poMaskDS != poDS);
1323 :
1324 37 : if (poMaskDS == nullptr)
1325 1 : return FALSE;
1326 :
1327 36 : bOwnMaskDS = true;
1328 :
1329 36 : return TRUE;
1330 : }
1331 :
1332 : /************************************************************************/
1333 : /* GDALGetNormalizedOvrResampling() */
1334 : /************************************************************************/
1335 :
1336 873 : std::string GDALGetNormalizedOvrResampling(const char *pszResampling)
1337 : {
1338 873 : if (pszResampling &&
1339 873 : EQUAL(pszResampling, "AVERAGE_BIT2GRAYSCALE_MINISWHITE"))
1340 0 : return "AVERAGE_BIT2GRAYSCALE_MINISWHITE";
1341 873 : else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2"))
1342 8 : return "AVERAGE_BIT2GRAYSCALE";
1343 865 : else if (pszResampling && STARTS_WITH_CI(pszResampling, "NEAR"))
1344 354 : return "NEAREST";
1345 511 : else if (pszResampling && EQUAL(pszResampling, "AVERAGE_MAGPHASE"))
1346 0 : return "AVERAGE_MAGPHASE";
1347 511 : else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVER"))
1348 242 : return "AVERAGE";
1349 269 : else if (pszResampling && !EQUAL(pszResampling, "NONE"))
1350 : {
1351 306 : return CPLString(pszResampling).toupper();
1352 : }
1353 116 : return std::string();
1354 : }
1355 :
1356 : //! @endcond
|