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

Generated by: LCOV version 1.14