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 <limits>
24 : #include <set>
25 : #include <string>
26 : #include <vector>
27 :
28 : #ifdef HAVE_TIFF
29 : #include "tiffio.h"
30 : #include "gt_overview.h"
31 : #endif
32 :
33 : #include "cpl_conv.h"
34 : #include "cpl_error.h"
35 : #include "cpl_progress.h"
36 : #include "cpl_string.h"
37 : #include "cpl_vsi.h"
38 : #include "gdal.h"
39 :
40 : //! @cond Doxygen_Suppress
41 : /************************************************************************/
42 : /* GDALDefaultOverviews() */
43 : /************************************************************************/
44 :
45 217647 : GDALDefaultOverviews::GDALDefaultOverviews()
46 : : poDS(nullptr), poODS(nullptr), bOvrIsAux(false), bCheckedForMask(false),
47 : bOwnMaskDS(false), poMaskDS(nullptr), poBaseDS(nullptr),
48 : bCheckedForOverviews(FALSE), pszInitName(nullptr), bInitNameIsOVR(false),
49 217647 : papszInitSiblingFiles(nullptr)
50 : {
51 217647 : }
52 :
53 : /************************************************************************/
54 : /* ~GDALDefaultOverviews() */
55 : /************************************************************************/
56 :
57 217620 : GDALDefaultOverviews::~GDALDefaultOverviews()
58 :
59 : {
60 217620 : CPLFree(pszInitName);
61 217620 : CSLDestroy(papszInitSiblingFiles);
62 :
63 217620 : CloseDependentDatasets();
64 217620 : }
65 :
66 : /************************************************************************/
67 : /* CloseDependentDatasets() */
68 : /************************************************************************/
69 :
70 237629 : int GDALDefaultOverviews::CloseDependentDatasets()
71 : {
72 237629 : bool bHasDroppedRef = false;
73 237629 : if (poODS != nullptr)
74 : {
75 408 : bHasDroppedRef = true;
76 408 : poODS->FlushCache(true);
77 408 : GDALClose(poODS);
78 408 : poODS = nullptr;
79 : }
80 :
81 237629 : if (poMaskDS != nullptr)
82 : {
83 58 : if (bOwnMaskDS)
84 : {
85 54 : bHasDroppedRef = true;
86 54 : poMaskDS->FlushCache(true);
87 54 : GDALClose(poMaskDS);
88 : }
89 58 : poMaskDS = nullptr;
90 : }
91 :
92 237629 : return bHasDroppedRef;
93 : }
94 :
95 : /************************************************************************/
96 : /* IsInitialized() */
97 : /* */
98 : /* Returns TRUE if we are initialized. */
99 : /************************************************************************/
100 :
101 1093040 : int GDALDefaultOverviews::IsInitialized()
102 :
103 : {
104 1093040 : OverviewScan();
105 1093040 : return poDS != nullptr;
106 : }
107 :
108 : /************************************************************************/
109 : /* Initialize() */
110 : /************************************************************************/
111 :
112 56627 : void GDALDefaultOverviews::Initialize(GDALDataset *poDSIn,
113 : const char *pszBasename,
114 : CSLConstList papszSiblingFiles,
115 : bool bNameIsOVR)
116 :
117 : {
118 56627 : poDS = poDSIn;
119 :
120 : /* -------------------------------------------------------------------- */
121 : /* If we were already initialized, destroy the old overview */
122 : /* file handle. */
123 : /* -------------------------------------------------------------------- */
124 56627 : if (poODS != nullptr)
125 : {
126 0 : GDALClose(poODS);
127 0 : poODS = nullptr;
128 :
129 0 : CPLDebug("GDAL", "GDALDefaultOverviews::Initialize() called twice - "
130 : "this is odd and perhaps dangerous!");
131 : }
132 :
133 : /* -------------------------------------------------------------------- */
134 : /* Store the initialization information for later use in */
135 : /* OverviewScan() */
136 : /* -------------------------------------------------------------------- */
137 56627 : bCheckedForOverviews = FALSE;
138 :
139 56627 : CPLFree(pszInitName);
140 56627 : pszInitName = nullptr;
141 56627 : if (pszBasename != nullptr)
142 56626 : pszInitName = CPLStrdup(pszBasename);
143 56627 : bInitNameIsOVR = bNameIsOVR;
144 :
145 56627 : CSLDestroy(papszInitSiblingFiles);
146 56627 : papszInitSiblingFiles = nullptr;
147 56627 : if (papszSiblingFiles != nullptr)
148 6725 : papszInitSiblingFiles = CSLDuplicate(papszSiblingFiles);
149 56627 : }
150 :
151 : /************************************************************************/
152 : /* Initialize() */
153 : /************************************************************************/
154 :
155 : /** Initialize the GDALDefaultOverviews instance.
156 : *
157 : * @param poDSIn Base dataset.
158 : * @param poOpenInfo Open info instance. Must not be NULL.
159 : * @param pszName Base dataset name. If set to NULL, poOpenInfo->pszFilename is
160 : * used.
161 : * @param bTransferSiblingFilesIfLoaded Whether sibling files of poOpenInfo
162 : * should be transferred to this
163 : * GDALDefaultOverviews instance, if they
164 : * have bean already loaded.
165 : * @since 3.10
166 : */
167 35221 : void GDALDefaultOverviews::Initialize(GDALDataset *poDSIn,
168 : GDALOpenInfo *poOpenInfo,
169 : const char *pszName,
170 : bool bTransferSiblingFilesIfLoaded)
171 : {
172 35221 : Initialize(poDSIn, pszName ? pszName : poOpenInfo->pszFilename);
173 :
174 35221 : if (bTransferSiblingFilesIfLoaded && poOpenInfo->AreSiblingFilesLoaded())
175 11088 : TransferSiblingFiles(poOpenInfo->StealSiblingFiles());
176 35221 : }
177 :
178 : /************************************************************************/
179 : /* TransferSiblingFiles() */
180 : /* */
181 : /* Contrary to Initialize(), this sets papszInitSiblingFiles but */
182 : /* without duplicating the passed list. Which must be */
183 : /* "de-allocatable" with CSLDestroy() */
184 : /************************************************************************/
185 :
186 28694 : void GDALDefaultOverviews::TransferSiblingFiles(char **papszSiblingFiles)
187 : {
188 28694 : CSLDestroy(papszInitSiblingFiles);
189 28694 : papszInitSiblingFiles = papszSiblingFiles;
190 28694 : }
191 :
192 : namespace
193 : {
194 : // Prevent infinite recursion.
195 : struct AntiRecursionStructDefaultOvr
196 : {
197 : int nRecLevel = 0;
198 : std::set<CPLString> oSetFiles{};
199 : };
200 : } // namespace
201 :
202 444 : static void FreeAntiRecursionDefaultOvr(void *pData)
203 : {
204 444 : delete static_cast<AntiRecursionStructDefaultOvr *>(pData);
205 444 : }
206 :
207 12101 : static AntiRecursionStructDefaultOvr &GetAntiRecursionDefaultOvr()
208 : {
209 12101 : static AntiRecursionStructDefaultOvr dummy;
210 12101 : int bMemoryErrorOccurred = false;
211 : void *pData =
212 12101 : CPLGetTLSEx(CTLS_GDALDEFAULTOVR_ANTIREC, &bMemoryErrorOccurred);
213 12101 : if (bMemoryErrorOccurred)
214 : {
215 0 : return dummy;
216 : }
217 12101 : if (pData == nullptr)
218 : {
219 526 : auto pAntiRecursion = new AntiRecursionStructDefaultOvr();
220 526 : CPLSetTLSWithFreeFuncEx(CTLS_GDALDEFAULTOVR_ANTIREC, pAntiRecursion,
221 : FreeAntiRecursionDefaultOvr,
222 : &bMemoryErrorOccurred);
223 526 : if (bMemoryErrorOccurred)
224 : {
225 0 : delete pAntiRecursion;
226 0 : return dummy;
227 : }
228 526 : return *pAntiRecursion;
229 : }
230 11575 : return *static_cast<AntiRecursionStructDefaultOvr *>(pData);
231 : }
232 :
233 : /************************************************************************/
234 : /* OverviewScan() */
235 : /* */
236 : /* This is called to scan for overview files when a first */
237 : /* request is made with regard to overviews. It uses the */
238 : /* pszInitName, bInitNameIsOVR and papszInitSiblingFiles */
239 : /* information that was stored at Initialization() time. */
240 : /************************************************************************/
241 :
242 1093040 : void GDALDefaultOverviews::OverviewScan()
243 :
244 : {
245 1093040 : if (bCheckedForOverviews || poDS == nullptr)
246 1080940 : return;
247 :
248 12101 : bCheckedForOverviews = true;
249 12101 : if (pszInitName == nullptr)
250 0 : pszInitName = CPLStrdup(poDS->GetDescription());
251 :
252 12101 : AntiRecursionStructDefaultOvr &antiRec = GetAntiRecursionDefaultOvr();
253 : // 32 should be enough to handle a .ovr.ovr.ovr...
254 12101 : if (antiRec.nRecLevel == 32)
255 0 : return;
256 12101 : if (antiRec.oSetFiles.find(pszInitName) != antiRec.oSetFiles.end())
257 0 : return;
258 12101 : antiRec.oSetFiles.insert(pszInitName);
259 12101 : ++antiRec.nRecLevel;
260 :
261 12101 : CPLDebug("GDAL", "GDALDefaultOverviews::OverviewScan()");
262 :
263 : /* -------------------------------------------------------------------- */
264 : /* Open overview dataset if it exists. */
265 : /* -------------------------------------------------------------------- */
266 24011 : if (!EQUAL(pszInitName, ":::VIRTUAL:::") &&
267 11910 : GDALCanFileAcceptSidecarFile(pszInitName))
268 : {
269 11908 : if (bInitNameIsOVR)
270 0 : osOvrFilename = pszInitName;
271 : else
272 11908 : osOvrFilename.Printf("%s.ovr", pszInitName);
273 :
274 23816 : std::vector<char> achOvrFilename;
275 11908 : achOvrFilename.resize(osOvrFilename.size() + 1);
276 11908 : memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
277 11908 : osOvrFilename.size() + 1);
278 11908 : bool bExists = CPL_TO_BOOL(
279 11908 : CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
280 11908 : osOvrFilename = &achOvrFilename[0];
281 :
282 : #if !defined(_WIN32)
283 11908 : if (!bInitNameIsOVR && !bExists && !papszInitSiblingFiles)
284 : {
285 3079 : osOvrFilename.Printf("%s.OVR", pszInitName);
286 3079 : memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
287 3079 : osOvrFilename.size() + 1);
288 3079 : bExists = CPL_TO_BOOL(
289 3079 : CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
290 3079 : osOvrFilename = &achOvrFilename[0];
291 3079 : if (!bExists)
292 3079 : osOvrFilename.Printf("%s.ovr", pszInitName);
293 : }
294 : #endif
295 :
296 11908 : if (bExists)
297 : {
298 205 : poODS = GDALDataset::Open(
299 : osOvrFilename,
300 : GDAL_OF_RASTER |
301 205 : (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
302 205 : nullptr, nullptr, papszInitSiblingFiles);
303 : }
304 : }
305 :
306 : /* -------------------------------------------------------------------- */
307 : /* We didn't find that, so try and find a corresponding aux */
308 : /* file. Check that we are the dependent file of the aux */
309 : /* file. */
310 : /* */
311 : /* We only use the .aux file for overviews if they already have */
312 : /* overviews existing, or if USE_RRD is set true. */
313 : /* -------------------------------------------------------------------- */
314 23807 : if (!poODS && !EQUAL(pszInitName, ":::VIRTUAL:::") &&
315 11706 : GDALCanFileAcceptSidecarFile(pszInitName))
316 : {
317 11704 : bool bTryFindAssociatedAuxFile = true;
318 11704 : if (papszInitSiblingFiles)
319 : {
320 17250 : CPLString osAuxFilename = CPLResetExtensionSafe(pszInitName, "aux");
321 8625 : int iSibling = CSLFindString(papszInitSiblingFiles,
322 : CPLGetFilename(osAuxFilename));
323 8625 : if (iSibling < 0)
324 : {
325 8621 : osAuxFilename = pszInitName;
326 8621 : osAuxFilename += ".aux";
327 8621 : iSibling = CSLFindString(papszInitSiblingFiles,
328 : CPLGetFilename(osAuxFilename));
329 8621 : if (iSibling < 0)
330 8621 : bTryFindAssociatedAuxFile = false;
331 : }
332 : }
333 :
334 11704 : if (bTryFindAssociatedAuxFile)
335 : {
336 3083 : poODS =
337 3083 : GDALFindAssociatedAuxFile(pszInitName, poDS->GetAccess(), poDS);
338 : }
339 :
340 11704 : if (poODS)
341 : {
342 : const bool bUseRRD =
343 8 : CPLTestBool(CPLGetConfigOption("USE_RRD", "NO"));
344 :
345 8 : bOvrIsAux = true;
346 8 : if (GetOverviewCount(1) == 0 && !bUseRRD)
347 : {
348 1 : bOvrIsAux = false;
349 1 : GDALClose(poODS);
350 1 : poODS = nullptr;
351 : }
352 : else
353 : {
354 7 : osOvrFilename = poODS->GetDescription();
355 : }
356 : }
357 : }
358 :
359 : /* -------------------------------------------------------------------- */
360 : /* If we still don't have an overview, check to see if we have */
361 : /* overview metadata referencing a remote (i.e. proxy) or local */
362 : /* subdataset overview dataset. */
363 : /* -------------------------------------------------------------------- */
364 12101 : if (poODS == nullptr)
365 : {
366 : const char *pszProxyOvrFilename =
367 11890 : poDS->GetMetadataItem("OVERVIEW_FILE", "OVERVIEWS");
368 :
369 11890 : if (pszProxyOvrFilename != nullptr)
370 : {
371 25 : if (STARTS_WITH_CI(pszProxyOvrFilename, ":::BASE:::"))
372 : {
373 0 : const CPLString osPath = CPLGetPathSafe(poDS->GetDescription());
374 :
375 0 : osOvrFilename = CPLFormFilenameSafe(
376 0 : osPath, pszProxyOvrFilename + 10, nullptr);
377 : }
378 : else
379 : {
380 25 : osOvrFilename = pszProxyOvrFilename;
381 : }
382 :
383 : // Exclude TILEDB because reading from /vsis3/ can be really slow
384 25 : const char *const apszAllowedDrivers[] = {"-TILEDB", nullptr};
385 25 : CPLPushErrorHandler(CPLQuietErrorHandler);
386 25 : poODS = GDALDataset::Open(
387 : osOvrFilename,
388 : GDAL_OF_RASTER |
389 25 : (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
390 : apszAllowedDrivers);
391 25 : CPLPopErrorHandler();
392 : }
393 : }
394 :
395 : /* -------------------------------------------------------------------- */
396 : /* If we have an overview dataset, then mark all the overviews */
397 : /* with the base dataset Used later for finding overviews */
398 : /* masks. Uggg. */
399 : /* -------------------------------------------------------------------- */
400 12101 : if (poODS)
401 : {
402 232 : const int nOverviewCount = GetOverviewCount(1);
403 :
404 552 : for (int iOver = 0; iOver < nOverviewCount; iOver++)
405 : {
406 320 : GDALRasterBand *const poBand = GetOverview(1, iOver);
407 : GDALDataset *const poOverDS =
408 320 : poBand != nullptr ? poBand->GetDataset() : nullptr;
409 :
410 320 : if (poOverDS != nullptr)
411 : {
412 308 : poOverDS->oOvManager.poBaseDS = poDS;
413 308 : poOverDS->oOvManager.poDS = poOverDS;
414 : }
415 : }
416 : }
417 :
418 : // Undo anti recursion protection
419 12101 : antiRec.oSetFiles.erase(pszInitName);
420 12101 : --antiRec.nRecLevel;
421 : }
422 :
423 : /************************************************************************/
424 : /* GetOverviewCount() */
425 : /************************************************************************/
426 :
427 657913 : int GDALDefaultOverviews::GetOverviewCount(int nBand)
428 :
429 : {
430 657913 : if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
431 656800 : return 0;
432 :
433 1113 : GDALRasterBand *poBand = poODS->GetRasterBand(nBand);
434 1113 : if (poBand == nullptr)
435 0 : return 0;
436 :
437 1113 : if (bOvrIsAux)
438 79 : return poBand->GetOverviewCount();
439 :
440 1034 : return poBand->GetOverviewCount() + 1;
441 : }
442 :
443 : /************************************************************************/
444 : /* GetOverview() */
445 : /************************************************************************/
446 :
447 1481 : GDALRasterBand *GDALDefaultOverviews::GetOverview(int nBand, int iOverview)
448 :
449 : {
450 1481 : if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
451 284 : return nullptr;
452 :
453 1197 : GDALRasterBand *const poBand = poODS->GetRasterBand(nBand);
454 1197 : if (poBand == nullptr)
455 0 : return nullptr;
456 :
457 1197 : if (bOvrIsAux)
458 63 : return poBand->GetOverview(iOverview);
459 :
460 : // TIFF case, base is overview 0.
461 1134 : if (iOverview == 0)
462 860 : return poBand;
463 :
464 274 : if (iOverview - 1 >= poBand->GetOverviewCount())
465 0 : return nullptr;
466 :
467 274 : return poBand->GetOverview(iOverview - 1);
468 : }
469 :
470 : /************************************************************************/
471 : /* GDALOvLevelAdjust() */
472 : /* */
473 : /* Some overview levels cannot be achieved closely enough to be */
474 : /* recognised as the desired overview level. This function */
475 : /* will adjust an overview level to one that is achievable on */
476 : /* the given raster size. */
477 : /* */
478 : /* For instance a 1200x1200 image on which a 256 level overview */
479 : /* is request will end up generating a 5x5 overview. However, */
480 : /* this will appear to the system be a level 240 overview. */
481 : /* This function will adjust 256 to 240 based on knowledge of */
482 : /* the image size. */
483 : /************************************************************************/
484 :
485 0 : int GDALOvLevelAdjust(int nOvLevel, int nXSize)
486 :
487 : {
488 0 : int nOXSize = DIV_ROUND_UP(nXSize, nOvLevel);
489 :
490 0 : return static_cast<int>(0.5 + nXSize / static_cast<double>(nOXSize));
491 : }
492 :
493 479 : int GDALOvLevelAdjust2(int nOvLevel, int nXSize, int nYSize)
494 :
495 : {
496 : // Select the larger dimension to have increased accuracy, but
497 : // with a slight preference to x even if (a bit) smaller than y
498 : // in an attempt to behave closer as previous behavior.
499 479 : if (nXSize >= nYSize / 2 && !(nXSize < nYSize && nXSize < nOvLevel))
500 : {
501 404 : const int nOXSize = DIV_ROUND_UP(nXSize, nOvLevel);
502 :
503 404 : return static_cast<int>(0.5 + nXSize / static_cast<double>(nOXSize));
504 : }
505 :
506 75 : const int nOYSize = DIV_ROUND_UP(nYSize, nOvLevel);
507 :
508 75 : return static_cast<int>(0.5 + nYSize / static_cast<double>(nOYSize));
509 : }
510 :
511 : /************************************************************************/
512 : /* GetFloorPowerOfTwo() */
513 : /************************************************************************/
514 :
515 67491 : static int GetFloorPowerOfTwo(int n)
516 : {
517 67491 : int p2 = 1;
518 136188 : while ((n = n >> 1) > 0)
519 : {
520 68697 : p2 <<= 1;
521 : }
522 67491 : return p2;
523 : }
524 :
525 : /************************************************************************/
526 : /* GDALComputeOvFactor() */
527 : /************************************************************************/
528 :
529 67491 : int GDALComputeOvFactor(int nOvrXSize, int nRasterXSize, int nOvrYSize,
530 : int nRasterYSize)
531 : {
532 : // Select the larger dimension to have increased accuracy, but
533 : // with a slight preference to x even if (a bit) smaller than y
534 : // in an attempt to behave closer as previous behavior.
535 67491 : if (nRasterXSize != 1 && nRasterXSize >= nRasterYSize / 2)
536 : {
537 67377 : const int nVal = static_cast<int>(
538 67377 : 0.5 + nRasterXSize / static_cast<double>(nOvrXSize));
539 : // Try to return a power-of-two value
540 67377 : const int nValPowerOfTwo = GetFloorPowerOfTwo(nVal);
541 67565 : for (int fact = 1; fact <= 2 && nValPowerOfTwo <= INT_MAX / fact;
542 : ++fact)
543 : {
544 67532 : if (DIV_ROUND_UP(nRasterXSize, fact * nValPowerOfTwo) == nOvrXSize)
545 67344 : return fact * nValPowerOfTwo;
546 : }
547 33 : return nVal;
548 : }
549 :
550 114 : const int nVal =
551 114 : static_cast<int>(0.5 + nRasterYSize / static_cast<double>(nOvrYSize));
552 : // Try to return a power-of-two value
553 114 : const int nValPowerOfTwo = GetFloorPowerOfTwo(nVal);
554 116 : for (int fact = 1; fact <= 2 && nValPowerOfTwo <= INT_MAX / fact; ++fact)
555 : {
556 115 : if (DIV_ROUND_UP(nRasterYSize, fact * nValPowerOfTwo) == nOvrYSize)
557 113 : return fact * nValPowerOfTwo;
558 : }
559 1 : return nVal;
560 : }
561 :
562 : /************************************************************************/
563 : /* CleanOverviews() */
564 : /* */
565 : /* Remove all existing overviews. */
566 : /************************************************************************/
567 :
568 10 : CPLErr GDALDefaultOverviews::CleanOverviews()
569 :
570 : {
571 : // Anything to do?
572 10 : if (poODS == nullptr)
573 1 : return CE_None;
574 :
575 : // Delete the overview file(s).
576 9 : GDALDriver *poOvrDriver = poODS->GetDriver();
577 9 : GDALClose(poODS);
578 9 : poODS = nullptr;
579 :
580 : CPLErr eErr =
581 9 : poOvrDriver != nullptr ? poOvrDriver->Delete(osOvrFilename) : CE_None;
582 :
583 : // Reset the saved overview filename.
584 9 : if (!EQUAL(poDS->GetDescription(), ":::VIRTUAL:::"))
585 : {
586 9 : const bool bUseRRD = CPLTestBool(CPLGetConfigOption("USE_RRD", "NO"));
587 :
588 9 : if (bUseRRD)
589 : osOvrFilename =
590 0 : CPLResetExtensionSafe(poDS->GetDescription(), "aux");
591 : else
592 9 : osOvrFilename = std::string(poDS->GetDescription()).append(".ovr");
593 : }
594 : else
595 : {
596 0 : osOvrFilename = "";
597 : }
598 :
599 9 : if (HaveMaskFile() && poMaskDS)
600 : {
601 1 : const CPLErr eErr2 = poMaskDS->BuildOverviews(
602 : nullptr, 0, nullptr, 0, nullptr, nullptr, nullptr, nullptr);
603 1 : if (eErr2 != CE_None)
604 0 : return eErr2;
605 : }
606 :
607 9 : return eErr;
608 : }
609 :
610 : /************************************************************************/
611 : /* BuildOverviewsSubDataset() */
612 : /************************************************************************/
613 :
614 10 : CPLErr GDALDefaultOverviews::BuildOverviewsSubDataset(
615 : const char *pszPhysicalFile, const char *pszResampling, int nOverviews,
616 : const int *panOverviewList, int nBands, const int *panBandList,
617 : GDALProgressFunc pfnProgress, void *pProgressData,
618 : CSLConstList papszOptions)
619 :
620 : {
621 10 : if (osOvrFilename.length() == 0 && nOverviews > 0)
622 : {
623 : VSIStatBufL sStatBuf;
624 :
625 8 : int iSequence = 0; // Used after for.
626 9 : for (iSequence = 0; iSequence < 100; iSequence++)
627 : {
628 9 : osOvrFilename.Printf("%s_%d.ovr", pszPhysicalFile, iSequence);
629 9 : if (VSIStatExL(osOvrFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) != 0)
630 : {
631 16 : CPLString osAdjustedOvrFilename;
632 :
633 8 : if (poDS->GetMOFlags() & GMO_PAM_CLASS)
634 : {
635 : osAdjustedOvrFilename.Printf(
636 : ":::BASE:::%s_%d.ovr", CPLGetFilename(pszPhysicalFile),
637 8 : iSequence);
638 : }
639 : else
640 : {
641 0 : osAdjustedOvrFilename = osOvrFilename;
642 : }
643 :
644 8 : poDS->SetMetadataItem("OVERVIEW_FILE", osAdjustedOvrFilename,
645 8 : "OVERVIEWS");
646 8 : break;
647 : }
648 : }
649 :
650 8 : if (iSequence == 100)
651 0 : osOvrFilename = "";
652 : }
653 :
654 10 : return BuildOverviews(nullptr, pszResampling, nOverviews, panOverviewList,
655 : nBands, panBandList, pfnProgress, pProgressData,
656 10 : papszOptions);
657 : }
658 :
659 : /************************************************************************/
660 : /* GetOptionValue() */
661 : /************************************************************************/
662 :
663 197 : static const char *GetOptionValue(CSLConstList papszOptions,
664 : const char *pszOptionKey,
665 : const char *pszConfigOptionKey)
666 : {
667 : const char *pszVal =
668 197 : pszOptionKey ? CSLFetchNameValue(papszOptions, pszOptionKey) : nullptr;
669 197 : if (pszVal)
670 : {
671 0 : return pszVal;
672 : }
673 197 : pszVal = CSLFetchNameValue(papszOptions, pszConfigOptionKey);
674 197 : if (pszVal)
675 : {
676 3 : return pszVal;
677 : }
678 194 : pszVal = CPLGetConfigOption(pszConfigOptionKey, nullptr);
679 194 : return pszVal;
680 : }
681 :
682 : /************************************************************************/
683 : /* CheckSrcOverviewsConsistencyWithBase() */
684 : /************************************************************************/
685 :
686 13 : /*static */ bool GDALDefaultOverviews::CheckSrcOverviewsConsistencyWithBase(
687 : GDALDataset *poFullResDS, const std::vector<GDALDataset *> &apoSrcOvrDS)
688 : {
689 13 : const auto poThisCRS = poFullResDS->GetSpatialRef();
690 13 : GDALGeoTransform thisGT;
691 13 : const bool bThisHasGT = poFullResDS->GetGeoTransform(thisGT) == CE_None;
692 21 : for (auto *poSrcOvrDS : apoSrcOvrDS)
693 : {
694 25 : if (poSrcOvrDS->GetRasterXSize() > poFullResDS->GetRasterXSize() ||
695 12 : poSrcOvrDS->GetRasterYSize() > poFullResDS->GetRasterYSize())
696 : {
697 1 : CPLError(
698 : CE_Failure, CPLE_AppDefined,
699 : "AddOverviews(): at least one input dataset has dimensions "
700 : "larger than the full resolution dataset.");
701 5 : return false;
702 : }
703 23 : if (poSrcOvrDS->GetRasterXSize() == 0 ||
704 11 : poSrcOvrDS->GetRasterYSize() == 0)
705 : {
706 1 : CPLError(
707 : CE_Failure, CPLE_AppDefined,
708 : "AddOverviews(): at least one input dataset has one of its "
709 : "dimensions equal to 0.");
710 1 : return false;
711 : }
712 11 : if (poSrcOvrDS->GetRasterCount() != poFullResDS->GetRasterCount())
713 : {
714 1 : CPLError(CE_Failure, CPLE_AppDefined,
715 : "AddOverviews(): at least one input dataset not the same "
716 : "number of bands than the full resolution dataset.");
717 1 : return false;
718 : }
719 10 : if (poThisCRS)
720 : {
721 9 : if (const auto poOvrCRS = poSrcOvrDS->GetSpatialRef())
722 : {
723 9 : if (!poOvrCRS->IsSame(poThisCRS))
724 : {
725 1 : CPLError(CE_Failure, CPLE_AppDefined,
726 : "AddOverviews(): at least one input dataset has "
727 : "its CRS "
728 : "different from the one of the full resolution "
729 : "dataset.");
730 1 : return false;
731 : }
732 : }
733 : }
734 9 : if (bThisHasGT)
735 : {
736 9 : GDALGeoTransform ovrGT;
737 : const bool bOvrHasGT =
738 9 : poSrcOvrDS->GetGeoTransform(ovrGT) == CE_None;
739 : const double dfOvrXRatio =
740 9 : static_cast<double>(poFullResDS->GetRasterXSize()) /
741 9 : poSrcOvrDS->GetRasterXSize();
742 : const double dfOvrYRatio =
743 9 : static_cast<double>(poFullResDS->GetRasterYSize()) /
744 9 : poSrcOvrDS->GetRasterYSize();
745 18 : if (bOvrHasGT && !(std::fabs(thisGT[0] - ovrGT[0]) <=
746 9 : 0.5 * std::fabs(ovrGT[1]) &&
747 9 : std::fabs(thisGT[1] - ovrGT[1] / dfOvrXRatio) <=
748 9 : 0.1 * std::fabs(ovrGT[1]) &&
749 8 : std::fabs(thisGT[2] - ovrGT[2] / dfOvrYRatio) <=
750 8 : 0.1 * std::fabs(ovrGT[2]) &&
751 8 : std::fabs(thisGT[3] - ovrGT[3]) <=
752 8 : 0.5 * std::fabs(ovrGT[5]) &&
753 8 : std::fabs(thisGT[4] - ovrGT[4] / dfOvrXRatio) <=
754 8 : 0.1 * std::fabs(ovrGT[4]) &&
755 8 : std::fabs(thisGT[5] - ovrGT[5] / dfOvrYRatio) <=
756 8 : 0.1 * std::fabs(ovrGT[5])))
757 : {
758 1 : CPLError(
759 : CE_Failure, CPLE_AppDefined,
760 : "AddOverviews(): at least one input dataset has its "
761 : "geospatial extent "
762 : "different from the one of the full resolution dataset.");
763 1 : return false;
764 : }
765 : }
766 : }
767 8 : return true;
768 : }
769 :
770 : /************************************************************************/
771 : /* AddOverviews() */
772 : /************************************************************************/
773 :
774 4 : CPLErr GDALDefaultOverviews::AddOverviews(
775 : [[maybe_unused]] const char *pszBasename,
776 : [[maybe_unused]] const std::vector<GDALDataset *> &apoSrcOvrDSIn,
777 : [[maybe_unused]] GDALProgressFunc pfnProgress,
778 : [[maybe_unused]] void *pProgressData,
779 : [[maybe_unused]] CSLConstList papszOptions)
780 : {
781 : #ifdef HAVE_TIFF
782 4 : if (pfnProgress == nullptr)
783 2 : pfnProgress = GDALDummyProgress;
784 :
785 4 : if (CreateOrOpenOverviewFile(pszBasename, papszOptions) != CE_None)
786 0 : return CE_Failure;
787 :
788 4 : if (bOvrIsAux)
789 : {
790 0 : CPLError(CE_Failure, CPLE_NotSupported,
791 : "AddOverviews() not supported for .aux overviews");
792 0 : return CE_Failure;
793 : }
794 :
795 4 : if (!GDALDefaultOverviews::CheckSrcOverviewsConsistencyWithBase(
796 : poDS, apoSrcOvrDSIn))
797 0 : return CE_Failure;
798 :
799 8 : std::vector<GDALDataset *> apoSrcOvrDS = apoSrcOvrDSIn;
800 : // Sort overviews by descending size
801 4 : std::sort(apoSrcOvrDS.begin(), apoSrcOvrDS.end(),
802 0 : [](const GDALDataset *poDS1, const GDALDataset *poDS2)
803 0 : { return poDS1->GetRasterXSize() > poDS2->GetRasterXSize(); });
804 :
805 4 : auto poBand = poDS->GetRasterBand(1);
806 4 : if (!poBand)
807 0 : return CE_Failure;
808 :
809 : // Determine which overview levels must be created
810 4 : std::vector<std::pair<int, int>> anOverviewSizes;
811 8 : for (auto *poSrcOvrDS : apoSrcOvrDS)
812 : {
813 4 : bool bFound = false;
814 4 : for (int j = 0; j < poBand->GetOverviewCount(); j++)
815 : {
816 2 : GDALRasterBand *poOverview = poBand->GetOverview(j);
817 2 : if (poOverview && poOverview->GetDataset() &&
818 2 : poOverview->GetDataset() != poDS &&
819 6 : poOverview->GetXSize() == poSrcOvrDS->GetRasterXSize() &&
820 2 : poOverview->GetYSize() == poSrcOvrDS->GetRasterYSize())
821 : {
822 2 : bFound = true;
823 2 : break;
824 : }
825 : }
826 4 : if (!bFound)
827 : {
828 0 : anOverviewSizes.emplace_back(poSrcOvrDS->GetRasterXSize(),
829 2 : poSrcOvrDS->GetRasterYSize());
830 : }
831 : }
832 :
833 4 : CPLErr eErr = CE_None;
834 :
835 4 : if (!anOverviewSizes.empty())
836 : {
837 2 : if (poODS != nullptr)
838 : {
839 0 : delete poODS;
840 0 : poODS = nullptr;
841 : }
842 :
843 2 : const int nBands = poDS->GetRasterCount();
844 4 : std::vector<GDALRasterBand *> apoBands;
845 4 : for (int i = 0; i < nBands; ++i)
846 2 : apoBands.push_back(poDS->GetRasterBand(i + 1));
847 :
848 2 : eErr = GTIFFBuildOverviewsEx(osOvrFilename, nBands, apoBands.data(),
849 2 : static_cast<int>(apoSrcOvrDS.size()),
850 2 : nullptr, anOverviewSizes.data(), "NONE",
851 : nullptr, GDALDummyProgress, nullptr);
852 :
853 : // Probe for proxy overview filename.
854 2 : if (eErr == CE_Failure)
855 : {
856 : const char *pszProxyOvrFilename =
857 0 : poDS->GetMetadataItem("FILENAME", "ProxyOverviewRequest");
858 :
859 0 : if (pszProxyOvrFilename != nullptr)
860 : {
861 0 : osOvrFilename = pszProxyOvrFilename;
862 0 : eErr = GTIFFBuildOverviewsEx(
863 0 : osOvrFilename, nBands, apoBands.data(),
864 0 : static_cast<int>(apoSrcOvrDS.size()), nullptr,
865 0 : anOverviewSizes.data(), "NONE", nullptr, GDALDummyProgress,
866 : nullptr);
867 : }
868 : }
869 :
870 2 : if (eErr == CE_None)
871 : {
872 2 : poODS = GDALDataset::Open(osOvrFilename,
873 : GDAL_OF_RASTER | GDAL_OF_UPDATE);
874 2 : if (poODS == nullptr)
875 0 : eErr = CE_Failure;
876 : }
877 : }
878 :
879 : // almost 0, but not 0 to please Coverity Scan
880 4 : double dfTotalPixels = std::numeric_limits<double>::min();
881 8 : for (const auto *poSrcOvrDS : apoSrcOvrDS)
882 : {
883 4 : dfTotalPixels += static_cast<double>(poSrcOvrDS->GetRasterXSize()) *
884 4 : poSrcOvrDS->GetRasterYSize();
885 : }
886 :
887 : // Copy source datasets into target overview datasets
888 4 : double dfCurPixels = 0;
889 8 : for (auto *poSrcOvrDS : apoSrcOvrDS)
890 : {
891 4 : GDALDataset *poDstOvrDS = nullptr;
892 4 : for (int j = 0; eErr == CE_None && j < poBand->GetOverviewCount(); j++)
893 : {
894 4 : GDALRasterBand *poOverview = poBand->GetOverview(j);
895 8 : if (poOverview &&
896 8 : poOverview->GetXSize() == poSrcOvrDS->GetRasterXSize() &&
897 4 : poOverview->GetYSize() == poSrcOvrDS->GetRasterYSize())
898 : {
899 4 : poDstOvrDS = poOverview->GetDataset();
900 4 : break;
901 : }
902 : }
903 4 : if (poDstOvrDS)
904 : {
905 : const double dfThisPixels =
906 4 : static_cast<double>(poSrcOvrDS->GetRasterXSize()) *
907 4 : poSrcOvrDS->GetRasterYSize();
908 8 : void *pScaledProgressData = GDALCreateScaledProgress(
909 : dfCurPixels / dfTotalPixels,
910 4 : (dfCurPixels + dfThisPixels) / dfTotalPixels, pfnProgress,
911 : pProgressData);
912 4 : dfCurPixels += dfThisPixels;
913 4 : eErr = GDALDatasetCopyWholeRaster(GDALDataset::ToHandle(poSrcOvrDS),
914 : GDALDataset::ToHandle(poDstOvrDS),
915 : nullptr, GDALScaledProgress,
916 : pScaledProgressData);
917 4 : GDALDestroyScaledProgress(pScaledProgressData);
918 : }
919 : }
920 :
921 4 : return eErr;
922 : #else
923 : CPLError(CE_Failure, CPLE_NotSupported,
924 : "AddOverviews() not supported due to GeoTIFF driver missing");
925 : return CE_Failure;
926 : #endif
927 : }
928 :
929 : /************************************************************************/
930 : /* CreateOrOpenOverviewFile() */
931 : /************************************************************************/
932 :
933 209 : CPLErr GDALDefaultOverviews::CreateOrOpenOverviewFile(const char *pszBasename,
934 : CSLConstList papszOptions)
935 : {
936 :
937 : /* -------------------------------------------------------------------- */
938 : /* If we don't already have an overview file, we need to decide */
939 : /* what format to use. */
940 : /* -------------------------------------------------------------------- */
941 209 : if (poODS == nullptr)
942 : {
943 : const char *pszUseRRD =
944 189 : GetOptionValue(papszOptions, nullptr, "USE_RRD");
945 189 : bOvrIsAux = pszUseRRD && CPLTestBool(pszUseRRD);
946 189 : if (bOvrIsAux)
947 : {
948 : osOvrFilename =
949 5 : CPLResetExtensionSafe(poDS->GetDescription(), "aux");
950 :
951 : VSIStatBufL sStatBuf;
952 5 : if (VSIStatExL(osOvrFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0)
953 0 : osOvrFilename.Printf("%s.aux", poDS->GetDescription());
954 : }
955 : }
956 : /* -------------------------------------------------------------------- */
957 : /* If we already have the overviews open, but they are */
958 : /* read-only, then try and reopen them read-write. */
959 : /* -------------------------------------------------------------------- */
960 20 : else if (poODS->GetAccess() == GA_ReadOnly)
961 : {
962 18 : GDALClose(poODS);
963 18 : poODS =
964 18 : GDALDataset::Open(osOvrFilename, GDAL_OF_RASTER | GDAL_OF_UPDATE);
965 18 : if (poODS == nullptr)
966 0 : return CE_Failure;
967 : }
968 :
969 : /* -------------------------------------------------------------------- */
970 : /* If a basename is provided, use it to override the internal */
971 : /* overview filename. */
972 : /* -------------------------------------------------------------------- */
973 209 : if (pszBasename == nullptr && osOvrFilename.length() == 0)
974 0 : pszBasename = poDS->GetDescription();
975 :
976 209 : if (pszBasename != nullptr)
977 : {
978 1 : if (bOvrIsAux)
979 0 : osOvrFilename.Printf("%s.aux", pszBasename);
980 : else
981 1 : osOvrFilename.Printf("%s.ovr", pszBasename);
982 : }
983 :
984 209 : return CE_None;
985 : }
986 :
987 : /************************************************************************/
988 : /* BuildOverviews() */
989 : /************************************************************************/
990 :
991 214 : CPLErr GDALDefaultOverviews::BuildOverviews(
992 : const char *pszBasename, const char *pszResampling, int nOverviews,
993 : const int *panOverviewList, int nBands, const int *panBandList,
994 : GDALProgressFunc pfnProgress, void *pProgressData,
995 : CSLConstList papszOptions)
996 :
997 : {
998 214 : if (pfnProgress == nullptr)
999 0 : pfnProgress = GDALDummyProgress;
1000 :
1001 214 : if (nOverviews == 0)
1002 9 : return CleanOverviews();
1003 :
1004 205 : if (CreateOrOpenOverviewFile(pszBasename, papszOptions) != CE_None)
1005 0 : return CE_Failure;
1006 :
1007 : /* -------------------------------------------------------------------- */
1008 : /* Our TIFF overview support currently only works safely if all */
1009 : /* bands are handled at the same time. */
1010 : /* -------------------------------------------------------------------- */
1011 205 : if (!bOvrIsAux && nBands != poDS->GetRasterCount())
1012 : {
1013 0 : CPLError(CE_Failure, CPLE_NotSupported,
1014 : "Generation of overviews in external TIFF currently only "
1015 : "supported when operating on all bands. "
1016 : "Operation failed.");
1017 0 : return CE_Failure;
1018 : }
1019 :
1020 : /* -------------------------------------------------------------------- */
1021 : /* Establish which of the overview levels we already have, and */
1022 : /* which are new. We assume that band 1 of the file is */
1023 : /* representative. */
1024 : /* -------------------------------------------------------------------- */
1025 205 : GDALRasterBand *poBand = poDS->GetRasterBand(1);
1026 :
1027 205 : int nNewOverviews = 0;
1028 : int *panNewOverviewList =
1029 205 : static_cast<int *>(CPLCalloc(sizeof(int), nOverviews));
1030 205 : double dfAreaNewOverviews = 0;
1031 205 : double dfAreaRefreshedOverviews = 0;
1032 410 : std::vector<bool> abValidLevel(nOverviews, true);
1033 205 : std::vector<bool> abRequireRefresh(nOverviews, false);
1034 205 : bool bFoundSinglePixelOverview = false;
1035 501 : for (int i = 0; i < nOverviews && poBand != nullptr; i++)
1036 : {
1037 : // If we already have a 1x1 overview and this new one would result
1038 : // in it too, then don't create it.
1039 16 : if (bFoundSinglePixelOverview &&
1040 312 : DIV_ROUND_UP(poBand->GetXSize(), panOverviewList[i]) == 1 &&
1041 16 : DIV_ROUND_UP(poBand->GetYSize(), panOverviewList[i]) == 1)
1042 : {
1043 16 : abValidLevel[i] = false;
1044 16 : continue;
1045 : }
1046 :
1047 303 : for (int j = 0; j < poBand->GetOverviewCount(); j++)
1048 : {
1049 43 : GDALRasterBand *poOverview = poBand->GetOverview(j);
1050 43 : if (poOverview == nullptr)
1051 0 : continue;
1052 :
1053 : int nOvFactor =
1054 43 : GDALComputeOvFactor(poOverview->GetXSize(), poBand->GetXSize(),
1055 : poOverview->GetYSize(), poBand->GetYSize());
1056 :
1057 66 : if (nOvFactor == panOverviewList[i] ||
1058 23 : nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
1059 : poBand->GetXSize(),
1060 : poBand->GetYSize()))
1061 : {
1062 : const auto osNewResampling =
1063 40 : GDALGetNormalizedOvrResampling(pszResampling);
1064 : const char *pszExistingResampling =
1065 20 : poOverview->GetMetadataItem("RESAMPLING");
1066 34 : if (pszExistingResampling &&
1067 14 : pszExistingResampling != osNewResampling)
1068 : {
1069 3 : if (auto l_poODS = poOverview->GetDataset())
1070 : {
1071 3 : if (auto poDriver = l_poODS->GetDriver())
1072 : {
1073 1 : if (EQUAL(poDriver->GetDescription(), "GTiff"))
1074 : {
1075 1 : poOverview->SetMetadataItem(
1076 1 : "RESAMPLING", osNewResampling.c_str());
1077 : }
1078 : }
1079 : }
1080 : }
1081 :
1082 20 : abRequireRefresh[i] = true;
1083 20 : break;
1084 : }
1085 : }
1086 :
1087 280 : if (abValidLevel[i])
1088 : {
1089 280 : const double dfArea =
1090 : 1.0 /
1091 280 : (static_cast<double>(panOverviewList[i]) * panOverviewList[i]);
1092 280 : dfAreaRefreshedOverviews += dfArea;
1093 280 : if (!abRequireRefresh[i])
1094 : {
1095 260 : dfAreaNewOverviews += dfArea;
1096 260 : panNewOverviewList[nNewOverviews++] = panOverviewList[i];
1097 : }
1098 :
1099 301 : if (DIV_ROUND_UP(poBand->GetXSize(), panOverviewList[i]) == 1 &&
1100 21 : DIV_ROUND_UP(poBand->GetYSize(), panOverviewList[i]) == 1)
1101 : {
1102 19 : bFoundSinglePixelOverview = true;
1103 : }
1104 : }
1105 : }
1106 :
1107 : /* -------------------------------------------------------------------- */
1108 : /* Build band list. */
1109 : /* -------------------------------------------------------------------- */
1110 : GDALRasterBand **pahBands = static_cast<GDALRasterBand **>(
1111 205 : CPLCalloc(sizeof(GDALRasterBand *), nBands));
1112 522 : for (int i = 0; i < nBands; i++)
1113 317 : pahBands[i] = poDS->GetRasterBand(panBandList[i]);
1114 :
1115 : /* -------------------------------------------------------------------- */
1116 : /* Build new overviews - Imagine. Keep existing file open if */
1117 : /* we have it. But mark all overviews as in need of */
1118 : /* regeneration, since HFAAuxBuildOverviews() doesn't actually */
1119 : /* produce the imagery. */
1120 : /* -------------------------------------------------------------------- */
1121 :
1122 205 : CPLErr eErr = CE_None;
1123 :
1124 205 : void *pScaledOverviewWithoutMask = GDALCreateScaledProgress(
1125 : 0,
1126 205 : (HaveMaskFile() ||
1127 203 : poDS->GetRasterBand(1)->GetMaskFlags() == GMF_PER_DATASET)
1128 9 : ? double(nBands) / (nBands + 1)
1129 : : 1,
1130 : pfnProgress, pProgressData);
1131 :
1132 228 : const auto AvoidZero = [](double x)
1133 : {
1134 228 : if (x == 0)
1135 0 : return 1.0;
1136 228 : return x;
1137 : };
1138 :
1139 205 : void *pScaledProgress = GDALCreateScaledProgress(
1140 205 : 0, dfAreaNewOverviews / AvoidZero(dfAreaRefreshedOverviews),
1141 : GDALScaledProgress, pScaledOverviewWithoutMask);
1142 205 : if (bOvrIsAux)
1143 : {
1144 : #ifdef NO_HFA_SUPPORT
1145 : CPLError(CE_Failure, CPLE_NotSupported,
1146 : "This build does not support creating .aux overviews");
1147 : eErr = CE_Failure;
1148 : #else
1149 9 : if (nNewOverviews == 0)
1150 : {
1151 : /* if we call HFAAuxBuildOverviews() with nNewOverviews == 0 */
1152 : /* because that there's no new, this will wipe existing */
1153 : /* overviews (#4831) */
1154 : // eErr = CE_None;
1155 : }
1156 : else
1157 : {
1158 6 : CPLStringList aosOptions(papszOptions);
1159 6 : aosOptions.SetNameValue("LOCATION", nullptr);
1160 6 : aosOptions.SetNameValue("USE_RRD", nullptr);
1161 6 : eErr = HFAAuxBuildOverviews(
1162 : osOvrFilename, poDS, &poODS, nBands, panBandList, nNewOverviews,
1163 : panNewOverviewList, pszResampling, GDALScaledProgress,
1164 6 : pScaledProgress, aosOptions.List());
1165 : }
1166 :
1167 : // HFAAuxBuildOverviews doesn't actually generate overviews
1168 9 : dfAreaNewOverviews = 0.0;
1169 22 : for (int j = 0; j < nOverviews; j++)
1170 : {
1171 13 : if (abValidLevel[j])
1172 13 : abRequireRefresh[j] = true;
1173 : }
1174 : #endif
1175 : }
1176 :
1177 : /* -------------------------------------------------------------------- */
1178 : /* Build new overviews - TIFF. Close TIFF files while we */
1179 : /* operate on it. */
1180 : /* -------------------------------------------------------------------- */
1181 : else
1182 : {
1183 196 : if (poODS != nullptr)
1184 : {
1185 14 : delete poODS;
1186 14 : poODS = nullptr;
1187 : }
1188 :
1189 : #ifdef HAVE_TIFF
1190 196 : eErr = GTIFFBuildOverviews(
1191 : osOvrFilename, nBands, pahBands, nNewOverviews, panNewOverviewList,
1192 : pszResampling, GDALScaledProgress, pScaledProgress, papszOptions);
1193 :
1194 : // Probe for proxy overview filename.
1195 196 : if (eErr == CE_Failure)
1196 : {
1197 : const char *pszProxyOvrFilename =
1198 5 : poDS->GetMetadataItem("FILENAME", "ProxyOverviewRequest");
1199 :
1200 5 : if (pszProxyOvrFilename != nullptr)
1201 : {
1202 1 : osOvrFilename = pszProxyOvrFilename;
1203 1 : eErr = GTIFFBuildOverviews(osOvrFilename, nBands, pahBands,
1204 : nNewOverviews, panNewOverviewList,
1205 : pszResampling, GDALScaledProgress,
1206 : pScaledProgress, papszOptions);
1207 : }
1208 : }
1209 :
1210 196 : if (eErr == CE_None)
1211 : {
1212 192 : poODS = GDALDataset::Open(osOvrFilename,
1213 : GDAL_OF_RASTER | GDAL_OF_UPDATE);
1214 192 : if (poODS == nullptr)
1215 0 : eErr = CE_Failure;
1216 : }
1217 : #else
1218 : CPLError(CE_Failure, CPLE_NotSupported,
1219 : "Cannot build TIFF overviews due to GeoTIFF driver missing");
1220 : eErr = CE_Failure;
1221 : #endif
1222 : }
1223 :
1224 205 : GDALDestroyScaledProgress(pScaledProgress);
1225 :
1226 : /* -------------------------------------------------------------------- */
1227 : /* Refresh old overviews that were listed. */
1228 : /* -------------------------------------------------------------------- */
1229 : GDALRasterBand **papoOverviewBands =
1230 205 : static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
1231 :
1232 518 : for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++)
1233 : {
1234 313 : poBand = poDS->GetRasterBand(panBandList[iBand]);
1235 313 : if (poBand == nullptr)
1236 : {
1237 0 : eErr = CE_Failure;
1238 0 : break;
1239 : }
1240 :
1241 313 : nNewOverviews = 0;
1242 626 : std::vector<bool> abAlreadyUsedOverviewBand(poBand->GetOverviewCount(),
1243 626 : false);
1244 :
1245 784 : for (int i = 0; i < nOverviews; i++)
1246 : {
1247 471 : if (!abValidLevel[i] || !abRequireRefresh[i])
1248 438 : continue;
1249 :
1250 51 : for (int j = 0; j < poBand->GetOverviewCount(); j++)
1251 : {
1252 51 : if (abAlreadyUsedOverviewBand[j])
1253 16 : continue;
1254 :
1255 35 : GDALRasterBand *poOverview = poBand->GetOverview(j);
1256 35 : if (poOverview == nullptr)
1257 0 : continue;
1258 :
1259 35 : int bHasNoData = FALSE;
1260 35 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
1261 :
1262 35 : if (bHasNoData)
1263 2 : poOverview->SetNoDataValue(noDataValue);
1264 :
1265 35 : const int nOvFactor = GDALComputeOvFactor(
1266 : poOverview->GetXSize(), poBand->GetXSize(),
1267 : poOverview->GetYSize(), poBand->GetYSize());
1268 :
1269 37 : if (nOvFactor == panOverviewList[i] ||
1270 2 : nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
1271 : poBand->GetXSize(),
1272 : poBand->GetYSize()))
1273 : {
1274 33 : abAlreadyUsedOverviewBand[j] = true;
1275 33 : CPLAssert(nNewOverviews < poBand->GetOverviewCount());
1276 33 : papoOverviewBands[nNewOverviews++] = poOverview;
1277 33 : break;
1278 : }
1279 : }
1280 : }
1281 :
1282 313 : if (nNewOverviews > 0)
1283 : {
1284 : const double dfOffset =
1285 23 : dfAreaNewOverviews / AvoidZero(dfAreaRefreshedOverviews);
1286 23 : const double dfScale = 1.0 - dfOffset;
1287 46 : pScaledProgress = GDALCreateScaledProgress(
1288 23 : dfOffset + dfScale * iBand / nBands,
1289 23 : dfOffset + dfScale * (iBand + 1) / nBands, GDALScaledProgress,
1290 : pScaledOverviewWithoutMask);
1291 23 : eErr = GDALRegenerateOverviewsEx(
1292 : GDALRasterBand::ToHandle(poBand), nNewOverviews,
1293 : reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
1294 : pszResampling, GDALScaledProgress, pScaledProgress,
1295 : papszOptions);
1296 23 : GDALDestroyScaledProgress(pScaledProgress);
1297 : }
1298 : }
1299 :
1300 : /* -------------------------------------------------------------------- */
1301 : /* Cleanup */
1302 : /* -------------------------------------------------------------------- */
1303 205 : CPLFree(papoOverviewBands);
1304 205 : CPLFree(panNewOverviewList);
1305 205 : CPLFree(pahBands);
1306 205 : GDALDestroyScaledProgress(pScaledOverviewWithoutMask);
1307 :
1308 205 : const int nOverviewCount = GetOverviewCount(1);
1309 :
1310 : /* -------------------------------------------------------------------- */
1311 : /* If we have a mask file, we need to build its overviews too. */
1312 : /* -------------------------------------------------------------------- */
1313 205 : if (HaveMaskFile() && eErr == CE_None)
1314 : {
1315 4 : pScaledProgress = GDALCreateScaledProgress(
1316 2 : double(nBands) / (nBands + 1), 1.0, pfnProgress, pProgressData);
1317 2 : eErr = BuildOverviewsMask(pszResampling, nOverviews, panOverviewList,
1318 : GDALScaledProgress, pScaledProgress,
1319 : papszOptions);
1320 2 : GDALDestroyScaledProgress(pScaledProgress);
1321 : }
1322 : #ifdef HAVE_TIFF
1323 : // Deal with external overviews of a non-external mask
1324 402 : else if (eErr == CE_None && poODS &&
1325 199 : poDS->GetRasterBand(1)->GetMaskFlags() == GMF_PER_DATASET)
1326 : {
1327 7 : bool bNeedsReopeningBefore = true;
1328 7 : bool bNeedsReopeningAfter = false;
1329 16 : for (int iOver = 0; eErr == CE_None && iOver < nOverviewCount; ++iOver)
1330 : {
1331 9 : GDALRasterBand *poOverBand = GetOverview(1, iOver);
1332 9 : if (poOverBand && poOverBand->GetMaskFlags() != GMF_PER_DATASET)
1333 : {
1334 4 : if (bNeedsReopeningBefore)
1335 : {
1336 4 : bNeedsReopeningBefore = false;
1337 : // We need to re-open the dataset so the TIFF handle is in an
1338 : // appropriate state for GTIFFWriteDirectory
1339 4 : poODS = GDALDataset::Open(osOvrFilename,
1340 : GDAL_OF_RASTER | GDAL_OF_UPDATE);
1341 4 : if (poODS == nullptr)
1342 0 : eErr = CE_Failure;
1343 : }
1344 4 : if (eErr == CE_None)
1345 : {
1346 : int nMaskOvrCompression;
1347 4 : auto hDrv = GDALGetDriverByName("GTiff");
1348 8 : if (hDrv &&
1349 4 : strstr(GDALGetMetadataItem(
1350 : hDrv, GDAL_DMD_CREATIONOPTIONLIST, nullptr),
1351 : "<Value>DEFLATE</Value>") != nullptr)
1352 4 : nMaskOvrCompression = COMPRESSION_ADOBE_DEFLATE;
1353 : else
1354 0 : nMaskOvrCompression = COMPRESSION_PACKBITS;
1355 :
1356 : TIFF *hOTIFF = static_cast<TIFF *>(
1357 4 : poODS->GetInternalHandle("TIFF_HANDLE"));
1358 :
1359 : int nOvrBlockXSize, nOvrBlockYSize;
1360 4 : poOverBand->GetBlockSize(&nOvrBlockXSize, &nOvrBlockYSize);
1361 4 : if (GTIFFWriteDirectory(
1362 : hOTIFF, FILETYPE_REDUCEDIMAGE | FILETYPE_MASK,
1363 : poOverBand->GetXSize(), poOverBand->GetYSize(), 1,
1364 : PLANARCONFIG_CONTIG, 1, nOvrBlockXSize,
1365 : nOvrBlockYSize, TRUE, nMaskOvrCompression,
1366 : PHOTOMETRIC_MASK, SAMPLEFORMAT_UINT, PREDICTOR_NONE,
1367 : nullptr, nullptr, nullptr, 0, nullptr, "", nullptr,
1368 4 : nullptr, nullptr, nullptr, false) == 0)
1369 : {
1370 0 : eErr = CE_Failure;
1371 : }
1372 :
1373 4 : bNeedsReopeningAfter = true;
1374 : }
1375 : }
1376 : }
1377 7 : if (eErr == CE_None && bNeedsReopeningAfter)
1378 : {
1379 : // Re-open dataset so that masks are properly attached to bands
1380 4 : delete poODS;
1381 4 : poODS = GDALDataset::Open(osOvrFilename,
1382 : GDAL_OF_RASTER | GDAL_OF_UPDATE);
1383 4 : if (poODS == nullptr)
1384 0 : eErr = CE_Failure;
1385 : }
1386 7 : if (eErr == CE_None)
1387 : {
1388 14 : std::vector<GDALRasterBandH> ahOvrMaskBands;
1389 16 : for (int iOver = 0; iOver < nOverviewCount; ++iOver)
1390 : {
1391 9 : GDALRasterBand *poOverBand = GetOverview(1, iOver);
1392 18 : if (!poOverBand ||
1393 9 : poOverBand->GetMaskFlags() != GMF_PER_DATASET)
1394 0 : continue;
1395 9 : ahOvrMaskBands.push_back(
1396 9 : GDALRasterBand::ToHandle(poOverBand->GetMaskBand()));
1397 : }
1398 :
1399 14 : pScaledProgress = GDALCreateScaledProgress(
1400 7 : double(nBands) / (nBands + 1), 1.0, pfnProgress, pProgressData);
1401 :
1402 7 : eErr = GDALRegenerateOverviewsEx(
1403 7 : poDS->GetRasterBand(1)->GetMaskBand(),
1404 7 : static_cast<int>(ahOvrMaskBands.size()), ahOvrMaskBands.data(),
1405 : pszResampling, GDALScaledProgress, pScaledProgress,
1406 : papszOptions);
1407 7 : GDALDestroyScaledProgress(pScaledProgress);
1408 : }
1409 : }
1410 : #endif
1411 :
1412 : /* -------------------------------------------------------------------- */
1413 : /* If we have an overview dataset, then mark all the overviews */
1414 : /* with the base dataset Used later for finding overviews */
1415 : /* masks. Uggg. */
1416 : /* -------------------------------------------------------------------- */
1417 205 : if (poODS)
1418 : {
1419 485 : for (int iOver = 0; iOver < nOverviewCount; iOver++)
1420 : {
1421 284 : GDALRasterBand *poOverBand = GetOverview(1, iOver);
1422 : GDALDataset *poOverDS =
1423 284 : poOverBand != nullptr ? poOverBand->GetDataset() : nullptr;
1424 :
1425 284 : if (poOverDS != nullptr)
1426 : {
1427 269 : poOverDS->oOvManager.poBaseDS = poDS;
1428 269 : poOverDS->oOvManager.poDS = poOverDS;
1429 : }
1430 : }
1431 : }
1432 :
1433 205 : return eErr;
1434 : }
1435 :
1436 : /************************************************************************/
1437 : /* BuildOverviewsMask() */
1438 : /************************************************************************/
1439 :
1440 4 : CPLErr GDALDefaultOverviews::BuildOverviewsMask(const char *pszResampling,
1441 : int nOverviews,
1442 : const int *panOverviewList,
1443 : GDALProgressFunc pfnProgress,
1444 : void *pProgressData,
1445 : CSLConstList papszOptions)
1446 : {
1447 4 : CPLErr eErr = CE_None;
1448 4 : if (HaveMaskFile() && poMaskDS)
1449 : {
1450 : // Some options are not compatible with mask overviews
1451 : // so unset them, and define more sensible values.
1452 4 : CPLStringList aosMaskOptions(papszOptions);
1453 : const char *pszCompress =
1454 4 : GetOptionValue(papszOptions, "COMPRESS", "COMPRESS_OVERVIEW");
1455 4 : const bool bJPEG = pszCompress && EQUAL(pszCompress, "JPEG");
1456 : const char *pszPhotometric =
1457 4 : GetOptionValue(papszOptions, "PHOTOMETRIC", "PHOTOMETRIC_OVERVIEW");
1458 4 : const bool bPHOTOMETRIC_YCBCR =
1459 4 : pszPhotometric && EQUAL(pszPhotometric, "YCBCR");
1460 4 : if (bJPEG)
1461 0 : aosMaskOptions.SetNameValue("COMPRESS", "DEFLATE");
1462 4 : if (bPHOTOMETRIC_YCBCR)
1463 0 : aosMaskOptions.SetNameValue("PHOTOMETRIC", "MINISBLACK");
1464 :
1465 4 : eErr = poMaskDS->BuildOverviews(
1466 : pszResampling, nOverviews, panOverviewList, 0, nullptr, pfnProgress,
1467 4 : pProgressData, aosMaskOptions.List());
1468 :
1469 4 : if (bOwnMaskDS)
1470 : {
1471 : // Reset the poMask member of main dataset bands, since it
1472 : // will become invalid after poMaskDS closing.
1473 10 : for (int iBand = 1; iBand <= poDS->GetRasterCount(); iBand++)
1474 : {
1475 6 : GDALRasterBand *poOtherBand = poDS->GetRasterBand(iBand);
1476 6 : if (poOtherBand != nullptr)
1477 6 : poOtherBand->InvalidateMaskBand();
1478 : }
1479 :
1480 4 : GDALClose(poMaskDS);
1481 : }
1482 :
1483 : // force next request to reread mask file.
1484 4 : poMaskDS = nullptr;
1485 4 : bOwnMaskDS = false;
1486 4 : bCheckedForMask = false;
1487 : }
1488 :
1489 4 : return eErr;
1490 : }
1491 :
1492 : /************************************************************************/
1493 : /* CreateMaskBand() */
1494 : /************************************************************************/
1495 :
1496 28 : CPLErr GDALDefaultOverviews::CreateMaskBand(int nFlags, int nBand)
1497 :
1498 : {
1499 28 : if (nBand < 1)
1500 17 : nFlags |= GMF_PER_DATASET;
1501 :
1502 : /* -------------------------------------------------------------------- */
1503 : /* ensure existing file gets opened if there is one. */
1504 : /* -------------------------------------------------------------------- */
1505 28 : CPL_IGNORE_RET_VAL(HaveMaskFile());
1506 :
1507 : /* -------------------------------------------------------------------- */
1508 : /* Try creating the mask file. */
1509 : /* -------------------------------------------------------------------- */
1510 28 : if (poMaskDS == nullptr)
1511 : {
1512 : GDALDriver *const poDr =
1513 23 : static_cast<GDALDriver *>(GDALGetDriverByName("GTiff"));
1514 :
1515 23 : if (poDr == nullptr)
1516 0 : return CE_Failure;
1517 :
1518 23 : GDALRasterBand *const poTBand = poDS->GetRasterBand(1);
1519 23 : if (poTBand == nullptr)
1520 0 : return CE_Failure;
1521 :
1522 : const int nBands =
1523 23 : (nFlags & GMF_PER_DATASET) ? 1 : poDS->GetRasterCount();
1524 :
1525 23 : char **papszOpt = CSLSetNameValue(nullptr, "COMPRESS", "DEFLATE");
1526 23 : papszOpt = CSLSetNameValue(papszOpt, GDALMD_INTERLEAVE, "BAND");
1527 :
1528 23 : int nBX = 0;
1529 23 : int nBY = 0;
1530 23 : poTBand->GetBlockSize(&nBX, &nBY);
1531 :
1532 : // Try to create matching tile size if legal in TIFF.
1533 23 : if ((nBX % 16) == 0 && (nBY % 16) == 0)
1534 : {
1535 2 : papszOpt = CSLSetNameValue(papszOpt, "TILED", "YES");
1536 2 : papszOpt = CSLSetNameValue(papszOpt, "BLOCKXSIZE",
1537 4 : CPLString().Printf("%d", nBX));
1538 2 : papszOpt = CSLSetNameValue(papszOpt, "BLOCKYSIZE",
1539 4 : CPLString().Printf("%d", nBY));
1540 : }
1541 :
1542 23 : CPLString osMskFilename;
1543 23 : osMskFilename.Printf("%s.msk", poDS->GetDescription());
1544 23 : poMaskDS =
1545 23 : poDr->Create(osMskFilename, poDS->GetRasterXSize(),
1546 23 : poDS->GetRasterYSize(), nBands, GDT_UInt8, papszOpt);
1547 23 : CSLDestroy(papszOpt);
1548 :
1549 23 : if (poMaskDS == nullptr) // Presumably error already issued.
1550 0 : return CE_Failure;
1551 :
1552 23 : bOwnMaskDS = true;
1553 : }
1554 :
1555 : /* -------------------------------------------------------------------- */
1556 : /* Save the mask flags for this band. */
1557 : /* -------------------------------------------------------------------- */
1558 28 : if (nBand > poMaskDS->GetRasterCount())
1559 : {
1560 1 : CPLError(CE_Failure, CPLE_AppDefined,
1561 : "Attempt to create a mask band for band %d of %s, "
1562 : "but the .msk file has a PER_DATASET mask.",
1563 1 : nBand, poDS->GetDescription());
1564 1 : return CE_Failure;
1565 : }
1566 :
1567 72 : for (int iBand = 0; iBand < poDS->GetRasterCount(); iBand++)
1568 : {
1569 : // we write only the info for this band, unless we are
1570 : // using PER_DATASET in which case we write for all.
1571 45 : if (nBand != iBand + 1 && !(nFlags & GMF_PER_DATASET))
1572 7 : continue;
1573 :
1574 38 : poMaskDS->SetMetadataItem(
1575 76 : CPLString().Printf("INTERNAL_MASK_FLAGS_%d", iBand + 1),
1576 76 : CPLString().Printf("%d", nFlags));
1577 : }
1578 :
1579 27 : return CE_None;
1580 : }
1581 :
1582 : /************************************************************************/
1583 : /* GetMaskBand() */
1584 : /************************************************************************/
1585 :
1586 : // Secret code meaning we don't handle this band.
1587 : constexpr int MISSING_FLAGS = 0x8000;
1588 :
1589 51 : GDALRasterBand *GDALDefaultOverviews::GetMaskBand(int nBand)
1590 :
1591 : {
1592 51 : const int nFlags = GetMaskFlags(nBand);
1593 :
1594 51 : if (poMaskDS == nullptr || nFlags == MISSING_FLAGS)
1595 2 : return nullptr;
1596 :
1597 49 : if (nFlags & GMF_PER_DATASET)
1598 37 : return poMaskDS->GetRasterBand(1);
1599 :
1600 12 : if (nBand > 0)
1601 12 : return poMaskDS->GetRasterBand(nBand);
1602 :
1603 0 : return nullptr;
1604 : }
1605 :
1606 : /************************************************************************/
1607 : /* GetMaskFlags() */
1608 : /************************************************************************/
1609 :
1610 98 : int GDALDefaultOverviews::GetMaskFlags(int nBand)
1611 :
1612 : {
1613 : /* -------------------------------------------------------------------- */
1614 : /* Fetch this band's metadata entry. They are of the form: */
1615 : /* INTERNAL_MASK_FLAGS_n: flags */
1616 : /* -------------------------------------------------------------------- */
1617 98 : if (!HaveMaskFile())
1618 0 : return 0;
1619 :
1620 98 : const char *pszValue = poMaskDS->GetMetadataItem(
1621 196 : CPLString().Printf("INTERNAL_MASK_FLAGS_%d", std::max(nBand, 1)));
1622 :
1623 98 : if (pszValue == nullptr)
1624 2 : return MISSING_FLAGS;
1625 :
1626 96 : return atoi(pszValue);
1627 : }
1628 :
1629 : /************************************************************************/
1630 : /* HaveMaskFile() */
1631 : /* */
1632 : /* Check for a mask file if we haven't already done so. */
1633 : /* Returns TRUE if we have one, otherwise FALSE. */
1634 : /************************************************************************/
1635 :
1636 106607 : int GDALDefaultOverviews::HaveMaskFile(char **papszSiblingFiles,
1637 : const char *pszBasename)
1638 :
1639 : {
1640 106607 : if (m_bInHaveMaskFile)
1641 : {
1642 0 : CPLDebug("GDAL",
1643 : "GDALDefaultOverviews::HaveMaskFile(): called recursively");
1644 0 : return false;
1645 : }
1646 :
1647 : struct InHaveMaskFileSetter
1648 : {
1649 : bool &m_bVal;
1650 :
1651 106607 : explicit InHaveMaskFileSetter(bool &bVal) : m_bVal(bVal)
1652 : {
1653 106607 : m_bVal = true;
1654 106607 : }
1655 :
1656 106607 : ~InHaveMaskFileSetter()
1657 106607 : {
1658 106607 : m_bVal = false;
1659 106607 : }
1660 : };
1661 :
1662 213214 : InHaveMaskFileSetter setter(m_bInHaveMaskFile);
1663 106607 : CPL_IGNORE_RET_VAL(setter);
1664 :
1665 : /* -------------------------------------------------------------------- */
1666 : /* Have we already checked for masks? */
1667 : /* -------------------------------------------------------------------- */
1668 106607 : if (bCheckedForMask)
1669 4438 : return poMaskDS != nullptr;
1670 :
1671 102169 : if (papszSiblingFiles == nullptr)
1672 102169 : papszSiblingFiles = papszInitSiblingFiles;
1673 :
1674 : /* -------------------------------------------------------------------- */
1675 : /* Are we an overview? If so we need to find the corresponding */
1676 : /* overview in the base files mask file (if there is one). */
1677 : /* -------------------------------------------------------------------- */
1678 102169 : if (poBaseDS != nullptr && poBaseDS->oOvManager.HaveMaskFile())
1679 : {
1680 4 : GDALRasterBand *const poBaseBand = poBaseDS->GetRasterBand(1);
1681 4 : GDALDataset *poMaskDSTemp = nullptr;
1682 4 : if (poBaseBand != nullptr)
1683 : {
1684 4 : GDALRasterBand *poBaseMask = poBaseBand->GetMaskBand();
1685 4 : if (poBaseMask != nullptr)
1686 : {
1687 4 : const int nOverviewCount = poBaseMask->GetOverviewCount();
1688 6 : for (int iOver = 0; iOver < nOverviewCount; iOver++)
1689 : {
1690 : GDALRasterBand *const poOverBand =
1691 6 : poBaseMask->GetOverview(iOver);
1692 6 : if (poOverBand == nullptr)
1693 0 : continue;
1694 :
1695 10 : if (poOverBand->GetXSize() == poDS->GetRasterXSize() &&
1696 4 : poOverBand->GetYSize() == poDS->GetRasterYSize())
1697 : {
1698 4 : poMaskDSTemp = poOverBand->GetDataset();
1699 4 : break;
1700 : }
1701 : }
1702 : }
1703 : }
1704 :
1705 4 : if (poMaskDSTemp != poDS)
1706 : {
1707 4 : poMaskDS = poMaskDSTemp;
1708 4 : bCheckedForMask = true;
1709 4 : bOwnMaskDS = false;
1710 :
1711 4 : return poMaskDS != nullptr;
1712 : }
1713 : }
1714 :
1715 : /* -------------------------------------------------------------------- */
1716 : /* Are we even initialized? If not, we apparently don't want */
1717 : /* to support overviews and masks. */
1718 : /* -------------------------------------------------------------------- */
1719 102165 : if (poDS == nullptr)
1720 91230 : return FALSE;
1721 :
1722 : /* -------------------------------------------------------------------- */
1723 : /* Check for .msk file. */
1724 : /* -------------------------------------------------------------------- */
1725 10935 : bCheckedForMask = true;
1726 :
1727 10935 : if (pszBasename == nullptr)
1728 10935 : pszBasename = poDS->GetDescription();
1729 :
1730 : // Don't bother checking for masks of masks.
1731 10935 : if (EQUAL(CPLGetExtensionSafe(pszBasename).c_str(), "msk"))
1732 18 : return FALSE;
1733 :
1734 10917 : if (!GDALCanFileAcceptSidecarFile(pszBasename))
1735 11 : return FALSE;
1736 21812 : CPLString osMskFilename;
1737 10906 : osMskFilename.Printf("%s.msk", pszBasename);
1738 :
1739 21812 : std::vector<char> achMskFilename;
1740 10906 : achMskFilename.resize(osMskFilename.size() + 1);
1741 10906 : memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
1742 10906 : osMskFilename.size() + 1);
1743 : bool bExists =
1744 10906 : CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
1745 10906 : osMskFilename = &achMskFilename[0];
1746 :
1747 : #if !defined(_WIN32)
1748 10906 : if (!bExists && !papszSiblingFiles)
1749 : {
1750 2519 : osMskFilename.Printf("%s.MSK", pszBasename);
1751 2519 : memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
1752 2519 : osMskFilename.size() + 1);
1753 : bExists =
1754 2519 : CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
1755 2519 : osMskFilename = &achMskFilename[0];
1756 : }
1757 : #endif
1758 :
1759 10906 : if (!bExists)
1760 10870 : return FALSE;
1761 :
1762 : /* -------------------------------------------------------------------- */
1763 : /* Open the file. */
1764 : /* -------------------------------------------------------------------- */
1765 36 : poMaskDS = GDALDataset::Open(
1766 : osMskFilename,
1767 36 : GDAL_OF_RASTER | (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
1768 36 : nullptr, nullptr, papszInitSiblingFiles);
1769 36 : CPLAssert(poMaskDS != poDS);
1770 :
1771 36 : if (poMaskDS == nullptr)
1772 1 : return FALSE;
1773 :
1774 35 : bOwnMaskDS = true;
1775 :
1776 35 : return TRUE;
1777 : }
1778 :
1779 : /************************************************************************/
1780 : /* GDALGetNormalizedOvrResampling() */
1781 : /************************************************************************/
1782 :
1783 1001 : std::string GDALGetNormalizedOvrResampling(const char *pszResampling)
1784 : {
1785 1001 : if (pszResampling &&
1786 1001 : EQUAL(pszResampling, "AVERAGE_BIT2GRAYSCALE_MINISWHITE"))
1787 0 : return "AVERAGE_BIT2GRAYSCALE_MINISWHITE";
1788 1001 : else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2"))
1789 8 : return "AVERAGE_BIT2GRAYSCALE";
1790 993 : else if (pszResampling && STARTS_WITH_CI(pszResampling, "NEAR"))
1791 433 : return "NEAREST";
1792 560 : else if (pszResampling && EQUAL(pszResampling, "AVERAGE_MAGPHASE"))
1793 0 : return "AVERAGE_MAGPHASE";
1794 560 : else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVER"))
1795 258 : return "AVERAGE";
1796 302 : else if (pszResampling && !EQUAL(pszResampling, "NONE"))
1797 : {
1798 334 : return CPLString(pszResampling).toupper();
1799 : }
1800 135 : return std::string();
1801 : }
1802 :
1803 : //! @endcond
|