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