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 127100 : 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 127100 : papszInitSiblingFiles(nullptr)
44 : {
45 127049 : }
46 :
47 : /************************************************************************/
48 : /* ~GDALDefaultOverviews() */
49 : /************************************************************************/
50 :
51 127101 : GDALDefaultOverviews::~GDALDefaultOverviews()
52 :
53 : {
54 127124 : CPLFree(pszInitName);
55 127126 : CSLDestroy(papszInitSiblingFiles);
56 :
57 127117 : CloseDependentDatasets();
58 127107 : }
59 :
60 : /************************************************************************/
61 : /* CloseDependentDatasets() */
62 : /************************************************************************/
63 :
64 145615 : int GDALDefaultOverviews::CloseDependentDatasets()
65 : {
66 145615 : bool bHasDroppedRef = false;
67 145615 : if (poODS != nullptr)
68 : {
69 372 : bHasDroppedRef = true;
70 372 : poODS->FlushCache(true);
71 372 : GDALClose(poODS);
72 349 : poODS = nullptr;
73 : }
74 :
75 145592 : 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 145592 : return bHasDroppedRef;
87 : }
88 :
89 : /************************************************************************/
90 : /* IsInitialized() */
91 : /* */
92 : /* Returns TRUE if we are initialized. */
93 : /************************************************************************/
94 :
95 665877 : int GDALDefaultOverviews::IsInitialized()
96 :
97 : {
98 665877 : OverviewScan();
99 665877 : return poDS != nullptr;
100 : }
101 :
102 : /************************************************************************/
103 : /* Initialize() */
104 : /************************************************************************/
105 :
106 44463 : void GDALDefaultOverviews::Initialize(GDALDataset *poDSIn,
107 : const char *pszBasename,
108 : CSLConstList papszSiblingFiles,
109 : bool bNameIsOVR)
110 :
111 : {
112 44463 : poDS = poDSIn;
113 :
114 : /* -------------------------------------------------------------------- */
115 : /* If we were already initialized, destroy the old overview */
116 : /* file handle. */
117 : /* -------------------------------------------------------------------- */
118 44463 : 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 44463 : bCheckedForOverviews = FALSE;
132 :
133 44463 : CPLFree(pszInitName);
134 44595 : pszInitName = nullptr;
135 44595 : if (pszBasename != nullptr)
136 44419 : pszInitName = CPLStrdup(pszBasename);
137 44596 : bInitNameIsOVR = bNameIsOVR;
138 :
139 44596 : CSLDestroy(papszInitSiblingFiles);
140 44574 : papszInitSiblingFiles = nullptr;
141 44574 : if (papszSiblingFiles != nullptr)
142 5198 : papszInitSiblingFiles = CSLDuplicate(papszSiblingFiles);
143 44574 : }
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 27806 : void GDALDefaultOverviews::Initialize(GDALDataset *poDSIn,
162 : GDALOpenInfo *poOpenInfo,
163 : const char *pszName,
164 : bool bTransferSiblingFilesIfLoaded)
165 : {
166 27806 : Initialize(poDSIn, pszName ? pszName : poOpenInfo->pszFilename);
167 :
168 27733 : if (bTransferSiblingFilesIfLoaded && poOpenInfo->AreSiblingFilesLoaded())
169 8415 : TransferSiblingFiles(poOpenInfo->StealSiblingFiles());
170 27698 : }
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 21383 : void GDALDefaultOverviews::TransferSiblingFiles(char **papszSiblingFiles)
181 : {
182 21383 : CSLDestroy(papszInitSiblingFiles);
183 21383 : papszInitSiblingFiles = papszSiblingFiles;
184 21383 : }
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 360 : static void FreeAntiRecursionDefaultOvr(void *pData)
197 : {
198 360 : delete static_cast<AntiRecursionStructDefaultOvr *>(pData);
199 360 : }
200 :
201 11043 : static AntiRecursionStructDefaultOvr &GetAntiRecursionDefaultOvr()
202 : {
203 11043 : static AntiRecursionStructDefaultOvr dummy;
204 11043 : int bMemoryErrorOccurred = false;
205 : void *pData =
206 11043 : CPLGetTLSEx(CTLS_GDALDEFAULTOVR_ANTIREC, &bMemoryErrorOccurred);
207 11043 : if (bMemoryErrorOccurred)
208 : {
209 0 : return dummy;
210 : }
211 11043 : if (pData == nullptr)
212 : {
213 423 : auto pAntiRecursion = new AntiRecursionStructDefaultOvr();
214 423 : CPLSetTLSWithFreeFuncEx(CTLS_GDALDEFAULTOVR_ANTIREC, pAntiRecursion,
215 : FreeAntiRecursionDefaultOvr,
216 : &bMemoryErrorOccurred);
217 423 : if (bMemoryErrorOccurred)
218 : {
219 0 : delete pAntiRecursion;
220 0 : return dummy;
221 : }
222 423 : return *pAntiRecursion;
223 : }
224 10620 : 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 665877 : void GDALDefaultOverviews::OverviewScan()
237 :
238 : {
239 665877 : if (bCheckedForOverviews || poDS == nullptr)
240 654834 : return;
241 :
242 11043 : bCheckedForOverviews = true;
243 11043 : if (pszInitName == nullptr)
244 12 : pszInitName = CPLStrdup(poDS->GetDescription());
245 :
246 11043 : AntiRecursionStructDefaultOvr &antiRec = GetAntiRecursionDefaultOvr();
247 : // 32 should be enough to handle a .ovr.ovr.ovr...
248 11043 : if (antiRec.nRecLevel == 32)
249 0 : return;
250 11043 : if (antiRec.oSetFiles.find(pszInitName) != antiRec.oSetFiles.end())
251 0 : return;
252 11043 : antiRec.oSetFiles.insert(pszInitName);
253 11043 : ++antiRec.nRecLevel;
254 :
255 11043 : CPLDebug("GDAL", "GDALDefaultOverviews::OverviewScan()");
256 :
257 : /* -------------------------------------------------------------------- */
258 : /* Open overview dataset if it exists. */
259 : /* -------------------------------------------------------------------- */
260 21904 : if (!EQUAL(pszInitName, ":::VIRTUAL:::") &&
261 10861 : GDALCanFileAcceptSidecarFile(pszInitName))
262 : {
263 10859 : if (bInitNameIsOVR)
264 0 : osOvrFilename = pszInitName;
265 : else
266 10859 : osOvrFilename.Printf("%s.ovr", pszInitName);
267 :
268 21718 : std::vector<char> achOvrFilename;
269 10859 : achOvrFilename.resize(osOvrFilename.size() + 1);
270 10859 : memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
271 10859 : osOvrFilename.size() + 1);
272 10859 : bool bExists = CPL_TO_BOOL(
273 10859 : CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
274 10859 : osOvrFilename = &achOvrFilename[0];
275 :
276 : #if !defined(_WIN32)
277 10859 : if (!bInitNameIsOVR && !bExists && !papszInitSiblingFiles)
278 : {
279 2595 : osOvrFilename.Printf("%s.OVR", pszInitName);
280 2595 : memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
281 2595 : osOvrFilename.size() + 1);
282 2595 : bExists = CPL_TO_BOOL(
283 2595 : CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
284 2595 : osOvrFilename = &achOvrFilename[0];
285 2595 : if (!bExists)
286 2595 : osOvrFilename.Printf("%s.ovr", pszInitName);
287 : }
288 : #endif
289 :
290 10859 : if (bExists)
291 : {
292 186 : poODS = GDALDataset::Open(
293 : osOvrFilename,
294 : GDAL_OF_RASTER |
295 186 : (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
296 186 : 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 21719 : if (!poODS && !EQUAL(pszInitName, ":::VIRTUAL:::") &&
309 10676 : GDALCanFileAcceptSidecarFile(pszInitName))
310 : {
311 10674 : bool bTryFindAssociatedAuxFile = true;
312 10674 : if (papszInitSiblingFiles)
313 : {
314 16158 : CPLString osAuxFilename = CPLResetExtension(pszInitName, "aux");
315 8079 : int iSibling = CSLFindString(papszInitSiblingFiles,
316 : CPLGetFilename(osAuxFilename));
317 8079 : if (iSibling < 0)
318 : {
319 8075 : osAuxFilename = pszInitName;
320 8075 : osAuxFilename += ".aux";
321 8075 : iSibling = CSLFindString(papszInitSiblingFiles,
322 : CPLGetFilename(osAuxFilename));
323 8075 : if (iSibling < 0)
324 8075 : bTryFindAssociatedAuxFile = false;
325 : }
326 : }
327 :
328 10674 : if (bTryFindAssociatedAuxFile)
329 : {
330 2599 : poODS =
331 2599 : GDALFindAssociatedAuxFile(pszInitName, poDS->GetAccess(), poDS);
332 : }
333 :
334 10674 : 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 11043 : if (poODS == nullptr)
359 : {
360 : const char *pszProxyOvrFilename =
361 10851 : poDS->GetMetadataItem("OVERVIEW_FILE", "OVERVIEWS");
362 :
363 10851 : if (pszProxyOvrFilename != nullptr)
364 : {
365 31 : if (STARTS_WITH_CI(pszProxyOvrFilename, ":::BASE:::"))
366 : {
367 0 : const CPLString osPath = CPLGetPath(poDS->GetDescription());
368 :
369 : osOvrFilename =
370 0 : CPLFormFilename(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 11043 : if (poODS)
392 : {
393 210 : const int nOverviewCount = GetOverviewCount(1);
394 :
395 504 : for (int iOver = 0; iOver < nOverviewCount; iOver++)
396 : {
397 294 : GDALRasterBand *const poBand = GetOverview(1, iOver);
398 : GDALDataset *const poOverDS =
399 294 : poBand != nullptr ? poBand->GetDataset() : nullptr;
400 :
401 294 : if (poOverDS != nullptr)
402 : {
403 280 : poOverDS->oOvManager.poBaseDS = poDS;
404 280 : poOverDS->oOvManager.poDS = poOverDS;
405 : }
406 : }
407 : }
408 :
409 : // Undo anti recursion protection
410 11043 : antiRec.oSetFiles.erase(pszInitName);
411 11043 : --antiRec.nRecLevel;
412 : }
413 :
414 : /************************************************************************/
415 : /* GetOverviewCount() */
416 : /************************************************************************/
417 :
418 655685 : int GDALDefaultOverviews::GetOverviewCount(int nBand)
419 :
420 : {
421 655685 : if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
422 654717 : return 0;
423 :
424 968 : GDALRasterBand *poBand = poODS->GetRasterBand(nBand);
425 968 : if (poBand == nullptr)
426 0 : return 0;
427 :
428 968 : if (bOvrIsAux)
429 74 : return poBand->GetOverviewCount();
430 :
431 894 : return poBand->GetOverviewCount() + 1;
432 : }
433 :
434 : /************************************************************************/
435 : /* GetOverview() */
436 : /************************************************************************/
437 :
438 1289 : GDALRasterBand *GDALDefaultOverviews::GetOverview(int nBand, int iOverview)
439 :
440 : {
441 1289 : if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
442 258 : return nullptr;
443 :
444 1031 : GDALRasterBand *const poBand = poODS->GetRasterBand(nBand);
445 1031 : if (poBand == nullptr)
446 0 : return nullptr;
447 :
448 1031 : if (bOvrIsAux)
449 63 : return poBand->GetOverview(iOverview);
450 :
451 : // TIFF case, base is overview 0.
452 968 : if (iOverview == 0)
453 729 : 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 494 : 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 494 : if (nXSize >= nYSize / 2 && !(nXSize < nYSize && nXSize < nOvLevel))
491 : {
492 397 : const int nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
493 :
494 397 : 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 1722 : 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 1722 : if (nRasterXSize != 1 && nRasterXSize >= nRasterYSize / 2)
513 : {
514 1610 : return static_cast<int>(0.5 +
515 1610 : 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 9 : CPLErr GDALDefaultOverviews::CleanOverviews()
529 :
530 : {
531 : // Anything to do?
532 9 : if (poODS == nullptr)
533 1 : return CE_None;
534 :
535 : // Delete the overview file(s).
536 8 : GDALDriver *poOvrDriver = poODS->GetDriver();
537 8 : GDALClose(poODS);
538 8 : poODS = nullptr;
539 :
540 : CPLErr eErr =
541 8 : poOvrDriver != nullptr ? poOvrDriver->Delete(osOvrFilename) : CE_None;
542 :
543 : // Reset the saved overview filename.
544 8 : if (!EQUAL(poDS->GetDescription(), ":::VIRTUAL:::"))
545 : {
546 8 : const bool bUseRRD = CPLTestBool(CPLGetConfigOption("USE_RRD", "NO"));
547 :
548 8 : if (bUseRRD)
549 0 : osOvrFilename = CPLResetExtension(poDS->GetDescription(), "aux");
550 : else
551 8 : osOvrFilename.Printf("%s.ovr", poDS->GetDescription());
552 : }
553 : else
554 : {
555 0 : osOvrFilename = "";
556 : }
557 :
558 8 : if (HaveMaskFile() && poMaskDS)
559 : {
560 1 : const CPLErr eErr2 = poMaskDS->BuildOverviews(
561 : nullptr, 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr);
562 1 : if (eErr2 != CE_None)
563 0 : return eErr2;
564 : }
565 :
566 8 : return eErr;
567 : }
568 :
569 : /************************************************************************/
570 : /* BuildOverviewsSubDataset() */
571 : /************************************************************************/
572 :
573 9 : CPLErr GDALDefaultOverviews::BuildOverviewsSubDataset(
574 : const char *pszPhysicalFile, const char *pszResampling, int nOverviews,
575 : const int *panOverviewList, int nBands, const int *panBandList,
576 : GDALProgressFunc pfnProgress, void *pProgressData,
577 : CSLConstList papszOptions)
578 :
579 : {
580 9 : if (osOvrFilename.length() == 0 && nOverviews > 0)
581 : {
582 : VSIStatBufL sStatBuf;
583 :
584 6 : int iSequence = 0; // Used after for.
585 6 : for (iSequence = 0; iSequence < 100; iSequence++)
586 : {
587 6 : osOvrFilename.Printf("%s_%d.ovr", pszPhysicalFile, iSequence);
588 6 : if (VSIStatExL(osOvrFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) != 0)
589 : {
590 12 : CPLString osAdjustedOvrFilename;
591 :
592 6 : if (poDS->GetMOFlags() & GMO_PAM_CLASS)
593 : {
594 : osAdjustedOvrFilename.Printf(
595 : ":::BASE:::%s_%d.ovr", CPLGetFilename(pszPhysicalFile),
596 6 : iSequence);
597 : }
598 : else
599 : {
600 0 : osAdjustedOvrFilename = osOvrFilename;
601 : }
602 :
603 6 : poDS->SetMetadataItem("OVERVIEW_FILE", osAdjustedOvrFilename,
604 6 : "OVERVIEWS");
605 6 : break;
606 : }
607 : }
608 :
609 6 : if (iSequence == 100)
610 0 : osOvrFilename = "";
611 : }
612 :
613 9 : return BuildOverviews(nullptr, pszResampling, nOverviews, panOverviewList,
614 : nBands, panBandList, pfnProgress, pProgressData,
615 9 : papszOptions);
616 : }
617 :
618 : /************************************************************************/
619 : /* GetOptionValue() */
620 : /************************************************************************/
621 :
622 182 : static const char *GetOptionValue(CSLConstList papszOptions,
623 : const char *pszOptionKey,
624 : const char *pszConfigOptionKey)
625 : {
626 : const char *pszVal =
627 182 : pszOptionKey ? CSLFetchNameValue(papszOptions, pszOptionKey) : nullptr;
628 182 : if (pszVal)
629 : {
630 0 : return pszVal;
631 : }
632 182 : pszVal = CSLFetchNameValue(papszOptions, pszConfigOptionKey);
633 182 : if (pszVal)
634 : {
635 2 : return pszVal;
636 : }
637 180 : pszVal = CPLGetConfigOption(pszConfigOptionKey, nullptr);
638 180 : return pszVal;
639 : }
640 :
641 : /************************************************************************/
642 : /* BuildOverviews() */
643 : /************************************************************************/
644 :
645 195 : CPLErr GDALDefaultOverviews::BuildOverviews(
646 : const char *pszBasename, const char *pszResampling, int nOverviews,
647 : const int *panOverviewList, int nBands, const int *panBandList,
648 : GDALProgressFunc pfnProgress, void *pProgressData,
649 : CSLConstList papszOptions)
650 :
651 : {
652 195 : if (pfnProgress == nullptr)
653 0 : pfnProgress = GDALDummyProgress;
654 :
655 195 : if (nOverviews == 0)
656 8 : return CleanOverviews();
657 :
658 : /* -------------------------------------------------------------------- */
659 : /* If we don't already have an overview file, we need to decide */
660 : /* what format to use. */
661 : /* -------------------------------------------------------------------- */
662 187 : if (poODS == nullptr)
663 : {
664 : const char *pszUseRRD =
665 174 : GetOptionValue(papszOptions, nullptr, "USE_RRD");
666 174 : bOvrIsAux = pszUseRRD && CPLTestBool(pszUseRRD);
667 174 : if (bOvrIsAux)
668 : {
669 4 : osOvrFilename = CPLResetExtension(poDS->GetDescription(), "aux");
670 :
671 : VSIStatBufL sStatBuf;
672 4 : if (VSIStatExL(osOvrFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0)
673 0 : osOvrFilename.Printf("%s.aux", poDS->GetDescription());
674 : }
675 : }
676 : /* -------------------------------------------------------------------- */
677 : /* If we already have the overviews open, but they are */
678 : /* read-only, then try and reopen them read-write. */
679 : /* -------------------------------------------------------------------- */
680 13 : else if (poODS->GetAccess() == GA_ReadOnly)
681 : {
682 11 : GDALClose(poODS);
683 11 : poODS =
684 11 : GDALDataset::Open(osOvrFilename, GDAL_OF_RASTER | GDAL_OF_UPDATE);
685 11 : if (poODS == nullptr)
686 0 : return CE_Failure;
687 : }
688 :
689 : /* -------------------------------------------------------------------- */
690 : /* Our TIFF overview support currently only works safely if all */
691 : /* bands are handled at the same time. */
692 : /* -------------------------------------------------------------------- */
693 187 : if (!bOvrIsAux && nBands != poDS->GetRasterCount())
694 : {
695 0 : CPLError(CE_Failure, CPLE_NotSupported,
696 : "Generation of overviews in external TIFF currently only "
697 : "supported when operating on all bands. "
698 : "Operation failed.");
699 0 : return CE_Failure;
700 : }
701 :
702 : /* -------------------------------------------------------------------- */
703 : /* If a basename is provided, use it to override the internal */
704 : /* overview filename. */
705 : /* -------------------------------------------------------------------- */
706 187 : if (pszBasename == nullptr && osOvrFilename.length() == 0)
707 0 : pszBasename = poDS->GetDescription();
708 :
709 187 : if (pszBasename != nullptr)
710 : {
711 1 : if (bOvrIsAux)
712 0 : osOvrFilename.Printf("%s.aux", pszBasename);
713 : else
714 1 : osOvrFilename.Printf("%s.ovr", pszBasename);
715 : }
716 :
717 : /* -------------------------------------------------------------------- */
718 : /* Establish which of the overview levels we already have, and */
719 : /* which are new. We assume that band 1 of the file is */
720 : /* representative. */
721 : /* -------------------------------------------------------------------- */
722 187 : GDALRasterBand *poBand = poDS->GetRasterBand(1);
723 :
724 187 : int nNewOverviews = 0;
725 : int *panNewOverviewList =
726 187 : static_cast<int *>(CPLCalloc(sizeof(int), nOverviews));
727 187 : double dfAreaNewOverviews = 0;
728 187 : double dfAreaRefreshedOverviews = 0;
729 374 : std::vector<bool> abValidLevel(nOverviews, true);
730 187 : std::vector<bool> abRequireRefresh(nOverviews, false);
731 187 : bool bFoundSinglePixelOverview = false;
732 462 : for (int i = 0; i < nOverviews && poBand != nullptr; i++)
733 : {
734 : // If we already have a 1x1 overview and this new one would result
735 : // in it too, then don't create it.
736 307 : if (bFoundSinglePixelOverview &&
737 16 : (poBand->GetXSize() + panOverviewList[i] - 1) /
738 16 : panOverviewList[i] ==
739 291 : 1 &&
740 16 : (poBand->GetYSize() + panOverviewList[i] - 1) /
741 16 : panOverviewList[i] ==
742 : 1)
743 : {
744 16 : abValidLevel[i] = false;
745 16 : continue;
746 : }
747 :
748 280 : for (int j = 0; j < poBand->GetOverviewCount(); j++)
749 : {
750 38 : GDALRasterBand *poOverview = poBand->GetOverview(j);
751 38 : if (poOverview == nullptr)
752 0 : continue;
753 :
754 : int nOvFactor =
755 38 : GDALComputeOvFactor(poOverview->GetXSize(), poBand->GetXSize(),
756 : poOverview->GetYSize(), poBand->GetYSize());
757 :
758 62 : if (nOvFactor == panOverviewList[i] ||
759 24 : nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
760 : poBand->GetXSize(),
761 : poBand->GetYSize()))
762 : {
763 : const auto osNewResampling =
764 34 : GDALGetNormalizedOvrResampling(pszResampling);
765 : const char *pszExistingResampling =
766 17 : poOverview->GetMetadataItem("RESAMPLING");
767 28 : if (pszExistingResampling &&
768 11 : pszExistingResampling != osNewResampling)
769 : {
770 3 : if (auto l_poODS = poOverview->GetDataset())
771 : {
772 3 : if (auto poDriver = l_poODS->GetDriver())
773 : {
774 1 : if (EQUAL(poDriver->GetDescription(), "GTiff"))
775 : {
776 1 : poOverview->SetMetadataItem(
777 1 : "RESAMPLING", osNewResampling.c_str());
778 : }
779 : }
780 : }
781 : }
782 :
783 17 : abRequireRefresh[i] = true;
784 17 : break;
785 : }
786 : }
787 :
788 259 : if (abValidLevel[i])
789 : {
790 259 : const double dfArea =
791 : 1.0 /
792 259 : (static_cast<double>(panOverviewList[i]) * panOverviewList[i]);
793 259 : dfAreaRefreshedOverviews += dfArea;
794 259 : if (!abRequireRefresh[i])
795 : {
796 242 : dfAreaNewOverviews += dfArea;
797 242 : panNewOverviewList[nNewOverviews++] = panOverviewList[i];
798 : }
799 :
800 259 : if ((poBand->GetXSize() + panOverviewList[i] - 1) /
801 259 : panOverviewList[i] ==
802 279 : 1 &&
803 20 : (poBand->GetYSize() + panOverviewList[i] - 1) /
804 20 : panOverviewList[i] ==
805 : 1)
806 : {
807 18 : bFoundSinglePixelOverview = true;
808 : }
809 : }
810 : }
811 :
812 : /* -------------------------------------------------------------------- */
813 : /* Build band list. */
814 : /* -------------------------------------------------------------------- */
815 : GDALRasterBand **pahBands = static_cast<GDALRasterBand **>(
816 187 : CPLCalloc(sizeof(GDALRasterBand *), nBands));
817 489 : for (int i = 0; i < nBands; i++)
818 302 : pahBands[i] = poDS->GetRasterBand(panBandList[i]);
819 :
820 : /* -------------------------------------------------------------------- */
821 : /* Build new overviews - Imagine. Keep existing file open if */
822 : /* we have it. But mark all overviews as in need of */
823 : /* regeneration, since HFAAuxBuildOverviews() doesn't actually */
824 : /* produce the imagery. */
825 : /* -------------------------------------------------------------------- */
826 :
827 187 : CPLErr eErr = CE_None;
828 :
829 187 : void *pScaledOverviewWithoutMask = GDALCreateScaledProgress(
830 187 : 0, (HaveMaskFile() && poMaskDS) ? double(nBands) / (nBands + 1) : 1,
831 : pfnProgress, pProgressData);
832 :
833 187 : void *pScaledProgress = GDALCreateScaledProgress(
834 : 0, dfAreaNewOverviews / dfAreaRefreshedOverviews, GDALScaledProgress,
835 : pScaledOverviewWithoutMask);
836 187 : if (bOvrIsAux)
837 : {
838 : #ifdef NO_HFA_SUPPORT
839 : CPLError(CE_Failure, CPLE_NotSupported,
840 : "This build does not support creating .aux overviews");
841 : eErr = CE_Failure;
842 : #else
843 8 : if (nNewOverviews == 0)
844 : {
845 : /* if we call HFAAuxBuildOverviews() with nNewOverviews == 0 */
846 : /* because that there's no new, this will wipe existing */
847 : /* overviews (#4831) */
848 : // eErr = CE_None;
849 : }
850 : else
851 : {
852 5 : eErr = HFAAuxBuildOverviews(
853 : osOvrFilename, poDS, &poODS, nBands, panBandList, nNewOverviews,
854 : panNewOverviewList, pszResampling, GDALScaledProgress,
855 : pScaledProgress, papszOptions);
856 : }
857 :
858 : // HFAAuxBuildOverviews doesn't actually generate overviews
859 8 : dfAreaNewOverviews = 0.0;
860 20 : for (int j = 0; j < nOverviews; j++)
861 : {
862 12 : if (abValidLevel[j])
863 12 : abRequireRefresh[j] = true;
864 : }
865 : #endif
866 : }
867 :
868 : /* -------------------------------------------------------------------- */
869 : /* Build new overviews - TIFF. Close TIFF files while we */
870 : /* operate on it. */
871 : /* -------------------------------------------------------------------- */
872 : else
873 : {
874 179 : if (poODS != nullptr)
875 : {
876 9 : delete poODS;
877 9 : poODS = nullptr;
878 : }
879 :
880 : #ifdef HAVE_TIFF
881 179 : eErr = GTIFFBuildOverviews(
882 : osOvrFilename, nBands, pahBands, nNewOverviews, panNewOverviewList,
883 : pszResampling, GDALScaledProgress, pScaledProgress, papszOptions);
884 :
885 : // Probe for proxy overview filename.
886 179 : if (eErr == CE_Failure)
887 : {
888 : const char *pszProxyOvrFilename =
889 5 : poDS->GetMetadataItem("FILENAME", "ProxyOverviewRequest");
890 :
891 5 : if (pszProxyOvrFilename != nullptr)
892 : {
893 1 : osOvrFilename = pszProxyOvrFilename;
894 1 : eErr = GTIFFBuildOverviews(osOvrFilename, nBands, pahBands,
895 : nNewOverviews, panNewOverviewList,
896 : pszResampling, GDALScaledProgress,
897 : pScaledProgress, papszOptions);
898 : }
899 : }
900 :
901 179 : if (eErr == CE_None)
902 : {
903 175 : poODS = GDALDataset::Open(osOvrFilename,
904 : GDAL_OF_RASTER | GDAL_OF_UPDATE);
905 175 : if (poODS == nullptr)
906 0 : eErr = CE_Failure;
907 : }
908 : #else
909 : CPLError(CE_Failure, CPLE_NotSupported,
910 : "Cannot build TIFF overviews due to GeoTIFF driver missing");
911 : eErr = CE_Failure;
912 : #endif
913 : }
914 :
915 187 : GDALDestroyScaledProgress(pScaledProgress);
916 :
917 : /* -------------------------------------------------------------------- */
918 : /* Refresh old overviews that were listed. */
919 : /* -------------------------------------------------------------------- */
920 : GDALRasterBand **papoOverviewBands =
921 187 : static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
922 :
923 485 : for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++)
924 : {
925 298 : poBand = poDS->GetRasterBand(panBandList[iBand]);
926 298 : if (poBand == nullptr)
927 : {
928 0 : eErr = CE_Failure;
929 0 : break;
930 : }
931 :
932 298 : nNewOverviews = 0;
933 596 : std::vector<bool> abAlreadyUsedOverviewBand(poBand->GetOverviewCount(),
934 596 : false);
935 :
936 751 : for (int i = 0; i < nOverviews; i++)
937 : {
938 453 : if (!abValidLevel[i] || !abRequireRefresh[i])
939 424 : continue;
940 :
941 47 : for (int j = 0; j < poBand->GetOverviewCount(); j++)
942 : {
943 47 : if (abAlreadyUsedOverviewBand[j])
944 16 : continue;
945 :
946 31 : GDALRasterBand *poOverview = poBand->GetOverview(j);
947 31 : if (poOverview == nullptr)
948 0 : continue;
949 :
950 31 : int bHasNoData = FALSE;
951 31 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
952 :
953 31 : if (bHasNoData)
954 2 : poOverview->SetNoDataValue(noDataValue);
955 :
956 31 : const int nOvFactor = GDALComputeOvFactor(
957 : poOverview->GetXSize(), poBand->GetXSize(),
958 : poOverview->GetYSize(), poBand->GetYSize());
959 :
960 36 : if (nOvFactor == panOverviewList[i] ||
961 5 : nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
962 : poBand->GetXSize(),
963 : poBand->GetYSize()))
964 : {
965 29 : abAlreadyUsedOverviewBand[j] = true;
966 29 : CPLAssert(nNewOverviews < poBand->GetOverviewCount());
967 29 : papoOverviewBands[nNewOverviews++] = poOverview;
968 29 : break;
969 : }
970 : }
971 : }
972 :
973 298 : if (nNewOverviews > 0)
974 : {
975 19 : const double dfOffset =
976 : dfAreaNewOverviews / dfAreaRefreshedOverviews;
977 19 : const double dfScale = 1.0 - dfOffset;
978 38 : pScaledProgress = GDALCreateScaledProgress(
979 19 : dfOffset + dfScale * iBand / nBands,
980 19 : dfOffset + dfScale * (iBand + 1) / nBands, GDALScaledProgress,
981 : pScaledOverviewWithoutMask);
982 19 : eErr = GDALRegenerateOverviewsEx(
983 : GDALRasterBand::ToHandle(poBand), nNewOverviews,
984 : reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
985 : pszResampling, GDALScaledProgress, pScaledProgress,
986 : papszOptions);
987 19 : GDALDestroyScaledProgress(pScaledProgress);
988 : }
989 : }
990 :
991 : /* -------------------------------------------------------------------- */
992 : /* Cleanup */
993 : /* -------------------------------------------------------------------- */
994 187 : CPLFree(papoOverviewBands);
995 187 : CPLFree(panNewOverviewList);
996 187 : CPLFree(pahBands);
997 187 : GDALDestroyScaledProgress(pScaledOverviewWithoutMask);
998 :
999 : /* -------------------------------------------------------------------- */
1000 : /* If we have a mask file, we need to build its overviews too. */
1001 : /* -------------------------------------------------------------------- */
1002 187 : if (HaveMaskFile() && eErr == CE_None)
1003 : {
1004 4 : pScaledProgress = GDALCreateScaledProgress(
1005 2 : double(nBands) / (nBands + 1), 1.0, pfnProgress, pProgressData);
1006 2 : eErr = BuildOverviewsMask(pszResampling, nOverviews, panOverviewList,
1007 : GDALScaledProgress, pScaledProgress,
1008 : papszOptions);
1009 2 : GDALDestroyScaledProgress(pScaledProgress);
1010 : }
1011 :
1012 : /* -------------------------------------------------------------------- */
1013 : /* If we have an overview dataset, then mark all the overviews */
1014 : /* with the base dataset Used later for finding overviews */
1015 : /* masks. Uggg. */
1016 : /* -------------------------------------------------------------------- */
1017 187 : if (poODS)
1018 : {
1019 183 : const int nOverviewCount = GetOverviewCount(1);
1020 :
1021 444 : for (int iOver = 0; iOver < nOverviewCount; iOver++)
1022 : {
1023 261 : GDALRasterBand *poOtherBand = GetOverview(1, iOver);
1024 : GDALDataset *poOverDS =
1025 261 : poOtherBand != nullptr ? poOtherBand->GetDataset() : nullptr;
1026 :
1027 261 : if (poOverDS != nullptr)
1028 : {
1029 247 : poOverDS->oOvManager.poBaseDS = poDS;
1030 247 : poOverDS->oOvManager.poDS = poOverDS;
1031 : }
1032 : }
1033 : }
1034 :
1035 187 : return eErr;
1036 : }
1037 :
1038 : /************************************************************************/
1039 : /* BuildOverviewsMask() */
1040 : /************************************************************************/
1041 :
1042 4 : CPLErr GDALDefaultOverviews::BuildOverviewsMask(const char *pszResampling,
1043 : int nOverviews,
1044 : const int *panOverviewList,
1045 : GDALProgressFunc pfnProgress,
1046 : void *pProgressData,
1047 : CSLConstList papszOptions)
1048 : {
1049 4 : CPLErr eErr = CE_None;
1050 4 : if (HaveMaskFile() && poMaskDS)
1051 : {
1052 : // Some options are not compatible with mask overviews
1053 : // so unset them, and define more sensible values.
1054 4 : CPLStringList aosMaskOptions(papszOptions);
1055 : const char *pszCompress =
1056 4 : GetOptionValue(papszOptions, "COMPRESS", "COMPRESS_OVERVIEW");
1057 4 : const bool bJPEG = pszCompress && EQUAL(pszCompress, "JPEG");
1058 : const char *pszPhotometric =
1059 4 : GetOptionValue(papszOptions, "PHOTOMETRIC", "PHOTOMETRIC_OVERVIEW");
1060 4 : const bool bPHOTOMETRIC_YCBCR =
1061 4 : pszPhotometric && EQUAL(pszPhotometric, "YCBCR");
1062 4 : if (bJPEG)
1063 0 : aosMaskOptions.SetNameValue("COMPRESS", "DEFLATE");
1064 4 : if (bPHOTOMETRIC_YCBCR)
1065 0 : aosMaskOptions.SetNameValue("PHOTOMETRIC", "MINISBLACK");
1066 :
1067 4 : eErr = poMaskDS->BuildOverviews(
1068 : pszResampling, nOverviews, panOverviewList, 0, nullptr, pfnProgress,
1069 4 : pProgressData, aosMaskOptions.List());
1070 :
1071 4 : if (bOwnMaskDS)
1072 : {
1073 : // Reset the poMask member of main dataset bands, since it
1074 : // will become invalid after poMaskDS closing.
1075 10 : for (int iBand = 1; iBand <= poDS->GetRasterCount(); iBand++)
1076 : {
1077 6 : GDALRasterBand *poOtherBand = poDS->GetRasterBand(iBand);
1078 6 : if (poOtherBand != nullptr)
1079 6 : poOtherBand->InvalidateMaskBand();
1080 : }
1081 :
1082 4 : GDALClose(poMaskDS);
1083 : }
1084 :
1085 : // force next request to reread mask file.
1086 4 : poMaskDS = nullptr;
1087 4 : bOwnMaskDS = false;
1088 4 : bCheckedForMask = false;
1089 : }
1090 :
1091 4 : return eErr;
1092 : }
1093 :
1094 : /************************************************************************/
1095 : /* CreateMaskBand() */
1096 : /************************************************************************/
1097 :
1098 26 : CPLErr GDALDefaultOverviews::CreateMaskBand(int nFlags, int nBand)
1099 :
1100 : {
1101 26 : if (nBand < 1)
1102 17 : nFlags |= GMF_PER_DATASET;
1103 :
1104 : /* -------------------------------------------------------------------- */
1105 : /* ensure existing file gets opened if there is one. */
1106 : /* -------------------------------------------------------------------- */
1107 26 : CPL_IGNORE_RET_VAL(HaveMaskFile());
1108 :
1109 : /* -------------------------------------------------------------------- */
1110 : /* Try creating the mask file. */
1111 : /* -------------------------------------------------------------------- */
1112 26 : if (poMaskDS == nullptr)
1113 : {
1114 : GDALDriver *const poDr =
1115 21 : static_cast<GDALDriver *>(GDALGetDriverByName("GTiff"));
1116 :
1117 21 : if (poDr == nullptr)
1118 0 : return CE_Failure;
1119 :
1120 21 : GDALRasterBand *const poTBand = poDS->GetRasterBand(1);
1121 21 : if (poTBand == nullptr)
1122 0 : return CE_Failure;
1123 :
1124 : const int nBands =
1125 21 : (nFlags & GMF_PER_DATASET) ? 1 : poDS->GetRasterCount();
1126 :
1127 21 : char **papszOpt = CSLSetNameValue(nullptr, "COMPRESS", "DEFLATE");
1128 21 : papszOpt = CSLSetNameValue(papszOpt, "INTERLEAVE", "BAND");
1129 :
1130 21 : int nBX = 0;
1131 21 : int nBY = 0;
1132 21 : poTBand->GetBlockSize(&nBX, &nBY);
1133 :
1134 : // Try to create matching tile size if legal in TIFF.
1135 21 : if ((nBX % 16) == 0 && (nBY % 16) == 0)
1136 : {
1137 2 : papszOpt = CSLSetNameValue(papszOpt, "TILED", "YES");
1138 2 : papszOpt = CSLSetNameValue(papszOpt, "BLOCKXSIZE",
1139 4 : CPLString().Printf("%d", nBX));
1140 2 : papszOpt = CSLSetNameValue(papszOpt, "BLOCKYSIZE",
1141 4 : CPLString().Printf("%d", nBY));
1142 : }
1143 :
1144 21 : CPLString osMskFilename;
1145 21 : osMskFilename.Printf("%s.msk", poDS->GetDescription());
1146 21 : poMaskDS =
1147 21 : poDr->Create(osMskFilename, poDS->GetRasterXSize(),
1148 21 : poDS->GetRasterYSize(), nBands, GDT_Byte, papszOpt);
1149 21 : CSLDestroy(papszOpt);
1150 :
1151 21 : if (poMaskDS == nullptr) // Presumably error already issued.
1152 0 : return CE_Failure;
1153 :
1154 21 : bOwnMaskDS = true;
1155 : }
1156 :
1157 : /* -------------------------------------------------------------------- */
1158 : /* Save the mask flags for this band. */
1159 : /* -------------------------------------------------------------------- */
1160 26 : if (nBand > poMaskDS->GetRasterCount())
1161 : {
1162 1 : CPLError(CE_Failure, CPLE_AppDefined,
1163 : "Attempt to create a mask band for band %d of %s, "
1164 : "but the .msk file has a PER_DATASET mask.",
1165 1 : nBand, poDS->GetDescription());
1166 1 : return CE_Failure;
1167 : }
1168 :
1169 67 : for (int iBand = 0; iBand < poDS->GetRasterCount(); iBand++)
1170 : {
1171 : // we write only the info for this band, unless we are
1172 : // using PER_DATASET in which case we write for all.
1173 42 : if (nBand != iBand + 1 && !(nFlags & GMF_PER_DATASET))
1174 6 : continue;
1175 :
1176 36 : poMaskDS->SetMetadataItem(
1177 72 : CPLString().Printf("INTERNAL_MASK_FLAGS_%d", iBand + 1),
1178 72 : CPLString().Printf("%d", nFlags));
1179 : }
1180 :
1181 25 : return CE_None;
1182 : }
1183 :
1184 : /************************************************************************/
1185 : /* GetMaskBand() */
1186 : /************************************************************************/
1187 :
1188 : // Secret code meaning we don't handle this band.
1189 : constexpr int MISSING_FLAGS = 0x8000;
1190 :
1191 46 : GDALRasterBand *GDALDefaultOverviews::GetMaskBand(int nBand)
1192 :
1193 : {
1194 46 : const int nFlags = GetMaskFlags(nBand);
1195 :
1196 46 : if (poMaskDS == nullptr || nFlags == MISSING_FLAGS)
1197 1 : return nullptr;
1198 :
1199 45 : if (nFlags & GMF_PER_DATASET)
1200 36 : return poMaskDS->GetRasterBand(1);
1201 :
1202 9 : if (nBand > 0)
1203 9 : return poMaskDS->GetRasterBand(nBand);
1204 :
1205 0 : return nullptr;
1206 : }
1207 :
1208 : /************************************************************************/
1209 : /* GetMaskFlags() */
1210 : /************************************************************************/
1211 :
1212 90 : int GDALDefaultOverviews::GetMaskFlags(int nBand)
1213 :
1214 : {
1215 : /* -------------------------------------------------------------------- */
1216 : /* Fetch this band's metadata entry. They are of the form: */
1217 : /* INTERNAL_MASK_FLAGS_n: flags */
1218 : /* -------------------------------------------------------------------- */
1219 90 : if (!HaveMaskFile())
1220 0 : return 0;
1221 :
1222 90 : const char *pszValue = poMaskDS->GetMetadataItem(
1223 180 : CPLString().Printf("INTERNAL_MASK_FLAGS_%d", std::max(nBand, 1)));
1224 :
1225 90 : if (pszValue == nullptr)
1226 1 : return MISSING_FLAGS;
1227 :
1228 89 : return atoi(pszValue);
1229 : }
1230 :
1231 : /************************************************************************/
1232 : /* HaveMaskFile() */
1233 : /* */
1234 : /* Check for a mask file if we haven't already done so. */
1235 : /* Returns TRUE if we have one, otherwise FALSE. */
1236 : /************************************************************************/
1237 :
1238 32979 : int GDALDefaultOverviews::HaveMaskFile(char **papszSiblingFiles,
1239 : const char *pszBasename)
1240 :
1241 : {
1242 : /* -------------------------------------------------------------------- */
1243 : /* Have we already checked for masks? */
1244 : /* -------------------------------------------------------------------- */
1245 32979 : if (bCheckedForMask)
1246 3615 : return poMaskDS != nullptr;
1247 :
1248 29364 : if (papszSiblingFiles == nullptr)
1249 29364 : papszSiblingFiles = papszInitSiblingFiles;
1250 :
1251 : /* -------------------------------------------------------------------- */
1252 : /* Are we an overview? If so we need to find the corresponding */
1253 : /* overview in the base files mask file (if there is one). */
1254 : /* -------------------------------------------------------------------- */
1255 29364 : if (poBaseDS != nullptr && poBaseDS->oOvManager.HaveMaskFile())
1256 : {
1257 4 : GDALRasterBand *const poBaseBand = poBaseDS->GetRasterBand(1);
1258 4 : GDALDataset *poMaskDSTemp = nullptr;
1259 4 : if (poBaseBand != nullptr)
1260 : {
1261 4 : GDALRasterBand *poBaseMask = poBaseBand->GetMaskBand();
1262 4 : if (poBaseMask != nullptr)
1263 : {
1264 4 : const int nOverviewCount = poBaseMask->GetOverviewCount();
1265 6 : for (int iOver = 0; iOver < nOverviewCount; iOver++)
1266 : {
1267 : GDALRasterBand *const poOverBand =
1268 6 : poBaseMask->GetOverview(iOver);
1269 6 : if (poOverBand == nullptr)
1270 0 : continue;
1271 :
1272 10 : if (poOverBand->GetXSize() == poDS->GetRasterXSize() &&
1273 4 : poOverBand->GetYSize() == poDS->GetRasterYSize())
1274 : {
1275 4 : poMaskDSTemp = poOverBand->GetDataset();
1276 4 : break;
1277 : }
1278 : }
1279 : }
1280 : }
1281 :
1282 4 : if (poMaskDSTemp != poDS)
1283 : {
1284 4 : poMaskDS = poMaskDSTemp;
1285 4 : bCheckedForMask = true;
1286 4 : bOwnMaskDS = false;
1287 :
1288 4 : return poMaskDS != nullptr;
1289 : }
1290 : }
1291 :
1292 : /* -------------------------------------------------------------------- */
1293 : /* Are we even initialized? If not, we apparently don't want */
1294 : /* to support overviews and masks. */
1295 : /* -------------------------------------------------------------------- */
1296 29360 : if (poDS == nullptr)
1297 19533 : return FALSE;
1298 :
1299 : /* -------------------------------------------------------------------- */
1300 : /* Check for .msk file. */
1301 : /* -------------------------------------------------------------------- */
1302 9827 : bCheckedForMask = true;
1303 :
1304 9827 : if (pszBasename == nullptr)
1305 9827 : pszBasename = poDS->GetDescription();
1306 :
1307 : // Don't bother checking for masks of masks.
1308 9827 : if (EQUAL(CPLGetExtension(pszBasename), "msk"))
1309 20 : return FALSE;
1310 :
1311 9807 : if (!GDALCanFileAcceptSidecarFile(pszBasename))
1312 1 : return FALSE;
1313 19612 : CPLString osMskFilename;
1314 9806 : osMskFilename.Printf("%s.msk", pszBasename);
1315 :
1316 19612 : std::vector<char> achMskFilename;
1317 9806 : achMskFilename.resize(osMskFilename.size() + 1);
1318 9806 : memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
1319 9806 : osMskFilename.size() + 1);
1320 : bool bExists =
1321 9806 : CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
1322 9806 : osMskFilename = &achMskFilename[0];
1323 :
1324 : #if !defined(_WIN32)
1325 9806 : if (!bExists && !papszSiblingFiles)
1326 : {
1327 2359 : osMskFilename.Printf("%s.MSK", pszBasename);
1328 2359 : memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
1329 2359 : osMskFilename.size() + 1);
1330 : bExists =
1331 2359 : CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
1332 2359 : osMskFilename = &achMskFilename[0];
1333 : }
1334 : #endif
1335 :
1336 9806 : if (!bExists)
1337 9769 : return FALSE;
1338 :
1339 : /* -------------------------------------------------------------------- */
1340 : /* Open the file. */
1341 : /* -------------------------------------------------------------------- */
1342 37 : poMaskDS = GDALDataset::Open(
1343 : osMskFilename,
1344 37 : GDAL_OF_RASTER | (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
1345 37 : nullptr, nullptr, papszInitSiblingFiles);
1346 37 : CPLAssert(poMaskDS != poDS);
1347 :
1348 37 : if (poMaskDS == nullptr)
1349 1 : return FALSE;
1350 :
1351 36 : bOwnMaskDS = true;
1352 :
1353 36 : return TRUE;
1354 : }
1355 :
1356 : /************************************************************************/
1357 : /* GDALGetNormalizedOvrResampling() */
1358 : /************************************************************************/
1359 :
1360 894 : std::string GDALGetNormalizedOvrResampling(const char *pszResampling)
1361 : {
1362 894 : if (pszResampling &&
1363 894 : EQUAL(pszResampling, "AVERAGE_BIT2GRAYSCALE_MINISWHITE"))
1364 0 : return "AVERAGE_BIT2GRAYSCALE_MINISWHITE";
1365 894 : else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2"))
1366 8 : return "AVERAGE_BIT2GRAYSCALE";
1367 886 : else if (pszResampling && STARTS_WITH_CI(pszResampling, "NEAR"))
1368 370 : return "NEAREST";
1369 516 : else if (pszResampling && EQUAL(pszResampling, "AVERAGE_MAGPHASE"))
1370 0 : return "AVERAGE_MAGPHASE";
1371 516 : else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVER"))
1372 243 : return "AVERAGE";
1373 273 : else if (pszResampling && !EQUAL(pszResampling, "NONE"))
1374 : {
1375 310 : return CPLString(pszResampling).toupper();
1376 : }
1377 118 : return std::string();
1378 : }
1379 :
1380 : //! @endcond
|