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