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