LCOV - code coverage report
Current view: top level - apps - gdaladdo.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 362 446 81.2 %
Date: 2025-01-18 12:42:00 Functions: 6 10 60.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Utilities
       4             :  * Purpose:  Command line application to build overviews.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2000, Frank Warmerdam
       9             :  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_string.h"
      15             : #include "gdal_version.h"
      16             : #include "gdal_priv.h"
      17             : #include "commonutils.h"
      18             : #include "vrtdataset.h"
      19             : #include "vrt_priv.h"
      20             : #include "gdalargumentparser.h"
      21             : 
      22             : #include <algorithm>
      23             : 
      24             : /************************************************************************/
      25             : /*                        GDALAddoErrorHandler()                        */
      26             : /************************************************************************/
      27             : 
      28             : class GDALError
      29             : {
      30             :   public:
      31             :     CPLErr m_eErr;
      32             :     CPLErrorNum m_errNum;
      33             :     CPLString m_osMsg;
      34             : 
      35           0 :     explicit GDALError(CPLErr eErr = CE_None, CPLErrorNum errNum = CPLE_None,
      36             :                        const char *pszMsg = "")
      37           0 :         : m_eErr(eErr), m_errNum(errNum), m_osMsg(pszMsg ? pszMsg : "")
      38             :     {
      39           0 :     }
      40             : };
      41             : 
      42             : std::vector<GDALError> aoErrors;
      43             : 
      44           0 : static void CPL_STDCALL GDALAddoErrorHandler(CPLErr eErr, CPLErrorNum errNum,
      45             :                                              const char *pszMsg)
      46             : {
      47           0 :     aoErrors.push_back(GDALError(eErr, errNum, pszMsg));
      48           0 : }
      49             : 
      50             : /************************************************************************/
      51             : /*                              PartialRefresh()                        */
      52             : /************************************************************************/
      53             : 
      54           4 : static bool PartialRefresh(GDALDataset *poDS,
      55             :                            const std::vector<int> &anOvrIndices, int nBandCount,
      56             :                            const int *panBandList, const char *pszResampling,
      57             :                            int nXOff, int nYOff, int nXSize, int nYSize,
      58             :                            GDALProgressFunc pfnProgress, void *pProgressArg)
      59             : {
      60           8 :     std::vector<int> anBandList;
      61           4 :     if (nBandCount == 0)
      62             :     {
      63           8 :         for (int i = 0; i < poDS->GetRasterCount(); ++i)
      64           4 :             anBandList.push_back(i + 1);
      65           4 :         nBandCount = poDS->GetRasterCount();
      66           4 :         panBandList = anBandList.data();
      67             :     }
      68             : 
      69           4 :     int nOvCount = 0;
      70           8 :     for (int i = 0; i < nBandCount; ++i)
      71             :     {
      72           4 :         auto poSrcBand = poDS->GetRasterBand(panBandList[i]);
      73           4 :         if (i == 0)
      74           4 :             nOvCount = poSrcBand->GetOverviewCount();
      75           0 :         else if (nOvCount != poSrcBand->GetOverviewCount())
      76             :         {
      77           0 :             CPLError(CE_Failure, CPLE_AppDefined,
      78             :                      "Not same number of overviews on all bands");
      79           0 :             return false;
      80             :         }
      81             :     }
      82             : 
      83           8 :     std::vector<GDALRasterBand *> apoSrcBands;
      84           8 :     std::vector<GDALRasterBand **> apapoOverviewBands;
      85           8 :     for (int i = 0; i < nBandCount; ++i)
      86             :     {
      87           4 :         auto poSrcBand = poDS->GetRasterBand(panBandList[i]);
      88           4 :         apoSrcBands.push_back(poSrcBand);
      89           0 :         apapoOverviewBands.push_back(static_cast<GDALRasterBand **>(
      90           4 :             CPLMalloc(sizeof(GDALRasterBand *) * anOvrIndices.size())));
      91           4 :         int j = 0;
      92           8 :         for (int nOvrIdx : anOvrIndices)
      93             :         {
      94           4 :             apapoOverviewBands[i][j] = poSrcBand->GetOverview(nOvrIdx);
      95           4 :             ++j;
      96             :         }
      97             :     }
      98             : 
      99           4 :     CPLStringList aosOptions;
     100           4 :     aosOptions.SetNameValue("XOFF", CPLSPrintf("%d", nXOff));
     101           4 :     aosOptions.SetNameValue("YOFF", CPLSPrintf("%d", nYOff));
     102           4 :     aosOptions.SetNameValue("XSIZE", CPLSPrintf("%d", nXSize));
     103           4 :     aosOptions.SetNameValue("YSIZE", CPLSPrintf("%d", nYSize));
     104           4 :     bool bOK = GDALRegenerateOverviewsMultiBand(
     105           4 :                    nBandCount, apoSrcBands.data(),
     106           4 :                    static_cast<int>(anOvrIndices.size()),
     107           4 :                    apapoOverviewBands.data(), pszResampling, pfnProgress,
     108           4 :                    pProgressArg, aosOptions.List()) == CE_None;
     109           8 :     for (auto papoOverviewBands : apapoOverviewBands)
     110           4 :         CPLFree(papoOverviewBands);
     111           4 :     return bOK;
     112             : }
     113             : 
     114             : /************************************************************************/
     115             : /*                           GetOvrIndices()                            */
     116             : /************************************************************************/
     117             : 
     118           4 : static bool GetOvrIndices(GDALDataset *poDS, int nLevelCount,
     119             :                           const int *panLevels, bool bMinSizeSpecified,
     120             :                           int nMinSize, std::vector<int> &anOvrIndices)
     121             : {
     122           4 :     auto poBand = poDS->GetRasterBand(1);
     123           4 :     if (!poBand)
     124             :     {
     125           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Dataset has no bands");
     126           0 :         return false;
     127             :     }
     128           4 :     const int nOvCount = poBand->GetOverviewCount();
     129           4 :     if (nOvCount == 0)
     130             :     {
     131           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Dataset has no overviews");
     132           0 :         return false;
     133             :     }
     134             : 
     135           4 :     if (nLevelCount == 0)
     136             :     {
     137           3 :         if (!bMinSizeSpecified)
     138             :         {
     139           6 :             for (int i = 0; i < nOvCount; ++i)
     140           3 :                 anOvrIndices.push_back(i);
     141             :         }
     142             :         else
     143             :         {
     144           0 :             for (int i = 0; i < nOvCount; i++)
     145             :             {
     146           0 :                 GDALRasterBand *poOverview = poBand->GetOverview(i);
     147           0 :                 if (poOverview == nullptr)
     148           0 :                     continue;
     149           0 :                 if (poOverview->GetXSize() >= nMinSize ||
     150           0 :                     poOverview->GetYSize() >= nMinSize)
     151             :                 {
     152           0 :                     anOvrIndices.push_back(i);
     153             :                 }
     154             :             }
     155             :         }
     156             :     }
     157             :     else
     158             :     {
     159           2 :         for (int i = 0; i < nLevelCount; ++i)
     160             :         {
     161           1 :             const int nLevel = panLevels[i];
     162           1 :             int nIdx = -1;
     163           1 :             for (int j = 0; j < nOvCount; j++)
     164             :             {
     165           1 :                 GDALRasterBand *poOverview = poBand->GetOverview(j);
     166           1 :                 if (poOverview == nullptr)
     167           0 :                     continue;
     168             : 
     169           1 :                 int nOvFactor = GDALComputeOvFactor(
     170             :                     poOverview->GetXSize(), poBand->GetXSize(),
     171             :                     poOverview->GetYSize(), poBand->GetYSize());
     172             : 
     173           1 :                 if (nOvFactor == nLevel ||
     174           0 :                     nOvFactor == GDALOvLevelAdjust2(nLevel, poBand->GetXSize(),
     175             :                                                     poBand->GetYSize()))
     176             :                 {
     177           1 :                     nIdx = j;
     178           1 :                     break;
     179             :                 }
     180             :             }
     181           1 :             if (nIdx < 0)
     182             :             {
     183           0 :                 CPLError(
     184             :                     CE_Failure, CPLE_AppDefined,
     185             :                     "Cannot find overview level with subsampling factor of %d",
     186             :                     nLevel);
     187           0 :                 return false;
     188             :             }
     189           1 :             anOvrIndices.push_back(nIdx);
     190             :         }
     191             :     }
     192           4 :     return true;
     193             : }
     194             : 
     195             : /************************************************************************/
     196             : /*                   PartialRefreshFromSourceTimestamp()                */
     197             : /************************************************************************/
     198             : 
     199           2 : static bool PartialRefreshFromSourceTimestamp(
     200             :     GDALDataset *poDS, const char *pszResampling, int nLevelCount,
     201             :     const int *panLevels, int nBandCount, const int *panBandList,
     202             :     bool bMinSizeSpecified, int nMinSize, GDALProgressFunc pfnProgress,
     203             :     void *pProgressArg)
     204             : {
     205           4 :     std::vector<int> anOvrIndices;
     206           2 :     if (!GetOvrIndices(poDS, nLevelCount, panLevels, bMinSizeSpecified,
     207             :                        nMinSize, anOvrIndices))
     208           0 :         return false;
     209             : 
     210             :     VSIStatBufL sStatVRTOvr;
     211           6 :     std::string osVRTOvr(std::string(poDS->GetDescription()) + ".ovr");
     212           2 :     if (VSIStatL(osVRTOvr.c_str(), &sStatVRTOvr) != 0)
     213             :     {
     214           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s\n",
     215             :                  osVRTOvr.c_str());
     216           0 :         return false;
     217             :     }
     218           2 :     if (sStatVRTOvr.st_mtime == 0)
     219             :     {
     220           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     221             :                  "Cannot get modification time of %s\n", osVRTOvr.c_str());
     222           0 :         return false;
     223             :     }
     224             : 
     225           4 :     std::vector<GTISourceDesc> regions;
     226             : 
     227           2 :     double dfTotalPixels = 0;
     228             : 
     229           2 :     if (dynamic_cast<VRTDataset *>(poDS))
     230             :     {
     231             :         auto poVRTBand =
     232           1 :             dynamic_cast<VRTSourcedRasterBand *>(poDS->GetRasterBand(1));
     233           1 :         if (!poVRTBand)
     234             :         {
     235           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     236             :                      "Band is not a VRTSourcedRasterBand");
     237           0 :             return false;
     238             :         }
     239             : 
     240           3 :         for (int i = 0; i < poVRTBand->nSources; ++i)
     241             :         {
     242             :             auto poSource =
     243           2 :                 dynamic_cast<VRTSimpleSource *>(poVRTBand->papoSources[i]);
     244           2 :             if (poSource)
     245             :             {
     246             :                 VSIStatBufL sStatSource;
     247           2 :                 if (VSIStatL(poSource->GetSourceDatasetName().c_str(),
     248           2 :                              &sStatSource) == 0)
     249             :                 {
     250           2 :                     if (sStatSource.st_mtime > sStatVRTOvr.st_mtime)
     251             :                     {
     252             :                         double dfXOff, dfYOff, dfXSize, dfYSize;
     253           1 :                         poSource->GetDstWindow(dfXOff, dfYOff, dfXSize,
     254             :                                                dfYSize);
     255           1 :                         constexpr double EPS = 1e-8;
     256           1 :                         int nXOff = static_cast<int>(dfXOff + EPS);
     257           1 :                         int nYOff = static_cast<int>(dfYOff + EPS);
     258           1 :                         int nXSize = static_cast<int>(dfXSize + 0.5);
     259           1 :                         int nYSize = static_cast<int>(dfYSize + 0.5);
     260           1 :                         if (nXOff > poDS->GetRasterXSize() ||
     261           1 :                             nYOff > poDS->GetRasterYSize() || nXSize <= 0 ||
     262             :                             nYSize <= 0)
     263             :                         {
     264           0 :                             continue;
     265             :                         }
     266           1 :                         if (nXOff < 0)
     267             :                         {
     268           0 :                             nXSize += nXOff;
     269           0 :                             nXOff = 0;
     270             :                         }
     271           1 :                         if (nXOff > poDS->GetRasterXSize() - nXSize)
     272             :                         {
     273           0 :                             nXSize = poDS->GetRasterXSize() - nXOff;
     274             :                         }
     275           1 :                         if (nYOff < 0)
     276             :                         {
     277           0 :                             nYSize += nYOff;
     278           0 :                             nYOff = 0;
     279             :                         }
     280           1 :                         if (nYOff > poDS->GetRasterYSize() - nYSize)
     281             :                         {
     282           0 :                             nYSize = poDS->GetRasterYSize() - nYOff;
     283             :                         }
     284             : 
     285           1 :                         dfTotalPixels += static_cast<double>(nXSize) * nYSize;
     286           2 :                         GTISourceDesc region;
     287           1 :                         region.osFilename = poSource->GetSourceDatasetName();
     288           1 :                         region.nDstXOff = nXOff;
     289           1 :                         region.nDstYOff = nYOff;
     290           1 :                         region.nDstXSize = nXSize;
     291           1 :                         region.nDstYSize = nYSize;
     292           1 :                         regions.push_back(std::move(region));
     293             :                     }
     294             :                 }
     295             :             }
     296             :         }
     297             :     }
     298             : #ifdef GTI_DRIVER_DISABLED_OR_PLUGIN
     299             :     else if (poDS->GetDriver() &&
     300             :              EQUAL(poDS->GetDriver()->GetDescription(), "GTI"))
     301             :     {
     302             :         CPLError(CE_Failure, CPLE_NotSupported,
     303             :                  "--partial-refresh-from-source-timestamp only works on a GTI "
     304             :                  "dataset if the GTI driver is not built as a plugin, "
     305             :                  "but in core library");
     306             :         return false;
     307             :     }
     308             : #else
     309           1 :     else if (auto poGTIDS = GDALDatasetCastToGTIDataset(poDS))
     310             :     {
     311           1 :         regions = GTIGetSourcesMoreRecentThan(poGTIDS, sStatVRTOvr.st_mtime);
     312           2 :         for (const auto &region : regions)
     313             :         {
     314           1 :             dfTotalPixels +=
     315           1 :                 static_cast<double>(region.nDstXSize) * region.nDstYSize;
     316             :         }
     317             :     }
     318             : #endif
     319             :     else
     320             :     {
     321           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     322             :                  "--partial-refresh-from-source-timestamp only works on a VRT "
     323             :                  "dataset");
     324           0 :         return false;
     325             :     }
     326             : 
     327           2 :     if (!regions.empty())
     328             :     {
     329           2 :         double dfCurPixels = 0;
     330           4 :         for (const auto &region : regions)
     331             :         {
     332           2 :             if (pfnProgress == GDALDummyProgress)
     333             :             {
     334           0 :                 CPLDebug("GDAL", "Refresh from source %s",
     335             :                          region.osFilename.c_str());
     336             :             }
     337             :             else
     338             :             {
     339           2 :                 printf("Refresh from source %s.\n", region.osFilename.c_str());
     340             :             }
     341           2 :             double dfNextCurPixels =
     342             :                 dfCurPixels +
     343           2 :                 static_cast<double>(region.nDstXSize) * region.nDstYSize;
     344           2 :             void *pScaledProgress = GDALCreateScaledProgress(
     345             :                 dfCurPixels / dfTotalPixels, dfNextCurPixels / dfTotalPixels,
     346             :                 pfnProgress, pProgressArg);
     347           4 :             bool bRet = PartialRefresh(
     348             :                 poDS, anOvrIndices, nBandCount, panBandList, pszResampling,
     349           2 :                 region.nDstXOff, region.nDstYOff, region.nDstXSize,
     350           2 :                 region.nDstYSize, GDALScaledProgress, pScaledProgress);
     351           2 :             GDALDestroyScaledProgress(pScaledProgress);
     352           2 :             if (!bRet)
     353           0 :                 return false;
     354           2 :             dfCurPixels = dfNextCurPixels;
     355             :         }
     356             :     }
     357             :     else
     358             :     {
     359           0 :         if (pfnProgress == GDALDummyProgress)
     360             :         {
     361           0 :             CPLDebug("GDAL", "No source is more recent than the overviews");
     362             :         }
     363             :         else
     364             :         {
     365           0 :             printf("No source is more recent than the overviews.\n");
     366             :         }
     367             :     }
     368             : 
     369           2 :     return true;
     370             : }
     371             : 
     372             : /************************************************************************/
     373             : /*                   PartialRefreshFromSourceExtent()                   */
     374             : /************************************************************************/
     375             : 
     376           1 : static bool PartialRefreshFromSourceExtent(
     377             :     GDALDataset *poDS, const CPLStringList &aosSources,
     378             :     const char *pszResampling, int nLevelCount, const int *panLevels,
     379             :     int nBandCount, const int *panBandList, bool bMinSizeSpecified,
     380             :     int nMinSize, GDALProgressFunc pfnProgress, void *pProgressArg)
     381             : {
     382           2 :     std::vector<int> anOvrIndices;
     383           1 :     if (!GetOvrIndices(poDS, nLevelCount, panLevels, bMinSizeSpecified,
     384             :                        nMinSize, anOvrIndices))
     385           0 :         return false;
     386             : 
     387             :     double adfGeoTransform[6];
     388           1 :     if (poDS->GetGeoTransform(adfGeoTransform) != CE_None)
     389             :     {
     390           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Dataset has no geotransform");
     391           0 :         return false;
     392             :     }
     393             :     double adfInvGT[6];
     394           1 :     if (!GDALInvGeoTransform(adfGeoTransform, adfInvGT))
     395             :     {
     396           0 :         return false;
     397             :     }
     398             : 
     399             :     struct Region
     400             :     {
     401             :         std::string osFileName;
     402             :         int nXOff;
     403             :         int nYOff;
     404             :         int nXSize;
     405             :         int nYSize;
     406             :     };
     407             : 
     408           2 :     std::vector<Region> regions;
     409             : 
     410           1 :     double dfTotalPixels = 0;
     411           2 :     for (int i = 0; i < aosSources.size(); ++i)
     412             :     {
     413             :         auto poSrcDS = std::unique_ptr<GDALDataset>(GDALDataset::Open(
     414           1 :             aosSources[i], GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR));
     415           1 :         if (!poSrcDS)
     416           0 :             return false;
     417             : 
     418             :         double adfSrcGT[6];
     419           1 :         if (poSrcDS->GetGeoTransform(adfSrcGT) != CE_None)
     420             :         {
     421           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     422             :                      "Source dataset has no geotransform");
     423           0 :             return false;
     424             :         }
     425             : 
     426           1 :         const double dfULX = adfSrcGT[0];
     427           1 :         const double dfULY = adfSrcGT[3];
     428           2 :         const double dfLRX = adfSrcGT[0] +
     429           1 :                              poSrcDS->GetRasterXSize() * adfSrcGT[1] +
     430           1 :                              poSrcDS->GetRasterYSize() * adfSrcGT[2];
     431           2 :         const double dfLRY = adfSrcGT[3] +
     432           1 :                              poSrcDS->GetRasterXSize() * adfSrcGT[4] +
     433           1 :                              poSrcDS->GetRasterYSize() * adfSrcGT[5];
     434           1 :         const double dfX1 =
     435           1 :             adfInvGT[0] + adfInvGT[1] * dfULX + adfInvGT[2] * dfULY;
     436           1 :         const double dfY1 =
     437           1 :             adfInvGT[3] + adfInvGT[4] * dfULX + adfInvGT[5] * dfULY;
     438           1 :         const double dfX2 =
     439           1 :             adfInvGT[0] + adfInvGT[1] * dfLRX + adfInvGT[2] * dfLRY;
     440           1 :         const double dfY2 =
     441           1 :             adfInvGT[3] + adfInvGT[4] * dfLRX + adfInvGT[5] * dfLRY;
     442           1 :         constexpr double EPS = 1e-8;
     443             :         const int nXOff =
     444           1 :             static_cast<int>(std::max(0.0, std::min(dfX1, dfX2)) + EPS);
     445             :         const int nYOff =
     446           1 :             static_cast<int>(std::max(0.0, std::min(dfY1, dfY2)) + EPS);
     447             :         const int nXSize =
     448           1 :             static_cast<int>(
     449           1 :                 std::ceil(std::min(static_cast<double>(poDS->GetRasterXSize()),
     450           2 :                                    std::max(dfX1, dfX2)) -
     451             :                           EPS)) -
     452           1 :             nXOff;
     453             :         const int nYSize =
     454           1 :             static_cast<int>(
     455           1 :                 std::ceil(std::min(static_cast<double>(poDS->GetRasterYSize()),
     456           2 :                                    std::max(dfY1, dfY2)) -
     457             :                           EPS)) -
     458           1 :             nYOff;
     459             : 
     460           1 :         dfTotalPixels += static_cast<double>(nXSize) * nYSize;
     461           2 :         Region region;
     462           1 :         region.osFileName = aosSources[i];
     463           1 :         region.nXOff = nXOff;
     464           1 :         region.nYOff = nYOff;
     465           1 :         region.nXSize = nXSize;
     466           1 :         region.nYSize = nYSize;
     467           1 :         regions.push_back(std::move(region));
     468             :     }
     469             : 
     470           1 :     double dfCurPixels = 0;
     471           2 :     for (const auto &region : regions)
     472             :     {
     473           1 :         if (pfnProgress == GDALDummyProgress)
     474             :         {
     475           0 :             CPLDebug("GDAL", "Refresh from source %s",
     476             :                      region.osFileName.c_str());
     477             :         }
     478             :         else
     479             :         {
     480           1 :             printf("Refresh from source %s.\n", region.osFileName.c_str());
     481             :         }
     482           1 :         double dfNextCurPixels =
     483           1 :             dfCurPixels + static_cast<double>(region.nXSize) * region.nYSize;
     484             :         // coverity[divide_by_zero]
     485           1 :         void *pScaledProgress = GDALCreateScaledProgress(
     486             :             dfCurPixels / dfTotalPixels, dfNextCurPixels / dfTotalPixels,
     487             :             pfnProgress, pProgressArg);
     488           2 :         bool bRet = PartialRefresh(poDS, anOvrIndices, nBandCount, panBandList,
     489           1 :                                    pszResampling, region.nXOff, region.nYOff,
     490           1 :                                    region.nXSize, region.nYSize,
     491             :                                    GDALScaledProgress, pScaledProgress);
     492           1 :         GDALDestroyScaledProgress(pScaledProgress);
     493           1 :         if (!bRet)
     494           0 :             return false;
     495           1 :         dfCurPixels = dfNextCurPixels;
     496             :     }
     497             : 
     498           1 :     return true;
     499             : }
     500             : 
     501             : /************************************************************************/
     502             : /*                     PartialRefreshFromProjWin()                      */
     503             : /************************************************************************/
     504             : 
     505           1 : static bool PartialRefreshFromProjWin(
     506             :     GDALDataset *poDS, double dfULX, double dfULY, double dfLRX, double dfLRY,
     507             :     const char *pszResampling, int nLevelCount, const int *panLevels,
     508             :     int nBandCount, const int *panBandList, bool bMinSizeSpecified,
     509             :     int nMinSize, GDALProgressFunc pfnProgress, void *pProgressArg)
     510             : {
     511           2 :     std::vector<int> anOvrIndices;
     512           1 :     if (!GetOvrIndices(poDS, nLevelCount, panLevels, bMinSizeSpecified,
     513             :                        nMinSize, anOvrIndices))
     514           0 :         return false;
     515             : 
     516             :     double adfGeoTransform[6];
     517           1 :     if (poDS->GetGeoTransform(adfGeoTransform) != CE_None)
     518             :     {
     519           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Dataset has no geotransform");
     520           0 :         return false;
     521             :     }
     522             :     double adfInvGT[6];
     523           1 :     if (!GDALInvGeoTransform(adfGeoTransform, adfInvGT))
     524             :     {
     525           0 :         return false;
     526             :     }
     527           1 :     const double dfX1 = adfInvGT[0] + adfInvGT[1] * dfULX + adfInvGT[2] * dfULY;
     528           1 :     const double dfY1 = adfInvGT[3] + adfInvGT[4] * dfULX + adfInvGT[5] * dfULY;
     529           1 :     const double dfX2 = adfInvGT[0] + adfInvGT[1] * dfLRX + adfInvGT[2] * dfLRY;
     530           1 :     const double dfY2 = adfInvGT[3] + adfInvGT[4] * dfLRX + adfInvGT[5] * dfLRY;
     531           1 :     constexpr double EPS = 1e-8;
     532             :     const int nXOff =
     533           1 :         static_cast<int>(std::max(0.0, std::min(dfX1, dfX2)) + EPS);
     534             :     const int nYOff =
     535           1 :         static_cast<int>(std::max(0.0, std::min(dfY1, dfY2)) + EPS);
     536           1 :     const int nXSize = static_cast<int>(std::ceil(
     537           1 :                            std::min(static_cast<double>(poDS->GetRasterXSize()),
     538           2 :                                     std::max(dfX1, dfX2)) -
     539             :                            EPS)) -
     540           1 :                        nXOff;
     541           1 :     const int nYSize = static_cast<int>(std::ceil(
     542           1 :                            std::min(static_cast<double>(poDS->GetRasterYSize()),
     543           2 :                                     std::max(dfY1, dfY2)) -
     544             :                            EPS)) -
     545           1 :                        nYOff;
     546           1 :     return PartialRefresh(poDS, anOvrIndices, nBandCount, panBandList,
     547             :                           pszResampling, nXOff, nYOff, nXSize, nYSize,
     548           1 :                           pfnProgress, pProgressArg);
     549             : }
     550             : 
     551             : /************************************************************************/
     552             : /*                                main()                                */
     553             : /************************************************************************/
     554             : 
     555          27 : MAIN_START(nArgc, papszArgv)
     556             : 
     557             : {
     558          27 :     EarlySetConfigOptions(nArgc, papszArgv);
     559          27 :     GDALAllRegister();
     560             : 
     561          27 :     nArgc = GDALGeneralCmdLineProcessor(nArgc, &papszArgv, 0);
     562          27 :     if (nArgc < 1)
     563           2 :         exit(-nArgc);
     564          47 :     CPLStringList aosArgv;
     565          25 :     aosArgv.Assign(papszArgv, /* bAssign = */ true);
     566             : 
     567          72 :     GDALArgumentParser argParser(aosArgv[0], /* bForBinary=*/true);
     568             : 
     569          25 :     argParser.add_description(_("Builds or rebuilds overview images."));
     570             : 
     571          25 :     const char *pszEpilog = _(
     572             :         "Useful configuration variables :\n"
     573             :         "  --config USE_RRD YES : Use Erdas Imagine format (.aux) as overview "
     574             :         "format.\n"
     575             :         "Below, only for external overviews in GeoTIFF format:\n"
     576             :         "  --config COMPRESS_OVERVIEW {JPEG,LZW,PACKBITS,DEFLATE} : TIFF "
     577             :         "compression\n"
     578             :         "  --config PHOTOMETRIC_OVERVIEW {RGB,YCBCR,...} : TIFF photometric "
     579             :         "interp.\n"
     580             :         "  --config INTERLEAVE_OVERVIEW {PIXEL|BAND} : TIFF interleaving "
     581             :         "method\n"
     582             :         "  --config BIGTIFF_OVERVIEW {IF_NEEDED|IF_SAFER|YES|NO} : is BigTIFF "
     583             :         "used\n"
     584             :         "\n"
     585             :         "Examples:\n"
     586             :         " %% gdaladdo -r average abc.tif\n"
     587             :         " %% gdaladdo --config COMPRESS_OVERVIEW JPEG\n"
     588             :         "            --config PHOTOMETRIC_OVERVIEW YCBCR\n"
     589             :         "            --config INTERLEAVE_OVERVIEW PIXEL -ro abc.tif\n"
     590             :         "\n"
     591             :         "For more details, consult https://gdal.org/programs/gdaladdo.html");
     592          25 :     argParser.add_epilog(pszEpilog);
     593             : 
     594          47 :     std::string osResampling;
     595          25 :     argParser.add_argument("-r")
     596          25 :         .store_into(osResampling)
     597             :         .metavar("nearest|average|rms|gauss|bilinear|cubic|cubicspline|lanczos|"
     598          50 :                  "average_magphase|mode")
     599          25 :         .help(_("Select a resampling algorithm."));
     600             : 
     601          25 :     bool bReadOnly = false;
     602          25 :     argParser.add_argument("-ro").store_into(bReadOnly).help(
     603             :         _("Open the dataset in read-only mode, in order to generate external "
     604          25 :           "overview."));
     605             : 
     606          25 :     bool bQuiet = false;
     607          25 :     argParser.add_quiet_argument(&bQuiet);
     608             : 
     609          47 :     std::vector<int> anBandList;
     610          25 :     argParser.add_argument("-b")
     611          25 :         .append()
     612          50 :         .metavar("<band>")
     613             :         .action(
     614           0 :             [&anBandList](const std::string &s)
     615             :             {
     616           0 :                 const int nBand = atoi(s.c_str());
     617           0 :                 if (nBand < 1)
     618             :                 {
     619             :                     throw std::invalid_argument(CPLSPrintf(
     620           0 :                         "Unrecognizable band number (%s).", s.c_str()));
     621             :                 }
     622           0 :                 anBandList.push_back(nBand);
     623          25 :             })
     624          25 :         .help(_("Select input band(s) for overview generation."));
     625             : 
     626          47 :     CPLStringList aosOpenOptions;
     627          25 :     argParser.add_argument("-oo")
     628          25 :         .append()
     629          50 :         .metavar("<NAME=VALUE>")
     630           0 :         .action([&aosOpenOptions](const std::string &s)
     631          25 :                 { aosOpenOptions.AddString(s.c_str()); })
     632          25 :         .help(_("Dataset open option (format-specific)."));
     633             : 
     634          25 :     int nMinSize = 256;
     635          25 :     argParser.add_argument("-minsize")
     636          25 :         .default_value(nMinSize)
     637          50 :         .metavar("<val>")
     638          25 :         .store_into(nMinSize)
     639          25 :         .help(_("Maximum width or height of the smallest overview level."));
     640             : 
     641          25 :     bool bClean = false;
     642          25 :     bool bPartialRefreshFromSourceTimestamp = false;
     643          47 :     std::string osPartialRefreshFromSourceExtent;
     644             : 
     645             :     {
     646          25 :         auto &group = argParser.add_mutually_exclusive_group();
     647          25 :         group.add_argument("-clean").store_into(bClean).help(
     648          25 :             _("Remove all overviews."));
     649             : 
     650          25 :         group.add_argument("--partial-refresh-from-source-timestamp")
     651          25 :             .store_into(bPartialRefreshFromSourceTimestamp)
     652             :             .help(_("Performs a partial refresh of existing overviews, when "
     653          25 :                     "<filename> is a VRT file with an external overview."));
     654             : 
     655          25 :         group.add_argument("--partial-refresh-from-projwin")
     656          50 :             .metavar("<ulx> <uly> <lrx> <lry>")
     657          25 :             .nargs(4)
     658          25 :             .scan<'g', double>()
     659             :             .help(
     660             :                 _("Performs a partial refresh of existing overviews, in the "
     661          25 :                   "region of interest specified by georeference coordinates."));
     662             : 
     663          25 :         group.add_argument("--partial-refresh-from-source-extent")
     664          50 :             .metavar("<filename1>[,<filenameN>]...")
     665          25 :             .store_into(osPartialRefreshFromSourceExtent)
     666             :             .help(
     667             :                 _("Performs a partial refresh of existing overviews, in the "
     668          25 :                   "region of interest specified by one or several filename."));
     669             :     }
     670             : 
     671          47 :     std::string osFilename;
     672          25 :     argParser.add_argument("filename")
     673          25 :         .store_into(osFilename)
     674             :         .help(_("The file to build overviews for (or whose overviews must be "
     675          25 :                 "removed)."));
     676             : 
     677          50 :     argParser.add_argument("level").remaining().metavar("<level>").help(
     678          25 :         _("A list of integral overview levels to build."));
     679             : 
     680             :     try
     681             :     {
     682          25 :         argParser.parse_args(aosArgv);
     683             :     }
     684           0 :     catch (const std::exception &err)
     685             :     {
     686           0 :         argParser.display_error_and_usage(err);
     687           0 :         std::exit(1);
     688             :     }
     689             : 
     690          47 :     std::vector<int> anLevels;
     691          47 :     auto levels = argParser.present<std::vector<std::string>>("level");
     692          25 :     if (levels)
     693             :     {
     694          29 :         for (const auto &level : *levels)
     695             :         {
     696          18 :             if (CPLGetValueType(level.c_str()) != CPL_VALUE_INTEGER)
     697             :             {
     698           1 :                 CPLError(
     699             :                     CE_Failure, CPLE_IllegalArg,
     700             :                     "Value '%s' is not a positive integer subsampling factor",
     701             :                     level.c_str());
     702           1 :                 std::exit(1);
     703             :             }
     704          17 :             anLevels.push_back(atoi(level.c_str()));
     705          17 :             if (anLevels.back() <= 0)
     706             :             {
     707           2 :                 CPLError(
     708             :                     CE_Failure, CPLE_IllegalArg,
     709             :                     "Value '%s' is not a positive integer subsampling factor",
     710             :                     level.c_str());
     711           2 :                 std::exit(1);
     712             :             }
     713          15 :             if (anLevels.back() == 1)
     714             :             {
     715           0 :                 printf(
     716             :                     "Warning: Overview with subsampling factor of 1 requested. "
     717             :                     "This will copy the full resolution dataset in the "
     718             :                     "overview!\n");
     719             :             }
     720             :         }
     721             :     }
     722             : 
     723          22 :     GDALProgressFunc pfnProgress =
     724          22 :         bQuiet ? GDALDummyProgress : GDALTermProgress;
     725          22 :     const bool bMinSizeSpecified = argParser.is_used("-minsize");
     726             : 
     727          22 :     CPLStringList aosSources;
     728          22 :     if (!osPartialRefreshFromSourceExtent.empty())
     729             :     {
     730             :         aosSources = CSLTokenizeString2(
     731           1 :             osPartialRefreshFromSourceExtent.c_str(), ",", 0);
     732             :     }
     733             : 
     734          22 :     bool bPartialRefreshFromProjWin = false;
     735          22 :     double dfULX = 0;
     736          22 :     double dfULY = 0;
     737          22 :     double dfLRX = 0;
     738          22 :     double dfLRY = 0;
     739          22 :     if (auto oProjWin = argParser.present<std::vector<double>>(
     740          44 :             "--partial-refresh-from-projwin"))
     741             :     {
     742           1 :         bPartialRefreshFromProjWin = true;
     743           1 :         dfULX = (*oProjWin)[0];
     744           1 :         dfULY = (*oProjWin)[1];
     745           1 :         dfLRX = (*oProjWin)[2];
     746           1 :         dfLRY = (*oProjWin)[3];
     747             :     }
     748             : 
     749             :     /* -------------------------------------------------------------------- */
     750             :     /*      Open data file.                                                 */
     751             :     /* -------------------------------------------------------------------- */
     752          22 :     GDALDatasetH hDataset = nullptr;
     753          22 :     if (!bReadOnly)
     754             :     {
     755          17 :         CPLPushErrorHandler(GDALAddoErrorHandler);
     756          17 :         CPLSetCurrentErrorHandlerCatchDebug(FALSE);
     757             :         hDataset =
     758          17 :             GDALOpenEx(osFilename.c_str(), GDAL_OF_RASTER | GDAL_OF_UPDATE,
     759          17 :                        nullptr, aosOpenOptions.List(), nullptr);
     760          17 :         CPLPopErrorHandler();
     761          17 :         if (hDataset != nullptr)
     762             :         {
     763          17 :             for (size_t i = 0; i < aoErrors.size(); i++)
     764             :             {
     765           0 :                 CPLError(aoErrors[i].m_eErr, aoErrors[i].m_errNum, "%s",
     766           0 :                          aoErrors[i].m_osMsg.c_str());
     767             :             }
     768             :         }
     769             :     }
     770             : 
     771          22 :     if (hDataset == nullptr)
     772           5 :         hDataset = GDALOpenEx(osFilename.c_str(),
     773             :                               GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR, nullptr,
     774           5 :                               aosOpenOptions.List(), nullptr);
     775          22 :     if (hDataset == nullptr)
     776           0 :         exit(2);
     777             : 
     778          22 :     if (!bClean && osResampling.empty())
     779             :     {
     780           8 :         auto poDS = GDALDataset::FromHandle(hDataset);
     781           8 :         if (poDS->GetRasterCount() > 0)
     782             :         {
     783           8 :             auto poBand = poDS->GetRasterBand(1);
     784           8 :             if (poBand->GetOverviewCount() > 0)
     785             :             {
     786             :                 const char *pszResampling =
     787           2 :                     poBand->GetOverview(0)->GetMetadataItem("RESAMPLING");
     788           2 :                 if (pszResampling)
     789             :                 {
     790           2 :                     osResampling = pszResampling;
     791           2 :                     if (pfnProgress == GDALDummyProgress)
     792           0 :                         CPLDebug("GDAL",
     793             :                                  "Reusing resampling method %s from existing "
     794             :                                  "overview",
     795             :                                  pszResampling);
     796             :                     else
     797           2 :                         printf("Info: reusing resampling method %s from "
     798             :                                "existing overview.\n",
     799             :                                pszResampling);
     800             :                 }
     801             :             }
     802             :         }
     803           8 :         if (osResampling.empty())
     804           6 :             osResampling = "nearest";
     805             :     }
     806             : 
     807             :     /* -------------------------------------------------------------------- */
     808             :     /*      Clean overviews.                                                */
     809             :     /* -------------------------------------------------------------------- */
     810          22 :     int nResultStatus = 0;
     811          22 :     void *pProgressArg = nullptr;
     812          22 :     const int nBandCount = static_cast<int>(anBandList.size());
     813          22 :     if (bClean)
     814             :     {
     815           1 :         if (GDALBuildOverviews(hDataset, "NONE", 0, nullptr, 0, nullptr,
     816           1 :                                pfnProgress, pProgressArg) != CE_None)
     817             :         {
     818           0 :             fprintf(stderr, "Cleaning overviews failed.\n");
     819           0 :             nResultStatus = 200;
     820             :         }
     821             :     }
     822          21 :     else if (bPartialRefreshFromSourceTimestamp)
     823             :     {
     824           2 :         if (!PartialRefreshFromSourceTimestamp(
     825             :                 GDALDataset::FromHandle(hDataset), osResampling.c_str(),
     826           2 :                 static_cast<int>(anLevels.size()), anLevels.data(), nBandCount,
     827           2 :                 anBandList.data(), bMinSizeSpecified, nMinSize, pfnProgress,
     828             :                 pProgressArg))
     829             :         {
     830           0 :             nResultStatus = 1;
     831             :         }
     832             :     }
     833          19 :     else if (bPartialRefreshFromProjWin)
     834             :     {
     835           1 :         if (!PartialRefreshFromProjWin(
     836             :                 GDALDataset::FromHandle(hDataset), dfULX, dfULY, dfLRX, dfLRY,
     837           1 :                 osResampling.c_str(), static_cast<int>(anLevels.size()),
     838           1 :                 anLevels.data(), nBandCount, anBandList.data(),
     839             :                 bMinSizeSpecified, nMinSize, pfnProgress, pProgressArg))
     840             :         {
     841           0 :             nResultStatus = 1;
     842             :         }
     843             :     }
     844          18 :     else if (!aosSources.empty())
     845             :     {
     846           1 :         if (!PartialRefreshFromSourceExtent(
     847             :                 GDALDataset::FromHandle(hDataset), aosSources,
     848           1 :                 osResampling.c_str(), static_cast<int>(anLevels.size()),
     849           1 :                 anLevels.data(), nBandCount, anBandList.data(),
     850             :                 bMinSizeSpecified, nMinSize, pfnProgress, pProgressArg))
     851             :         {
     852           0 :             nResultStatus = 1;
     853             :         }
     854             :     }
     855             :     else
     856             :     {
     857             :         /* --------------------------------------------------------------------
     858             :          */
     859             :         /*      Generate overviews. */
     860             :         /* --------------------------------------------------------------------
     861             :          */
     862             : 
     863             :         // If no levels are specified, reuse the potentially existing ones.
     864          17 :         if (anLevels.empty())
     865             :         {
     866           7 :             auto poDS = GDALDataset::FromHandle(hDataset);
     867           7 :             if (poDS->GetRasterCount() > 0)
     868             :             {
     869           7 :                 auto poBand = poDS->GetRasterBand(1);
     870           7 :                 const int nExistingCount = poBand->GetOverviewCount();
     871           7 :                 if (nExistingCount > 0)
     872             :                 {
     873          12 :                     for (int iOvr = 0; iOvr < nExistingCount; ++iOvr)
     874             :                     {
     875           8 :                         auto poOverview = poBand->GetOverview(iOvr);
     876           8 :                         if (poOverview)
     877             :                         {
     878           8 :                             const int nOvFactor = GDALComputeOvFactor(
     879             :                                 poOverview->GetXSize(), poBand->GetXSize(),
     880           8 :                                 poOverview->GetYSize(), poBand->GetYSize());
     881           8 :                             anLevels.push_back(nOvFactor);
     882             :                         }
     883             :                     }
     884             :                 }
     885             :             }
     886             :         }
     887             : 
     888          17 :         if (anLevels.empty())
     889             :         {
     890           3 :             const int nXSize = GDALGetRasterXSize(hDataset);
     891           3 :             const int nYSize = GDALGetRasterYSize(hDataset);
     892           3 :             int nOvrFactor = 1;
     893           9 :             while (DIV_ROUND_UP(nXSize, nOvrFactor) > nMinSize ||
     894           3 :                    DIV_ROUND_UP(nYSize, nOvrFactor) > nMinSize)
     895             :             {
     896           6 :                 nOvrFactor *= 2;
     897           6 :                 anLevels.push_back(nOvrFactor);
     898             :             }
     899             :         }
     900             : 
     901             :         // Only HFA supports selected layers
     902          17 :         if (nBandCount > 0)
     903           0 :             CPLSetConfigOption("USE_RRD", "YES");
     904             : 
     905          33 :         if (!anLevels.empty() &&
     906          16 :             GDALBuildOverviews(hDataset, osResampling.c_str(),
     907          16 :                                static_cast<int>(anLevels.size()),
     908          16 :                                anLevels.data(), nBandCount, anBandList.data(),
     909             :                                pfnProgress, pProgressArg) != CE_None)
     910             :         {
     911           0 :             fprintf(stderr, "Overview building failed.\n");
     912           0 :             nResultStatus = 100;
     913             :         }
     914             :     }
     915             : 
     916             :     /* -------------------------------------------------------------------- */
     917             :     /*      Cleanup                                                         */
     918             :     /* -------------------------------------------------------------------- */
     919          22 :     if (GDALClose(hDataset) != CE_None)
     920             :     {
     921           0 :         if (nResultStatus == 0)
     922           0 :             nResultStatus = 1;
     923             :     }
     924             : 
     925          22 :     GDALDestroyDriverManager();
     926             : 
     927          22 :     return nResultStatus;
     928             : }
     929             : 
     930           0 : MAIN_END

Generated by: LCOV version 1.14