LCOV - code coverage report
Current view: top level - apps - gdalalg_raster_edit.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 135 135 100.0 %
Date: 2025-03-28 11:40:40 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  "edit" step of "raster pipeline"
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_raster_edit.h"
      14             : 
      15             : #include "gdal_priv.h"
      16             : #include "gdal_utils.h"
      17             : 
      18             : //! @cond Doxygen_Suppress
      19             : 
      20             : #ifndef _
      21             : #define _(x) (x)
      22             : #endif
      23             : 
      24             : /************************************************************************/
      25             : /*          GDALRasterEditAlgorithm::GDALRasterEditAlgorithm()          */
      26             : /************************************************************************/
      27             : 
      28          30 : GDALRasterEditAlgorithm::GDALRasterEditAlgorithm(bool standaloneStep)
      29             :     : GDALRasterPipelineStepAlgorithm(
      30             :           NAME, DESCRIPTION, HELP_URL,
      31             :           // Avoid automatic addition of input/output arguments
      32          30 :           /*standaloneStep = */ false)
      33             : {
      34          30 :     if (standaloneStep)
      35             :     {
      36          18 :         AddProgressArg();
      37             : 
      38             :         AddArg("dataset", 0,
      39             :                _("Dataset (to be updated in-place, unless --auxiliary)"),
      40          36 :                &m_dataset, GDAL_OF_RASTER | GDAL_OF_UPDATE)
      41          18 :             .SetPositional()
      42          18 :             .SetRequired();
      43             :         AddArg("auxiliary", 0,
      44             :                _("Ask for an auxiliary .aux.xml file to be edited"),
      45          36 :                &m_readOnly)
      46          36 :             .AddHiddenAlias("ro")
      47          18 :             .AddHiddenAlias(GDAL_ARG_NAME_READ_ONLY);
      48             : 
      49          18 :         m_standaloneStep = true;
      50             :     }
      51             : 
      52          60 :     AddArg("crs", 0, _("Override CRS (without reprojection)"), &m_overrideCrs)
      53          60 :         .AddHiddenAlias("a_srs")
      54          30 :         .SetIsCRSArg(/*noneAllowed=*/true);
      55             : 
      56          30 :     AddBBOXArg(&m_bbox);
      57             : 
      58             :     {
      59             :         auto &arg = AddArg("metadata", 0, _("Add/update dataset metadata item"),
      60          60 :                            &m_metadata)
      61          30 :                         .SetMetaVar("<KEY>=<VALUE>");
      62           3 :         arg.AddValidationAction([this, &arg]()
      63          33 :                                 { return ValidateKeyValue(arg); });
      64          30 :         arg.AddHiddenAlias("mo");
      65             :     }
      66             : 
      67             :     AddArg("unset-metadata", 0, _("Remove dataset metadata item"),
      68          60 :            &m_unsetMetadata)
      69          30 :         .SetMetaVar("<KEY>");
      70             : 
      71          30 :     if (standaloneStep)
      72             :     {
      73          36 :         AddArg("stats", 0, _("Compute statistics, using all pixels"), &m_stats)
      74          18 :             .SetMutualExclusionGroup("stats");
      75             :         AddArg("approx-stats", 0,
      76             :                _("Compute statistics, using a subset of pixels"),
      77          36 :                &m_approxStats)
      78          18 :             .SetMutualExclusionGroup("stats");
      79          18 :         AddArg("hist", 0, _("Compute histogram"), &m_hist);
      80             :     }
      81          30 : }
      82             : 
      83             : /************************************************************************/
      84             : /*                GDALRasterEditAlgorithm::RunImpl()                    */
      85             : /************************************************************************/
      86             : 
      87          20 : bool GDALRasterEditAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
      88             :                                       void *pProgressData)
      89             : {
      90          20 :     if (m_standaloneStep)
      91             :     {
      92          15 :         auto poDS = m_dataset.GetDatasetRef();
      93          15 :         CPLAssert(poDS);
      94          15 :         if (poDS->GetAccess() != GA_Update && !m_readOnly)
      95             :         {
      96           1 :             ReportError(CE_Failure, CPLE_AppDefined,
      97             :                         "Dataset should be opened in update mode unless "
      98             :                         "--auxiliary is set");
      99           1 :             return false;
     100             :         }
     101             : 
     102          14 :         if (m_overrideCrs == "null" || m_overrideCrs == "none")
     103             :         {
     104           2 :             if (poDS->SetSpatialRef(nullptr) != CE_None)
     105             :             {
     106           1 :                 ReportError(CE_Failure, CPLE_AppDefined,
     107             :                             "SetSpatialRef(%s) failed", m_overrideCrs.c_str());
     108           1 :                 return false;
     109             :             }
     110             :         }
     111          12 :         else if (!m_overrideCrs.empty())
     112             :         {
     113           2 :             OGRSpatialReference oSRS;
     114           2 :             oSRS.SetFromUserInput(m_overrideCrs.c_str());
     115           2 :             oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     116           2 :             if (poDS->SetSpatialRef(&oSRS) != CE_None)
     117             :             {
     118           1 :                 ReportError(CE_Failure, CPLE_AppDefined,
     119             :                             "SetSpatialRef(%s) failed", m_overrideCrs.c_str());
     120           1 :                 return false;
     121             :             }
     122             :         }
     123             : 
     124          12 :         if (!m_bbox.empty())
     125             :         {
     126           3 :             if (poDS->GetRasterXSize() == 0 || poDS->GetRasterYSize() == 0)
     127             :             {
     128           1 :                 ReportError(
     129             :                     CE_Failure, CPLE_AppDefined,
     130             :                     "Cannot set extent because dataset has 0x0 dimension");
     131           2 :                 return false;
     132             :             }
     133             :             double adfGT[6];
     134           2 :             adfGT[0] = m_bbox[0];
     135           2 :             adfGT[1] = (m_bbox[2] - m_bbox[0]) / poDS->GetRasterXSize();
     136           2 :             adfGT[2] = 0;
     137           2 :             adfGT[3] = m_bbox[3];
     138           2 :             adfGT[4] = 0;
     139           2 :             adfGT[5] = -(m_bbox[3] - m_bbox[1]) / poDS->GetRasterYSize();
     140           2 :             if (poDS->SetGeoTransform(adfGT) != CE_None)
     141             :             {
     142           1 :                 ReportError(CE_Failure, CPLE_AppDefined,
     143             :                             "Setting extent failed");
     144           1 :                 return false;
     145             :             }
     146             :         }
     147             : 
     148          20 :         const CPLStringList aosMD(m_metadata);
     149          12 :         for (const auto &[key, value] : cpl::IterateNameValue(aosMD))
     150             :         {
     151           3 :             if (poDS->SetMetadataItem(key, value) != CE_None)
     152             :             {
     153           1 :                 ReportError(CE_Failure, CPLE_AppDefined,
     154             :                             "SetMetadataItem('%s', '%s') failed", key, value);
     155           1 :                 return false;
     156             :             }
     157             :         }
     158             : 
     159          10 :         for (const std::string &key : m_unsetMetadata)
     160             :         {
     161           2 :             if (poDS->SetMetadataItem(key.c_str(), nullptr) != CE_None)
     162             :             {
     163           1 :                 ReportError(CE_Failure, CPLE_AppDefined,
     164             :                             "SetMetadataItem('%s', NULL) failed", key.c_str());
     165           1 :                 return false;
     166             :             }
     167             :         }
     168             : 
     169           8 :         const int nBands = poDS->GetRasterCount();
     170           8 :         int nCurProgress = 0;
     171           8 :         const double dfTotalProgress =
     172           8 :             ((m_stats || m_approxStats) ? nBands : 0) + (m_hist ? nBands : 0);
     173           8 :         bool ret = true;
     174           8 :         if (m_stats || m_approxStats)
     175             :         {
     176           4 :             for (int i = 0; (i < nBands) && ret; ++i)
     177             :             {
     178           4 :                 void *pScaledProgress = GDALCreateScaledProgress(
     179             :                     nCurProgress / dfTotalProgress,
     180           2 :                     (nCurProgress + 1) / dfTotalProgress, pfnProgress,
     181             :                     pProgressData);
     182           2 :                 ++nCurProgress;
     183           2 :                 double dfMin = 0.0;
     184           2 :                 double dfMax = 0.0;
     185           2 :                 double dfMean = 0.0;
     186           2 :                 double dfStdDev = 0.0;
     187           2 :                 ret = poDS->GetRasterBand(i + 1)->ComputeStatistics(
     188           2 :                           m_approxStats, &dfMin, &dfMax, &dfMean, &dfStdDev,
     189           2 :                           GDALScaledProgress, pScaledProgress) == CE_None;
     190           2 :                 GDALDestroyScaledProgress(pScaledProgress);
     191             :             }
     192             :         }
     193           8 :         if (m_hist)
     194             :         {
     195           2 :             for (int i = 0; (i < nBands) && ret; ++i)
     196             :             {
     197           2 :                 void *pScaledProgress = GDALCreateScaledProgress(
     198             :                     nCurProgress / dfTotalProgress,
     199           1 :                     (nCurProgress + 1) / dfTotalProgress, pfnProgress,
     200             :                     pProgressData);
     201           1 :                 ++nCurProgress;
     202           1 :                 double dfMin = 0.0;
     203           1 :                 double dfMax = 0.0;
     204           1 :                 int nBucketCount = 0;
     205           1 :                 GUIntBig *panHistogram = nullptr;
     206           1 :                 ret = poDS->GetRasterBand(i + 1)->GetDefaultHistogram(
     207             :                           &dfMin, &dfMax, &nBucketCount, &panHistogram, TRUE,
     208           1 :                           GDALScaledProgress, pScaledProgress) == CE_None;
     209           1 :                 if (ret)
     210             :                 {
     211           2 :                     ret = poDS->GetRasterBand(i + 1)->SetDefaultHistogram(
     212           1 :                               dfMin, dfMax, nBucketCount, panHistogram) ==
     213             :                           CE_None;
     214             :                 }
     215           1 :                 CPLFree(panHistogram);
     216           1 :                 GDALDestroyScaledProgress(pScaledProgress);
     217             :             }
     218             :         }
     219             : 
     220           8 :         return ret;
     221             :     }
     222             :     else
     223             :     {
     224           5 :         return RunStep(pfnProgress, pProgressData);
     225             :     }
     226             : }
     227             : 
     228             : /************************************************************************/
     229             : /*                GDALRasterEditAlgorithm::RunStep()                    */
     230             : /************************************************************************/
     231             : 
     232           5 : bool GDALRasterEditAlgorithm::RunStep(GDALProgressFunc, void *)
     233             : {
     234           5 :     CPLAssert(m_inputDataset.GetDatasetRef());
     235           5 :     CPLAssert(m_outputDataset.GetName().empty());
     236           5 :     CPLAssert(!m_outputDataset.GetDatasetRef());
     237             : 
     238           5 :     CPLStringList aosOptions;
     239           5 :     aosOptions.AddString("-of");
     240           5 :     aosOptions.AddString("VRT");
     241           5 :     if (!m_overrideCrs.empty())
     242             :     {
     243           2 :         aosOptions.AddString("-a_srs");
     244           2 :         aosOptions.AddString(m_overrideCrs.c_str());
     245             :     }
     246           5 :     if (!m_bbox.empty())
     247             :     {
     248           1 :         aosOptions.AddString("-a_ullr");
     249           1 :         aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[0]));  // upper-left X
     250           1 :         aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[3]));  // upper-left Y
     251           1 :         aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[2]));  // lower-right X
     252           1 :         aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[1]));  // lower-right Y
     253             :     }
     254             : 
     255           7 :     for (const auto &val : m_metadata)
     256             :     {
     257           2 :         aosOptions.AddString("-mo");
     258           2 :         aosOptions.AddString(val.c_str());
     259             :     }
     260             : 
     261           6 :     for (const std::string &key : m_unsetMetadata)
     262             :     {
     263           1 :         aosOptions.AddString("-mo");
     264           1 :         aosOptions.AddString((key + "=").c_str());
     265             :     }
     266             : 
     267             :     GDALTranslateOptions *psOptions =
     268           5 :         GDALTranslateOptionsNew(aosOptions.List(), nullptr);
     269             : 
     270           5 :     GDALDatasetH hSrcDS = GDALDataset::ToHandle(m_inputDataset.GetDatasetRef());
     271             :     auto poRetDS =
     272           5 :         GDALDataset::FromHandle(GDALTranslate("", hSrcDS, psOptions, nullptr));
     273           5 :     GDALTranslateOptionsFree(psOptions);
     274           5 :     const bool ok = poRetDS != nullptr;
     275           5 :     if (ok)
     276           5 :         m_outputDataset.Set(std::unique_ptr<GDALDataset>(poRetDS));
     277             : 
     278          10 :     return ok;
     279             : }
     280             : 
     281             : //! @endcond

Generated by: LCOV version 1.14