LCOV - code coverage report
Current view: top level - apps - gdalalg_raster_overview_add.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 140 146 95.9 %
Date: 2026-06-03 12:46:18 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal "raster overview add" subcommand
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_raster_overview.h"
      14             : #include "gdalalg_raster_overview_add.h"
      15             : 
      16             : #include "cpl_string.h"
      17             : #include "gdal_priv.h"
      18             : 
      19             : //! @cond Doxygen_Suppress
      20             : 
      21             : #ifndef _
      22             : #define _(x) (x)
      23             : #endif
      24             : 
      25           0 : bool GDALRasterOverviewAlgorithm::RunStep(GDALPipelineStepRunContext &)
      26             : {
      27           0 :     CPLError(CE_Failure, CPLE_AppDefined,
      28             :              "The Run() method should not be called directly on the \"gdal "
      29             :              "raster overview\" program.");
      30           0 :     return false;
      31             : }
      32             : 
      33             : GDALRasterOverviewAlgorithmStandalone::
      34             :     ~GDALRasterOverviewAlgorithmStandalone() = default;
      35             : 
      36             : /************************************************************************/
      37             : /*                   GDALRasterOverviewAlgorithmAdd()                   */
      38             : /************************************************************************/
      39             : 
      40          85 : GDALRasterOverviewAlgorithmAdd::GDALRasterOverviewAlgorithmAdd(
      41          85 :     bool standaloneStep)
      42             :     : GDALRasterPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
      43           0 :                                       ConstructorOptions()
      44          85 :                                           .SetStandaloneStep(standaloneStep)
      45         170 :                                           .SetAddDefaultArguments(false))
      46             : {
      47          85 :     if (standaloneStep)
      48          75 :         AddProgressArg();
      49             : 
      50          85 :     AddOpenOptionsArg(&m_openOptions);
      51             :     auto &datasetArg =
      52             :         AddInputDatasetArg(
      53             :             &m_inputDataset, GDAL_OF_RASTER | GDAL_OF_UPDATE,
      54             :             /* positionalAndRequired = */ standaloneStep,
      55          85 :             _("Dataset (to be updated in-place, unless --external)"))
      56         170 :             .AddAlias("dataset")
      57          85 :             .SetMaxCount(1);
      58          85 :     if (!standaloneStep)
      59             :     {
      60          10 :         datasetArg.SetPositional();
      61          10 :         datasetArg.SetHidden();
      62             :     }
      63             : 
      64          85 :     constexpr const char *OVERVIEW_SRC_LEVELS_MUTEX = "overview-src-levels";
      65             : 
      66             :     auto &overviewSrcArg =
      67             :         AddArg("overview-src", 0, _("Source overview dataset"),
      68         170 :                &m_overviewSources, GDAL_OF_RASTER)
      69          85 :             .SetMutualExclusionGroup(OVERVIEW_SRC_LEVELS_MUTEX);
      70          85 :     SetAutoCompleteFunctionForFilename(overviewSrcArg, GDAL_OF_RASTER);
      71             : 
      72          85 :     if (standaloneStep)
      73             :     {
      74         150 :         AddArg("external", 0, _("Add external overviews"), &m_readOnly)
      75         150 :             .AddHiddenAlias("ro")
      76          75 :             .AddHiddenAlias(GDAL_ARG_NAME_READ_ONLY);
      77             :     }
      78             : 
      79         170 :     AddArg("resampling", 'r', _("Resampling method"), &m_resampling)
      80             :         .SetChoices("nearest", "average", "cubic", "cubicspline", "lanczos",
      81          85 :                     "bilinear", "gauss", "average_magphase", "rms", "mode")
      82          85 :         .SetHiddenChoices("near", "none");
      83             : 
      84         170 :     AddArg("levels", 0, _("Levels / decimation factors"), &m_levels)
      85          85 :         .SetMinValueIncluded(2)
      86          85 :         .SetMutualExclusionGroup(OVERVIEW_SRC_LEVELS_MUTEX);
      87             :     AddArg("min-size", 0,
      88             :            _("Maximum width or height of the smallest overview level."),
      89         170 :            &m_minSize)
      90          85 :         .SetMinValueIncluded(1);
      91             : 
      92          85 :     if (standaloneStep)
      93             :     {
      94             :         auto &ovrCreationOptionArg =
      95             :             AddArg(GDAL_ARG_NAME_CREATION_OPTION, 0,
      96         150 :                    _("Overview creation option"), &m_creationOptions)
      97         150 :                 .AddAlias("co")
      98         150 :                 .SetMetaVar("<KEY>=<VALUE>")
      99          75 :                 .SetPackedValuesAllowed(false);
     100             :         ovrCreationOptionArg.AddValidationAction(
     101           5 :             [this, &ovrCreationOptionArg]()
     102          80 :             { return ParseAndValidateKeyValue(ovrCreationOptionArg); });
     103             : 
     104             :         ovrCreationOptionArg.SetAutoCompleteFunction(
     105           6 :             [this](const std::string &currentValue)
     106             :             {
     107           2 :                 std::vector<std::string> oRet;
     108             : 
     109           2 :                 const std::string osDSName = m_inputDataset.size() == 1
     110           2 :                                                  ? m_inputDataset[0].GetName()
     111           6 :                                                  : std::string();
     112           4 :                 const std::string osExt = CPLGetExtensionSafe(osDSName.c_str());
     113           2 :                 if (!osExt.empty())
     114             :                 {
     115           2 :                     std::set<std::string> oVisitedExtensions;
     116           2 :                     auto poDM = GetGDALDriverManager();
     117         233 :                     for (int i = 0; i < poDM->GetDriverCount(); ++i)
     118             :                     {
     119         232 :                         auto poDriver = poDM->GetDriver(i);
     120         232 :                         if (poDriver->GetMetadataItem(GDAL_DCAP_RASTER))
     121             :                         {
     122             :                             const char *pszExtensions =
     123         160 :                                 poDriver->GetMetadataItem(GDAL_DMD_EXTENSIONS);
     124         160 :                             if (pszExtensions)
     125             :                             {
     126             :                                 const CPLStringList aosExts(
     127         105 :                                     CSLTokenizeString2(pszExtensions, " ", 0));
     128         232 :                                 for (const char *pszExt : cpl::Iterate(aosExts))
     129             :                                 {
     130         133 :                                     if (EQUAL(pszExt, osExt.c_str()) &&
     131           4 :                                         !cpl::contains(oVisitedExtensions,
     132             :                                                        pszExt))
     133             :                                     {
     134           2 :                                         oVisitedExtensions.insert(pszExt);
     135           2 :                                         if (AddOptionsSuggestions(
     136             :                                                 poDriver->GetMetadataItem(
     137           2 :                                                     GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST),
     138             :                                                 GDAL_OF_RASTER, currentValue,
     139             :                                                 oRet))
     140             :                                         {
     141           1 :                                             return oRet;
     142             :                                         }
     143           1 :                                         break;
     144             :                                     }
     145             :                                 }
     146             :                             }
     147             :                         }
     148             :                     }
     149             :                 }
     150             : 
     151           1 :                 return oRet;
     152          75 :             });
     153             :     }
     154          85 : }
     155             : 
     156             : /************************************************************************/
     157             : /*              GDALRasterOverviewAlgorithmAdd::RunStep()               */
     158             : /************************************************************************/
     159             : 
     160          27 : bool GDALRasterOverviewAlgorithmAdd::RunStep(GDALPipelineStepRunContext &ctxt)
     161             : {
     162          27 :     GDALProgressFunc pfnProgress = ctxt.m_pfnProgress;
     163          27 :     void *pProgressData = ctxt.m_pProgressData;
     164          27 :     auto poDS = m_inputDataset[0].GetDatasetRef();
     165          27 :     CPLAssert(poDS);
     166             : 
     167          54 :     CPLStringList aosOptions(m_creationOptions);
     168          27 :     if (m_readOnly)
     169             :     {
     170           7 :         auto poDriver = poDS->GetDriver();
     171           7 :         if (poDriver)
     172             :         {
     173             :             const char *pszOptionList =
     174           7 :                 poDriver->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST);
     175           7 :             if (pszOptionList)
     176             :             {
     177           7 :                 if (strstr(pszOptionList, "<Value>EXTERNAL</Value>") == nullptr)
     178             :                 {
     179           1 :                     ReportError(CE_Failure, CPLE_NotSupported,
     180             :                                 "Driver %s does not support external overviews",
     181           1 :                                 poDriver->GetDescription());
     182           1 :                     return false;
     183             :                 }
     184           6 :                 else if (aosOptions.FetchNameValue("LOCATION") == nullptr)
     185             :                 {
     186           6 :                     aosOptions.SetNameValue("LOCATION", "EXTERNAL");
     187             :                 }
     188             :             }
     189             :         }
     190             :     }
     191             : 
     192          52 :     std::string resampling = m_resampling;
     193          26 :     if (resampling.empty() && poDS->GetRasterCount() > 0)
     194             :     {
     195          22 :         auto poBand = poDS->GetRasterBand(1);
     196          22 :         if (poBand->GetOverviewCount() > 0)
     197             :         {
     198             :             const char *pszResampling =
     199           5 :                 poBand->GetOverview(0)->GetMetadataItem("RESAMPLING");
     200           5 :             if (pszResampling)
     201             :             {
     202           1 :                 resampling = pszResampling;
     203           1 :                 CPLDebug("GDAL",
     204             :                          "Reusing resampling method %s from existing "
     205             :                          "overview",
     206             :                          pszResampling);
     207             :             }
     208             :         }
     209             :     }
     210          26 :     if (resampling.empty())
     211          21 :         resampling = "nearest";
     212             : 
     213          26 :     if (!m_overviewSources.empty())
     214             :     {
     215          14 :         std::vector<GDALDataset *> apoDS;
     216          28 :         for (auto &val : m_overviewSources)
     217             :         {
     218          14 :             CPLAssert(val.GetDatasetRef());
     219          14 :             apoDS.push_back(val.GetDatasetRef());
     220             :         }
     221          14 :         return poDS->AddOverviews(apoDS, pfnProgress, pProgressData, nullptr) ==
     222          14 :                CE_None;
     223             :     }
     224             : 
     225          24 :     std::vector<int> levels = m_levels;
     226             : 
     227             :     // If no levels are specified, reuse the potentially existing ones.
     228          12 :     if (levels.empty() && poDS->GetRasterCount() > 0)
     229             :     {
     230           5 :         auto poBand = poDS->GetRasterBand(1);
     231           5 :         const int nExistingCount = poBand->GetOverviewCount();
     232           5 :         if (nExistingCount > 0)
     233             :         {
     234           2 :             for (int iOvr = 0; iOvr < nExistingCount; ++iOvr)
     235             :             {
     236           1 :                 auto poOverview = poBand->GetOverview(iOvr);
     237           1 :                 if (poOverview)
     238             :                 {
     239           1 :                     const int nOvFactor = GDALComputeOvFactor(
     240             :                         poOverview->GetXSize(), poBand->GetXSize(),
     241           1 :                         poOverview->GetYSize(), poBand->GetYSize());
     242           1 :                     levels.push_back(nOvFactor);
     243             :                 }
     244             :             }
     245             :         }
     246             :     }
     247             : 
     248          12 :     if (levels.empty())
     249             :     {
     250           4 :         const int nXSize = poDS->GetRasterXSize();
     251           4 :         const int nYSize = poDS->GetRasterYSize();
     252           4 :         int nOvrFactor = 1;
     253           9 :         while (DIV_ROUND_UP(nXSize, nOvrFactor) > m_minSize ||
     254           4 :                DIV_ROUND_UP(nYSize, nOvrFactor) > m_minSize)
     255             :         {
     256           5 :             nOvrFactor *= 2;
     257           5 :             levels.push_back(nOvrFactor);
     258             :         }
     259             :     }
     260             : 
     261          12 :     if (!m_standaloneStep && !levels.empty())
     262             :     {
     263           1 :         auto poVRTDriver = GetGDALDriverManager()->GetDriverByName("VRT");
     264           1 :         if (!poVRTDriver)
     265             :         {
     266           0 :             ReportError(CE_Failure, CPLE_AppDefined,
     267             :                         "VRT driver not available");
     268           0 :             return false;
     269             :         }
     270             :         auto poVRTDS = std::unique_ptr<GDALDataset>(poVRTDriver->CreateCopy(
     271           1 :             "", poDS, false, nullptr, nullptr, nullptr));
     272           1 :         bool bRet = poVRTDS != nullptr;
     273           1 :         if (bRet)
     274             :         {
     275           1 :             aosOptions.SetNameValue("VIRTUAL", "YES");
     276           1 :             bRet = GDALBuildOverviewsEx(
     277             :                        GDALDataset::ToHandle(poVRTDS.get()), resampling.c_str(),
     278           1 :                        static_cast<int>(levels.size()), levels.data(), 0,
     279           1 :                        nullptr, nullptr, nullptr, aosOptions.List()) == CE_None;
     280           1 :             if (bRet)
     281           1 :                 m_outputDataset.Set(std::move(poVRTDS));
     282             :         }
     283           1 :         return bRet;
     284             :     }
     285             :     else
     286             :     {
     287             :         const auto ret =
     288          22 :             levels.empty() ||
     289          11 :             GDALBuildOverviewsEx(
     290             :                 GDALDataset::ToHandle(poDS), resampling.c_str(),
     291          11 :                 static_cast<int>(levels.size()), levels.data(), 0, nullptr,
     292          11 :                 pfnProgress, pProgressData, aosOptions.List()) == CE_None;
     293          11 :         if (ret)
     294          11 :             m_outputDataset.Set(poDS);
     295          11 :         return ret;
     296             :     }
     297             : }
     298             : 
     299             : /************************************************************************/
     300             : /*              GDALRasterOverviewAlgorithmAdd::RunImpl()               */
     301             : /************************************************************************/
     302             : 
     303          26 : bool GDALRasterOverviewAlgorithmAdd::RunImpl(GDALProgressFunc pfnProgress,
     304             :                                              void *pProgressData)
     305             : {
     306          26 :     GDALPipelineStepRunContext stepCtxt;
     307          26 :     stepCtxt.m_pfnProgress = pfnProgress;
     308          26 :     stepCtxt.m_pProgressData = pProgressData;
     309          52 :     return RunStep(stepCtxt);
     310             : }
     311             : 
     312             : GDALRasterOverviewAlgorithmAddStandalone::
     313             :     ~GDALRasterOverviewAlgorithmAddStandalone() = default;
     314             : 
     315             : //! @endcond

Generated by: LCOV version 1.14