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 150003 : 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 150003 : papszInitSiblingFiles(nullptr)
45 : {
46 149945 : }
47 :
48 : /************************************************************************/
49 : /* ~GDALDefaultOverviews() */
50 : /************************************************************************/
51 :
52 149927 : GDALDefaultOverviews::~GDALDefaultOverviews()
53 :
54 : {
55 149936 : CPLFree(pszInitName);
56 149933 : CSLDestroy(papszInitSiblingFiles);
57 :
58 149933 : CloseDependentDatasets();
59 149921 : }
60 :
61 : /************************************************************************/
62 : /* CloseDependentDatasets() */
63 : /************************************************************************/
64 :
65 168848 : int GDALDefaultOverviews::CloseDependentDatasets()
66 : {
67 168848 : bool bHasDroppedRef = false;
68 168848 : if (poODS != nullptr)
69 : {
70 397 : bHasDroppedRef = true;
71 397 : poODS->FlushCache(true);
72 397 : GDALClose(poODS);
73 380 : poODS = nullptr;
74 : }
75 :
76 168831 : if (poMaskDS != nullptr)
77 : {
78 56 : if (bOwnMaskDS)
79 : {
80 52 : bHasDroppedRef = true;
81 52 : poMaskDS->FlushCache(true);
82 52 : GDALClose(poMaskDS);
83 : }
84 56 : poMaskDS = nullptr;
85 : }
86 :
87 168831 : return bHasDroppedRef;
88 : }
89 :
90 : /************************************************************************/
91 : /* IsInitialized() */
92 : /* */
93 : /* Returns TRUE if we are initialized. */
94 : /************************************************************************/
95 :
96 1072090 : int GDALDefaultOverviews::IsInitialized()
97 :
98 : {
99 1072090 : OverviewScan();
100 1072090 : return poDS != nullptr;
101 : }
102 :
103 : /************************************************************************/
104 : /* Initialize() */
105 : /************************************************************************/
106 :
107 52363 : void GDALDefaultOverviews::Initialize(GDALDataset *poDSIn,
108 : const char *pszBasename,
109 : CSLConstList papszSiblingFiles,
110 : bool bNameIsOVR)
111 :
112 : {
113 52363 : poDS = poDSIn;
114 :
115 : /* -------------------------------------------------------------------- */
116 : /* If we were already initialized, destroy the old overview */
117 : /* file handle. */
118 : /* -------------------------------------------------------------------- */
119 52363 : 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 52363 : bCheckedForOverviews = FALSE;
133 :
134 52363 : CPLFree(pszInitName);
135 52633 : pszInitName = nullptr;
136 52633 : if (pszBasename != nullptr)
137 52387 : pszInitName = CPLStrdup(pszBasename);
138 52616 : bInitNameIsOVR = bNameIsOVR;
139 :
140 52616 : CSLDestroy(papszInitSiblingFiles);
141 52489 : papszInitSiblingFiles = nullptr;
142 52489 : if (papszSiblingFiles != nullptr)
143 5665 : papszInitSiblingFiles = CSLDuplicate(papszSiblingFiles);
144 52487 : }
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 32952 : void GDALDefaultOverviews::Initialize(GDALDataset *poDSIn,
163 : GDALOpenInfo *poOpenInfo,
164 : const char *pszName,
165 : bool bTransferSiblingFilesIfLoaded)
166 : {
167 32952 : Initialize(poDSIn, pszName ? pszName : poOpenInfo->pszFilename);
168 :
169 32757 : if (bTransferSiblingFilesIfLoaded && poOpenInfo->AreSiblingFilesLoaded())
170 9715 : TransferSiblingFiles(poOpenInfo->StealSiblingFiles());
171 32754 : }
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 26678 : void GDALDefaultOverviews::TransferSiblingFiles(char **papszSiblingFiles)
182 : {
183 26678 : CSLDestroy(papszInitSiblingFiles);
184 26674 : papszInitSiblingFiles = papszSiblingFiles;
185 26674 : }
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 11774 : static AntiRecursionStructDefaultOvr &GetAntiRecursionDefaultOvr()
203 : {
204 11774 : static AntiRecursionStructDefaultOvr dummy;
205 11774 : int bMemoryErrorOccurred = false;
206 : void *pData =
207 11774 : CPLGetTLSEx(CTLS_GDALDEFAULTOVR_ANTIREC, &bMemoryErrorOccurred);
208 11774 : if (bMemoryErrorOccurred)
209 : {
210 0 : return dummy;
211 : }
212 11774 : if (pData == nullptr)
213 : {
214 459 : auto pAntiRecursion = new AntiRecursionStructDefaultOvr();
215 459 : CPLSetTLSWithFreeFuncEx(CTLS_GDALDEFAULTOVR_ANTIREC, pAntiRecursion,
216 : FreeAntiRecursionDefaultOvr,
217 : &bMemoryErrorOccurred);
218 459 : if (bMemoryErrorOccurred)
219 : {
220 0 : delete pAntiRecursion;
221 0 : return dummy;
222 : }
223 459 : return *pAntiRecursion;
224 : }
225 11315 : 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 1072090 : void GDALDefaultOverviews::OverviewScan()
238 :
239 : {
240 1072090 : if (bCheckedForOverviews || poDS == nullptr)
241 1060310 : return;
242 :
243 11774 : bCheckedForOverviews = true;
244 11774 : if (pszInitName == nullptr)
245 14 : pszInitName = CPLStrdup(poDS->GetDescription());
246 :
247 11774 : AntiRecursionStructDefaultOvr &antiRec = GetAntiRecursionDefaultOvr();
248 : // 32 should be enough to handle a .ovr.ovr.ovr...
249 11774 : if (antiRec.nRecLevel == 32)
250 0 : return;
251 11774 : if (antiRec.oSetFiles.find(pszInitName) != antiRec.oSetFiles.end())
252 0 : return;
253 11774 : antiRec.oSetFiles.insert(pszInitName);
254 11774 : ++antiRec.nRecLevel;
255 :
256 11774 : CPLDebug("GDAL", "GDALDefaultOverviews::OverviewScan()");
257 :
258 : /* -------------------------------------------------------------------- */
259 : /* Open overview dataset if it exists. */
260 : /* -------------------------------------------------------------------- */
261 23365 : if (!EQUAL(pszInitName, ":::VIRTUAL:::") &&
262 11592 : GDALCanFileAcceptSidecarFile(pszInitName))
263 : {
264 11590 : if (bInitNameIsOVR)
265 0 : osOvrFilename = pszInitName;
266 : else
267 11590 : osOvrFilename.Printf("%s.ovr", pszInitName);
268 :
269 23182 : std::vector<char> achOvrFilename;
270 11590 : achOvrFilename.resize(osOvrFilename.size() + 1);
271 11591 : memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
272 11591 : osOvrFilename.size() + 1);
273 11591 : bool bExists = CPL_TO_BOOL(
274 11591 : CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
275 11590 : osOvrFilename = &achOvrFilename[0];
276 :
277 : #if !defined(_WIN32)
278 11591 : if (!bInitNameIsOVR && !bExists && !papszInitSiblingFiles)
279 : {
280 2945 : osOvrFilename.Printf("%s.OVR", pszInitName);
281 2945 : memcpy(&(achOvrFilename[0]), osOvrFilename.c_str(),
282 2945 : osOvrFilename.size() + 1);
283 2945 : bExists = CPL_TO_BOOL(
284 2945 : CPLCheckForFile(&achOvrFilename[0], papszInitSiblingFiles));
285 2945 : osOvrFilename = &achOvrFilename[0];
286 2945 : if (!bExists)
287 2945 : osOvrFilename.Printf("%s.ovr", pszInitName);
288 : }
289 : #endif
290 :
291 11591 : 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 23167 : if (!poODS && !EQUAL(pszInitName, ":::VIRTUAL:::") &&
310 11392 : GDALCanFileAcceptSidecarFile(pszInitName))
311 : {
312 11390 : bool bTryFindAssociatedAuxFile = true;
313 11390 : if (papszInitSiblingFiles)
314 : {
315 16891 : CPLString osAuxFilename = CPLResetExtensionSafe(pszInitName, "aux");
316 8446 : int iSibling = CSLFindString(papszInitSiblingFiles,
317 : CPLGetFilename(osAuxFilename));
318 8445 : if (iSibling < 0)
319 : {
320 8441 : osAuxFilename = pszInitName;
321 8442 : osAuxFilename += ".aux";
322 8441 : iSibling = CSLFindString(papszInitSiblingFiles,
323 : CPLGetFilename(osAuxFilename));
324 8441 : if (iSibling < 0)
325 8441 : bTryFindAssociatedAuxFile = false;
326 : }
327 : }
328 :
329 11390 : if (bTryFindAssociatedAuxFile)
330 : {
331 2949 : poODS =
332 2949 : GDALFindAssociatedAuxFile(pszInitName, poDS->GetAccess(), poDS);
333 : }
334 :
335 11390 : if (poODS)
336 : {
337 : const bool bUseRRD =
338 8 : CPLTestBool(CPLGetConfigOption("USE_RRD", "NO"));
339 :
340 8 : bOvrIsAux = true;
341 8 : if (GetOverviewCount(1) == 0 && !bUseRRD)
342 : {
343 1 : bOvrIsAux = false;
344 1 : GDALClose(poODS);
345 1 : poODS = nullptr;
346 : }
347 : else
348 : {
349 7 : 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 11775 : if (poODS == nullptr)
360 : {
361 : const char *pszProxyOvrFilename =
362 11567 : poDS->GetMetadataItem("OVERVIEW_FILE", "OVERVIEWS");
363 :
364 11566 : 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 11773 : if (poODS)
393 : {
394 225 : const int nOverviewCount = GetOverviewCount(1);
395 :
396 536 : for (int iOver = 0; iOver < nOverviewCount; iOver++)
397 : {
398 311 : GDALRasterBand *const poBand = GetOverview(1, iOver);
399 : GDALDataset *const poOverDS =
400 311 : poBand != nullptr ? poBand->GetDataset() : nullptr;
401 :
402 311 : 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 11773 : antiRec.oSetFiles.erase(pszInitName);
412 11773 : --antiRec.nRecLevel;
413 : }
414 :
415 : /************************************************************************/
416 : /* GetOverviewCount() */
417 : /************************************************************************/
418 :
419 657162 : int GDALDefaultOverviews::GetOverviewCount(int nBand)
420 :
421 : {
422 657162 : if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
423 656126 : return 0;
424 :
425 1036 : GDALRasterBand *poBand = poODS->GetRasterBand(nBand);
426 1036 : if (poBand == nullptr)
427 0 : return 0;
428 :
429 1036 : if (bOvrIsAux)
430 79 : return poBand->GetOverviewCount();
431 :
432 957 : return poBand->GetOverviewCount() + 1;
433 : }
434 :
435 : /************************************************************************/
436 : /* GetOverview() */
437 : /************************************************************************/
438 :
439 1373 : GDALRasterBand *GDALDefaultOverviews::GetOverview(int nBand, int iOverview)
440 :
441 : {
442 1373 : if (poODS == nullptr || nBand < 1 || nBand > poODS->GetRasterCount())
443 262 : return nullptr;
444 :
445 1111 : GDALRasterBand *const poBand = poODS->GetRasterBand(nBand);
446 1111 : if (poBand == nullptr)
447 0 : return nullptr;
448 :
449 1111 : if (bOvrIsAux)
450 63 : return poBand->GetOverview(iOverview);
451 :
452 : // TIFF case, base is overview 0.
453 1048 : if (iOverview == 0)
454 797 : 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 473 : 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 473 : if (nXSize >= nYSize / 2 && !(nXSize < nYSize && nXSize < nOvLevel))
492 : {
493 398 : const int nOXSize = DIV_ROUND_UP(nXSize, nOvLevel);
494 :
495 398 : 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 67460 : static int GetFloorPowerOfTwo(int n)
508 : {
509 67460 : int p2 = 1;
510 136118 : while ((n = n >> 1) > 0)
511 : {
512 68658 : p2 <<= 1;
513 : }
514 67460 : return p2;
515 : }
516 :
517 : /************************************************************************/
518 : /* GDALComputeOvFactor() */
519 : /************************************************************************/
520 :
521 67460 : 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 67460 : if (nRasterXSize != 1 && nRasterXSize >= nRasterYSize / 2)
528 : {
529 67346 : const int nVal = static_cast<int>(
530 67346 : 0.5 + nRasterXSize / static_cast<double>(nOvrXSize));
531 : // Try to return a power-of-two value
532 67346 : const int nValPowerOfTwo = GetFloorPowerOfTwo(nVal);
533 67534 : for (int fact = 1; fact <= 2 && nValPowerOfTwo <= INT_MAX / fact;
534 : ++fact)
535 : {
536 67501 : if (DIV_ROUND_UP(nRasterXSize, fact * nValPowerOfTwo) == nOvrXSize)
537 67313 : 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 193 : static const char *GetOptionValue(CSLConstList papszOptions,
656 : const char *pszOptionKey,
657 : const char *pszConfigOptionKey)
658 : {
659 : const char *pszVal =
660 193 : pszOptionKey ? CSLFetchNameValue(papszOptions, pszOptionKey) : nullptr;
661 193 : if (pszVal)
662 : {
663 0 : return pszVal;
664 : }
665 193 : pszVal = CSLFetchNameValue(papszOptions, pszConfigOptionKey);
666 193 : if (pszVal)
667 : {
668 3 : 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 200 : 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 200 : if (poODS == nullptr)
934 : {
935 : const char *pszUseRRD =
936 185 : GetOptionValue(papszOptions, nullptr, "USE_RRD");
937 185 : bOvrIsAux = pszUseRRD && CPLTestBool(pszUseRRD);
938 185 : if (bOvrIsAux)
939 : {
940 : osOvrFilename =
941 5 : CPLResetExtensionSafe(poDS->GetDescription(), "aux");
942 :
943 : VSIStatBufL sStatBuf;
944 5 : 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 200 : if (pszBasename == nullptr && osOvrFilename.length() == 0)
966 0 : pszBasename = poDS->GetDescription();
967 :
968 200 : 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 200 : return CE_None;
977 : }
978 :
979 : /************************************************************************/
980 : /* BuildOverviews() */
981 : /************************************************************************/
982 :
983 205 : 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 205 : if (pfnProgress == nullptr)
991 0 : pfnProgress = GDALDummyProgress;
992 :
993 205 : if (nOverviews == 0)
994 9 : return CleanOverviews();
995 :
996 196 : 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 196 : 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 196 : GDALRasterBand *poBand = poDS->GetRasterBand(1);
1018 :
1019 196 : int nNewOverviews = 0;
1020 : int *panNewOverviewList =
1021 196 : static_cast<int *>(CPLCalloc(sizeof(int), nOverviews));
1022 196 : double dfAreaNewOverviews = 0;
1023 196 : double dfAreaRefreshedOverviews = 0;
1024 392 : std::vector<bool> abValidLevel(nOverviews, true);
1025 196 : std::vector<bool> abRequireRefresh(nOverviews, false);
1026 196 : bool bFoundSinglePixelOverview = false;
1027 482 : 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 302 : 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 291 : 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 270 : if (abValidLevel[i])
1080 : {
1081 270 : const double dfArea =
1082 : 1.0 /
1083 270 : (static_cast<double>(panOverviewList[i]) * panOverviewList[i]);
1084 270 : dfAreaRefreshedOverviews += dfArea;
1085 270 : if (!abRequireRefresh[i])
1086 : {
1087 253 : dfAreaNewOverviews += dfArea;
1088 253 : panNewOverviewList[nNewOverviews++] = panOverviewList[i];
1089 : }
1090 :
1091 291 : 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 196 : CPLCalloc(sizeof(GDALRasterBand *), nBands));
1104 504 : for (int i = 0; i < nBands; i++)
1105 308 : 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 196 : CPLErr eErr = CE_None;
1115 :
1116 196 : void *pScaledOverviewWithoutMask = GDALCreateScaledProgress(
1117 196 : 0, (HaveMaskFile() && poMaskDS) ? double(nBands) / (nBands + 1) : 1,
1118 : pfnProgress, pProgressData);
1119 :
1120 216 : const auto AvoidZero = [](double x)
1121 : {
1122 216 : if (x == 0)
1123 0 : return 1.0;
1124 216 : return x;
1125 : };
1126 :
1127 196 : void *pScaledProgress = GDALCreateScaledProgress(
1128 196 : 0, dfAreaNewOverviews / AvoidZero(dfAreaRefreshedOverviews),
1129 : GDALScaledProgress, pScaledOverviewWithoutMask);
1130 196 : 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 9 : 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 6 : CPLStringList aosOptions(papszOptions);
1147 6 : aosOptions.SetNameValue("LOCATION", nullptr);
1148 6 : aosOptions.SetNameValue("USE_RRD", nullptr);
1149 6 : eErr = HFAAuxBuildOverviews(
1150 : osOvrFilename, poDS, &poODS, nBands, panBandList, nNewOverviews,
1151 : panNewOverviewList, pszResampling, GDALScaledProgress,
1152 6 : pScaledProgress, aosOptions.List());
1153 : }
1154 :
1155 : // HFAAuxBuildOverviews doesn't actually generate overviews
1156 9 : dfAreaNewOverviews = 0.0;
1157 22 : for (int j = 0; j < nOverviews; j++)
1158 : {
1159 13 : if (abValidLevel[j])
1160 13 : abRequireRefresh[j] = true;
1161 : }
1162 : #endif
1163 : }
1164 :
1165 : /* -------------------------------------------------------------------- */
1166 : /* Build new overviews - TIFF. Close TIFF files while we */
1167 : /* operate on it. */
1168 : /* -------------------------------------------------------------------- */
1169 : else
1170 : {
1171 187 : if (poODS != nullptr)
1172 : {
1173 9 : delete poODS;
1174 9 : poODS = nullptr;
1175 : }
1176 :
1177 : #ifdef HAVE_TIFF
1178 187 : eErr = GTIFFBuildOverviews(
1179 : osOvrFilename, nBands, pahBands, nNewOverviews, panNewOverviewList,
1180 : pszResampling, GDALScaledProgress, pScaledProgress, papszOptions);
1181 :
1182 : // Probe for proxy overview filename.
1183 187 : if (eErr == CE_Failure)
1184 : {
1185 : const char *pszProxyOvrFilename =
1186 5 : poDS->GetMetadataItem("FILENAME", "ProxyOverviewRequest");
1187 :
1188 5 : if (pszProxyOvrFilename != nullptr)
1189 : {
1190 1 : osOvrFilename = pszProxyOvrFilename;
1191 1 : eErr = GTIFFBuildOverviews(osOvrFilename, nBands, pahBands,
1192 : nNewOverviews, panNewOverviewList,
1193 : pszResampling, GDALScaledProgress,
1194 : pScaledProgress, papszOptions);
1195 : }
1196 : }
1197 :
1198 187 : if (eErr == CE_None)
1199 : {
1200 183 : poODS = GDALDataset::Open(osOvrFilename,
1201 : GDAL_OF_RASTER | GDAL_OF_UPDATE);
1202 183 : if (poODS == nullptr)
1203 0 : eErr = CE_Failure;
1204 : }
1205 : #else
1206 : CPLError(CE_Failure, CPLE_NotSupported,
1207 : "Cannot build TIFF overviews due to GeoTIFF driver missing");
1208 : eErr = CE_Failure;
1209 : #endif
1210 : }
1211 :
1212 196 : GDALDestroyScaledProgress(pScaledProgress);
1213 :
1214 : /* -------------------------------------------------------------------- */
1215 : /* Refresh old overviews that were listed. */
1216 : /* -------------------------------------------------------------------- */
1217 : GDALRasterBand **papoOverviewBands =
1218 196 : static_cast<GDALRasterBand **>(CPLCalloc(sizeof(void *), nOverviews));
1219 :
1220 500 : for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++)
1221 : {
1222 304 : poBand = poDS->GetRasterBand(panBandList[iBand]);
1223 304 : if (poBand == nullptr)
1224 : {
1225 0 : eErr = CE_Failure;
1226 0 : break;
1227 : }
1228 :
1229 304 : nNewOverviews = 0;
1230 608 : std::vector<bool> abAlreadyUsedOverviewBand(poBand->GetOverviewCount(),
1231 608 : false);
1232 :
1233 765 : for (int i = 0; i < nOverviews; i++)
1234 : {
1235 461 : if (!abValidLevel[i] || !abRequireRefresh[i])
1236 431 : continue;
1237 :
1238 48 : for (int j = 0; j < poBand->GetOverviewCount(); j++)
1239 : {
1240 48 : if (abAlreadyUsedOverviewBand[j])
1241 16 : continue;
1242 :
1243 32 : GDALRasterBand *poOverview = poBand->GetOverview(j);
1244 32 : if (poOverview == nullptr)
1245 0 : continue;
1246 :
1247 32 : int bHasNoData = FALSE;
1248 32 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
1249 :
1250 32 : if (bHasNoData)
1251 2 : poOverview->SetNoDataValue(noDataValue);
1252 :
1253 32 : const int nOvFactor = GDALComputeOvFactor(
1254 : poOverview->GetXSize(), poBand->GetXSize(),
1255 : poOverview->GetYSize(), poBand->GetYSize());
1256 :
1257 34 : if (nOvFactor == panOverviewList[i] ||
1258 2 : nOvFactor == GDALOvLevelAdjust2(panOverviewList[i],
1259 : poBand->GetXSize(),
1260 : poBand->GetYSize()))
1261 : {
1262 30 : abAlreadyUsedOverviewBand[j] = true;
1263 30 : CPLAssert(nNewOverviews < poBand->GetOverviewCount());
1264 30 : papoOverviewBands[nNewOverviews++] = poOverview;
1265 30 : break;
1266 : }
1267 : }
1268 : }
1269 :
1270 304 : if (nNewOverviews > 0)
1271 : {
1272 : const double dfOffset =
1273 20 : dfAreaNewOverviews / AvoidZero(dfAreaRefreshedOverviews);
1274 20 : const double dfScale = 1.0 - dfOffset;
1275 40 : pScaledProgress = GDALCreateScaledProgress(
1276 20 : dfOffset + dfScale * iBand / nBands,
1277 20 : dfOffset + dfScale * (iBand + 1) / nBands, GDALScaledProgress,
1278 : pScaledOverviewWithoutMask);
1279 20 : eErr = GDALRegenerateOverviewsEx(
1280 : GDALRasterBand::ToHandle(poBand), nNewOverviews,
1281 : reinterpret_cast<GDALRasterBandH *>(papoOverviewBands),
1282 : pszResampling, GDALScaledProgress, pScaledProgress,
1283 : papszOptions);
1284 20 : GDALDestroyScaledProgress(pScaledProgress);
1285 : }
1286 : }
1287 :
1288 : /* -------------------------------------------------------------------- */
1289 : /* Cleanup */
1290 : /* -------------------------------------------------------------------- */
1291 196 : CPLFree(papoOverviewBands);
1292 196 : CPLFree(panNewOverviewList);
1293 196 : CPLFree(pahBands);
1294 196 : GDALDestroyScaledProgress(pScaledOverviewWithoutMask);
1295 :
1296 : /* -------------------------------------------------------------------- */
1297 : /* If we have a mask file, we need to build its overviews too. */
1298 : /* -------------------------------------------------------------------- */
1299 196 : if (HaveMaskFile() && eErr == CE_None)
1300 : {
1301 4 : pScaledProgress = GDALCreateScaledProgress(
1302 2 : double(nBands) / (nBands + 1), 1.0, pfnProgress, pProgressData);
1303 2 : eErr = BuildOverviewsMask(pszResampling, nOverviews, panOverviewList,
1304 : GDALScaledProgress, pScaledProgress,
1305 : papszOptions);
1306 2 : GDALDestroyScaledProgress(pScaledProgress);
1307 : }
1308 :
1309 : /* -------------------------------------------------------------------- */
1310 : /* If we have an overview dataset, then mark all the overviews */
1311 : /* with the base dataset Used later for finding overviews */
1312 : /* masks. Uggg. */
1313 : /* -------------------------------------------------------------------- */
1314 196 : if (poODS)
1315 : {
1316 192 : const int nOverviewCount = GetOverviewCount(1);
1317 :
1318 464 : for (int iOver = 0; iOver < nOverviewCount; iOver++)
1319 : {
1320 272 : GDALRasterBand *poOtherBand = GetOverview(1, iOver);
1321 : GDALDataset *poOverDS =
1322 272 : poOtherBand != nullptr ? poOtherBand->GetDataset() : nullptr;
1323 :
1324 272 : if (poOverDS != nullptr)
1325 : {
1326 257 : poOverDS->oOvManager.poBaseDS = poDS;
1327 257 : poOverDS->oOvManager.poDS = poOverDS;
1328 : }
1329 : }
1330 : }
1331 :
1332 196 : return eErr;
1333 : }
1334 :
1335 : /************************************************************************/
1336 : /* BuildOverviewsMask() */
1337 : /************************************************************************/
1338 :
1339 4 : CPLErr GDALDefaultOverviews::BuildOverviewsMask(const char *pszResampling,
1340 : int nOverviews,
1341 : const int *panOverviewList,
1342 : GDALProgressFunc pfnProgress,
1343 : void *pProgressData,
1344 : CSLConstList papszOptions)
1345 : {
1346 4 : CPLErr eErr = CE_None;
1347 4 : if (HaveMaskFile() && poMaskDS)
1348 : {
1349 : // Some options are not compatible with mask overviews
1350 : // so unset them, and define more sensible values.
1351 4 : CPLStringList aosMaskOptions(papszOptions);
1352 : const char *pszCompress =
1353 4 : GetOptionValue(papszOptions, "COMPRESS", "COMPRESS_OVERVIEW");
1354 4 : const bool bJPEG = pszCompress && EQUAL(pszCompress, "JPEG");
1355 : const char *pszPhotometric =
1356 4 : GetOptionValue(papszOptions, "PHOTOMETRIC", "PHOTOMETRIC_OVERVIEW");
1357 4 : const bool bPHOTOMETRIC_YCBCR =
1358 4 : pszPhotometric && EQUAL(pszPhotometric, "YCBCR");
1359 4 : if (bJPEG)
1360 0 : aosMaskOptions.SetNameValue("COMPRESS", "DEFLATE");
1361 4 : if (bPHOTOMETRIC_YCBCR)
1362 0 : aosMaskOptions.SetNameValue("PHOTOMETRIC", "MINISBLACK");
1363 :
1364 4 : eErr = poMaskDS->BuildOverviews(
1365 : pszResampling, nOverviews, panOverviewList, 0, nullptr, pfnProgress,
1366 4 : pProgressData, aosMaskOptions.List());
1367 :
1368 4 : if (bOwnMaskDS)
1369 : {
1370 : // Reset the poMask member of main dataset bands, since it
1371 : // will become invalid after poMaskDS closing.
1372 10 : for (int iBand = 1; iBand <= poDS->GetRasterCount(); iBand++)
1373 : {
1374 6 : GDALRasterBand *poOtherBand = poDS->GetRasterBand(iBand);
1375 6 : if (poOtherBand != nullptr)
1376 6 : poOtherBand->InvalidateMaskBand();
1377 : }
1378 :
1379 4 : GDALClose(poMaskDS);
1380 : }
1381 :
1382 : // force next request to reread mask file.
1383 4 : poMaskDS = nullptr;
1384 4 : bOwnMaskDS = false;
1385 4 : bCheckedForMask = false;
1386 : }
1387 :
1388 4 : return eErr;
1389 : }
1390 :
1391 : /************************************************************************/
1392 : /* CreateMaskBand() */
1393 : /************************************************************************/
1394 :
1395 27 : CPLErr GDALDefaultOverviews::CreateMaskBand(int nFlags, int nBand)
1396 :
1397 : {
1398 27 : if (nBand < 1)
1399 17 : nFlags |= GMF_PER_DATASET;
1400 :
1401 : /* -------------------------------------------------------------------- */
1402 : /* ensure existing file gets opened if there is one. */
1403 : /* -------------------------------------------------------------------- */
1404 27 : CPL_IGNORE_RET_VAL(HaveMaskFile());
1405 :
1406 : /* -------------------------------------------------------------------- */
1407 : /* Try creating the mask file. */
1408 : /* -------------------------------------------------------------------- */
1409 27 : if (poMaskDS == nullptr)
1410 : {
1411 : GDALDriver *const poDr =
1412 22 : static_cast<GDALDriver *>(GDALGetDriverByName("GTiff"));
1413 :
1414 22 : if (poDr == nullptr)
1415 0 : return CE_Failure;
1416 :
1417 22 : GDALRasterBand *const poTBand = poDS->GetRasterBand(1);
1418 22 : if (poTBand == nullptr)
1419 0 : return CE_Failure;
1420 :
1421 : const int nBands =
1422 22 : (nFlags & GMF_PER_DATASET) ? 1 : poDS->GetRasterCount();
1423 :
1424 22 : char **papszOpt = CSLSetNameValue(nullptr, "COMPRESS", "DEFLATE");
1425 22 : papszOpt = CSLSetNameValue(papszOpt, "INTERLEAVE", "BAND");
1426 :
1427 22 : int nBX = 0;
1428 22 : int nBY = 0;
1429 22 : poTBand->GetBlockSize(&nBX, &nBY);
1430 :
1431 : // Try to create matching tile size if legal in TIFF.
1432 22 : if ((nBX % 16) == 0 && (nBY % 16) == 0)
1433 : {
1434 2 : papszOpt = CSLSetNameValue(papszOpt, "TILED", "YES");
1435 2 : papszOpt = CSLSetNameValue(papszOpt, "BLOCKXSIZE",
1436 4 : CPLString().Printf("%d", nBX));
1437 2 : papszOpt = CSLSetNameValue(papszOpt, "BLOCKYSIZE",
1438 4 : CPLString().Printf("%d", nBY));
1439 : }
1440 :
1441 22 : CPLString osMskFilename;
1442 22 : osMskFilename.Printf("%s.msk", poDS->GetDescription());
1443 22 : poMaskDS =
1444 22 : poDr->Create(osMskFilename, poDS->GetRasterXSize(),
1445 22 : poDS->GetRasterYSize(), nBands, GDT_Byte, papszOpt);
1446 22 : CSLDestroy(papszOpt);
1447 :
1448 22 : if (poMaskDS == nullptr) // Presumably error already issued.
1449 0 : return CE_Failure;
1450 :
1451 22 : bOwnMaskDS = true;
1452 : }
1453 :
1454 : /* -------------------------------------------------------------------- */
1455 : /* Save the mask flags for this band. */
1456 : /* -------------------------------------------------------------------- */
1457 27 : if (nBand > poMaskDS->GetRasterCount())
1458 : {
1459 1 : CPLError(CE_Failure, CPLE_AppDefined,
1460 : "Attempt to create a mask band for band %d of %s, "
1461 : "but the .msk file has a PER_DATASET mask.",
1462 1 : nBand, poDS->GetDescription());
1463 1 : return CE_Failure;
1464 : }
1465 :
1466 69 : for (int iBand = 0; iBand < poDS->GetRasterCount(); iBand++)
1467 : {
1468 : // we write only the info for this band, unless we are
1469 : // using PER_DATASET in which case we write for all.
1470 43 : if (nBand != iBand + 1 && !(nFlags & GMF_PER_DATASET))
1471 6 : continue;
1472 :
1473 37 : poMaskDS->SetMetadataItem(
1474 74 : CPLString().Printf("INTERNAL_MASK_FLAGS_%d", iBand + 1),
1475 74 : CPLString().Printf("%d", nFlags));
1476 : }
1477 :
1478 26 : return CE_None;
1479 : }
1480 :
1481 : /************************************************************************/
1482 : /* GetMaskBand() */
1483 : /************************************************************************/
1484 :
1485 : // Secret code meaning we don't handle this band.
1486 : constexpr int MISSING_FLAGS = 0x8000;
1487 :
1488 47 : GDALRasterBand *GDALDefaultOverviews::GetMaskBand(int nBand)
1489 :
1490 : {
1491 47 : const int nFlags = GetMaskFlags(nBand);
1492 :
1493 47 : if (poMaskDS == nullptr || nFlags == MISSING_FLAGS)
1494 1 : return nullptr;
1495 :
1496 46 : if (nFlags & GMF_PER_DATASET)
1497 36 : return poMaskDS->GetRasterBand(1);
1498 :
1499 10 : if (nBand > 0)
1500 10 : return poMaskDS->GetRasterBand(nBand);
1501 :
1502 0 : return nullptr;
1503 : }
1504 :
1505 : /************************************************************************/
1506 : /* GetMaskFlags() */
1507 : /************************************************************************/
1508 :
1509 92 : int GDALDefaultOverviews::GetMaskFlags(int nBand)
1510 :
1511 : {
1512 : /* -------------------------------------------------------------------- */
1513 : /* Fetch this band's metadata entry. They are of the form: */
1514 : /* INTERNAL_MASK_FLAGS_n: flags */
1515 : /* -------------------------------------------------------------------- */
1516 92 : if (!HaveMaskFile())
1517 0 : return 0;
1518 :
1519 92 : const char *pszValue = poMaskDS->GetMetadataItem(
1520 184 : CPLString().Printf("INTERNAL_MASK_FLAGS_%d", std::max(nBand, 1)));
1521 :
1522 92 : if (pszValue == nullptr)
1523 1 : return MISSING_FLAGS;
1524 :
1525 91 : return atoi(pszValue);
1526 : }
1527 :
1528 : /************************************************************************/
1529 : /* HaveMaskFile() */
1530 : /* */
1531 : /* Check for a mask file if we haven't already done so. */
1532 : /* Returns TRUE if we have one, otherwise FALSE. */
1533 : /************************************************************************/
1534 :
1535 103253 : int GDALDefaultOverviews::HaveMaskFile(char **papszSiblingFiles,
1536 : const char *pszBasename)
1537 :
1538 : {
1539 : /* -------------------------------------------------------------------- */
1540 : /* Have we already checked for masks? */
1541 : /* -------------------------------------------------------------------- */
1542 103253 : if (bCheckedForMask)
1543 3918 : return poMaskDS != nullptr;
1544 :
1545 99335 : if (papszSiblingFiles == nullptr)
1546 99336 : papszSiblingFiles = papszInitSiblingFiles;
1547 :
1548 : /* -------------------------------------------------------------------- */
1549 : /* Are we an overview? If so we need to find the corresponding */
1550 : /* overview in the base files mask file (if there is one). */
1551 : /* -------------------------------------------------------------------- */
1552 99335 : if (poBaseDS != nullptr && poBaseDS->oOvManager.HaveMaskFile())
1553 : {
1554 4 : GDALRasterBand *const poBaseBand = poBaseDS->GetRasterBand(1);
1555 4 : GDALDataset *poMaskDSTemp = nullptr;
1556 4 : if (poBaseBand != nullptr)
1557 : {
1558 4 : GDALRasterBand *poBaseMask = poBaseBand->GetMaskBand();
1559 4 : if (poBaseMask != nullptr)
1560 : {
1561 4 : const int nOverviewCount = poBaseMask->GetOverviewCount();
1562 6 : for (int iOver = 0; iOver < nOverviewCount; iOver++)
1563 : {
1564 : GDALRasterBand *const poOverBand =
1565 6 : poBaseMask->GetOverview(iOver);
1566 6 : if (poOverBand == nullptr)
1567 0 : continue;
1568 :
1569 10 : if (poOverBand->GetXSize() == poDS->GetRasterXSize() &&
1570 4 : poOverBand->GetYSize() == poDS->GetRasterYSize())
1571 : {
1572 4 : poMaskDSTemp = poOverBand->GetDataset();
1573 4 : break;
1574 : }
1575 : }
1576 : }
1577 : }
1578 :
1579 4 : if (poMaskDSTemp != poDS)
1580 : {
1581 4 : poMaskDS = poMaskDSTemp;
1582 4 : bCheckedForMask = true;
1583 4 : bOwnMaskDS = false;
1584 :
1585 4 : return poMaskDS != nullptr;
1586 : }
1587 : }
1588 :
1589 : /* -------------------------------------------------------------------- */
1590 : /* Are we even initialized? If not, we apparently don't want */
1591 : /* to support overviews and masks. */
1592 : /* -------------------------------------------------------------------- */
1593 99331 : if (poDS == nullptr)
1594 88878 : return FALSE;
1595 :
1596 : /* -------------------------------------------------------------------- */
1597 : /* Check for .msk file. */
1598 : /* -------------------------------------------------------------------- */
1599 10453 : bCheckedForMask = true;
1600 :
1601 10453 : if (pszBasename == nullptr)
1602 10454 : pszBasename = poDS->GetDescription();
1603 :
1604 : // Don't bother checking for masks of masks.
1605 10453 : if (EQUAL(CPLGetExtensionSafe(pszBasename).c_str(), "msk"))
1606 18 : return FALSE;
1607 :
1608 10435 : if (!GDALCanFileAcceptSidecarFile(pszBasename))
1609 1 : return FALSE;
1610 20870 : CPLString osMskFilename;
1611 10435 : osMskFilename.Printf("%s.msk", pszBasename);
1612 :
1613 20869 : std::vector<char> achMskFilename;
1614 10435 : achMskFilename.resize(osMskFilename.size() + 1);
1615 10434 : memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
1616 10435 : osMskFilename.size() + 1);
1617 : bool bExists =
1618 10434 : CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
1619 10434 : osMskFilename = &achMskFilename[0];
1620 :
1621 : #if !defined(_WIN32)
1622 10435 : if (!bExists && !papszSiblingFiles)
1623 : {
1624 2249 : osMskFilename.Printf("%s.MSK", pszBasename);
1625 2249 : memcpy(&(achMskFilename[0]), osMskFilename.c_str(),
1626 2249 : osMskFilename.size() + 1);
1627 : bExists =
1628 2249 : CPL_TO_BOOL(CPLCheckForFile(&achMskFilename[0], papszSiblingFiles));
1629 2249 : osMskFilename = &achMskFilename[0];
1630 : }
1631 : #endif
1632 :
1633 10434 : if (!bExists)
1634 10399 : return FALSE;
1635 :
1636 : /* -------------------------------------------------------------------- */
1637 : /* Open the file. */
1638 : /* -------------------------------------------------------------------- */
1639 35 : poMaskDS = GDALDataset::Open(
1640 : osMskFilename,
1641 35 : GDAL_OF_RASTER | (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE : 0),
1642 35 : nullptr, nullptr, papszInitSiblingFiles);
1643 35 : CPLAssert(poMaskDS != poDS);
1644 :
1645 35 : if (poMaskDS == nullptr)
1646 1 : return FALSE;
1647 :
1648 34 : bOwnMaskDS = true;
1649 :
1650 34 : return TRUE;
1651 : }
1652 :
1653 : /************************************************************************/
1654 : /* GDALGetNormalizedOvrResampling() */
1655 : /************************************************************************/
1656 :
1657 982 : std::string GDALGetNormalizedOvrResampling(const char *pszResampling)
1658 : {
1659 982 : if (pszResampling &&
1660 982 : EQUAL(pszResampling, "AVERAGE_BIT2GRAYSCALE_MINISWHITE"))
1661 0 : return "AVERAGE_BIT2GRAYSCALE_MINISWHITE";
1662 982 : else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2"))
1663 8 : return "AVERAGE_BIT2GRAYSCALE";
1664 974 : else if (pszResampling && STARTS_WITH_CI(pszResampling, "NEAR"))
1665 419 : return "NEAREST";
1666 555 : else if (pszResampling && EQUAL(pszResampling, "AVERAGE_MAGPHASE"))
1667 0 : return "AVERAGE_MAGPHASE";
1668 555 : else if (pszResampling && STARTS_WITH_CI(pszResampling, "AVER"))
1669 258 : return "AVERAGE";
1670 297 : else if (pszResampling && !EQUAL(pszResampling, "NONE"))
1671 : {
1672 334 : return CPLString(pszResampling).toupper();
1673 : }
1674 130 : return std::string();
1675 : }
1676 :
1677 : //! @endcond
|