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

Generated by: LCOV version 1.14