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

Generated by: LCOV version 1.14