LCOV - code coverage report
Current view: top level - apps - gdalalg_raster_pixel_info.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 508 547 92.9 %
Date: 2026-04-03 14:38:35 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal "raster pixelinfo" 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_pixel_info.h"
      14             : 
      15             : #include "cpl_conv.h"
      16             : #include "cpl_json.h"
      17             : #include "cpl_minixml.h"
      18             : #include "gdal_priv.h"
      19             : #include "ogrsf_frmts.h"
      20             : #include "ogr_spatialref.h"
      21             : 
      22             : #include <algorithm>
      23             : #include <cmath>
      24             : #include <limits>
      25             : #include <set>
      26             : #include <vector>
      27             : 
      28             : //! @cond Doxygen_Suppress
      29             : 
      30             : #ifndef _
      31             : #define _(x) (x)
      32             : #endif
      33             : 
      34             : /************************************************************************/
      35             : /*     GDALRasterPixelInfoAlgorithm::GDALRasterPixelInfoAlgorithm()     */
      36             : /************************************************************************/
      37             : 
      38         120 : GDALRasterPixelInfoAlgorithm::GDALRasterPixelInfoAlgorithm(bool standaloneStep)
      39             :     : GDALPipelineStepAlgorithm(
      40             :           NAME, DESCRIPTION, HELP_URL,
      41           0 :           ConstructorOptions()
      42         120 :               .SetStandaloneStep(standaloneStep)
      43         120 :               .SetAddAppendLayerArgument(false)
      44         120 :               .SetAddOverwriteLayerArgument(false)
      45         120 :               .SetAddUpdateArgument(false)
      46         120 :               .SetAddUpsertArgument(false)
      47         120 :               .SetAddSkipErrorsArgument(false)
      48         360 :               .SetOutputFormatCreateCapability(GDAL_DCAP_CREATE))
      49             : {
      50         120 :     if (standaloneStep)
      51             :     {
      52             :         AddOutputFormatArg(&m_format, false, false,
      53             :                            _("Output format (default is 'GeoJSON' if "
      54          91 :                              "'position-dataset' not specified)"))
      55             :             .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
      56         273 :                              {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE});
      57          91 :         AddOpenOptionsArg(&m_openOptions);
      58          91 :         AddInputFormatsArg(&m_inputFormats)
      59         182 :             .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_RASTER});
      60             :     }
      61             : 
      62         120 :     AddInputDatasetArg(&m_inputDataset, GDAL_OF_RASTER)
      63         240 :         .AddAlias("dataset")
      64         120 :         .SetMinCount(1)
      65         120 :         .SetMaxCount(1);
      66             : 
      67             :     {
      68             :         auto &coordinateDatasetArg =
      69             :             AddArg("position-dataset", '\0',
      70             :                    _("Vector dataset with coordinates"), &m_vectorDataset,
      71         240 :                    GDAL_OF_VECTOR)
      72         120 :                 .SetMutualExclusionGroup("position-dataset-pos");
      73         120 :         if (!standaloneStep)
      74          29 :             coordinateDatasetArg.SetPositional();
      75             : 
      76         120 :         SetAutoCompleteFunctionForFilename(coordinateDatasetArg,
      77             :                                            GDAL_OF_VECTOR);
      78             : 
      79             :         auto &layerArg = AddArg(GDAL_ARG_NAME_INPUT_LAYER, 'l',
      80         240 :                                 _("Input layer name"), &m_inputLayerNames)
      81         120 :                              .SetMaxCount(1)
      82         120 :                              .AddAlias("layer");
      83         120 :         SetAutoCompleteFunctionForLayerName(layerArg, coordinateDatasetArg);
      84             :     }
      85             : 
      86             :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR,
      87         120 :                         /* positionalAndRequired = */ false)
      88         120 :         .SetHiddenForCLI(!standaloneStep);
      89         120 :     if (standaloneStep)
      90             :     {
      91          91 :         AddCreationOptionsArg(&m_creationOptions);
      92          91 :         AddLayerCreationOptionsArg(&m_layerCreationOptions);
      93          91 :         AddOverwriteArg(&m_overwrite);
      94          91 :         AddOutputStringArg(&m_output).SetHiddenForCLI();
      95             :     }
      96             : 
      97         120 :     AddBandArg(&m_band);
      98             :     AddArg("overview", 0, _("Which overview level of source file must be used"),
      99         240 :            &m_overview)
     100         120 :         .SetMinValueIncluded(0);
     101             : 
     102             :     auto &positionArg =
     103         240 :         AddArg("position", 'p', _("Pixel position"), &m_pos)
     104         240 :             .AddAlias("pos")
     105         240 :             .SetMetaVar("<column,line> or <X,Y>")
     106         240 :             .SetMutualExclusionGroup("position-dataset-pos")
     107             :             .AddValidationAction(
     108          51 :                 [this]
     109             :                 {
     110          50 :                     if ((m_pos.size() % 2) != 0)
     111             :                     {
     112           1 :                         ReportError(
     113             :                             CE_Failure, CPLE_IllegalArg,
     114             :                             "An even number of values must be specified "
     115             :                             "for 'position' argument");
     116           1 :                         return false;
     117             :                     }
     118          49 :                     return true;
     119         120 :                 });
     120         120 :     if (standaloneStep)
     121          91 :         positionArg.SetPositional();
     122             : 
     123             :     AddArg("position-crs", 0,
     124             :            _("CRS of position (default is 'pixel' if 'position-dataset' not "
     125             :              "specified)"),
     126         240 :            &m_posCrs)
     127         480 :         .SetIsCRSArg(false, {"pixel", "dataset"})
     128         120 :         .AddHiddenAlias("l_srs");
     129             : 
     130             :     AddArg("resampling", 'r', _("Resampling algorithm for interpolation"),
     131         240 :            &m_resampling)
     132         120 :         .SetDefault(m_resampling)
     133         120 :         .SetChoices("nearest", "bilinear", "cubic", "cubicspline")
     134         120 :         .SetHiddenChoices("near");
     135             : 
     136             :     AddArg(
     137             :         "promote-pixel-value-to-z", 0,
     138             :         _("Whether to set the pixel value as Z component of GeoJSON geometry"),
     139         120 :         &m_promotePixelValueToZ);
     140             : 
     141             :     AddArg("include-field", 0,
     142             :            _("Fields from coordinate dataset to include in output (special "
     143             :              "values: ALL and NONE)"),
     144         240 :            &m_includeFields)
     145         120 :         .SetDefault("ALL");
     146             : 
     147         120 :     AddValidationAction(
     148         184 :         [this]
     149             :         {
     150          63 :             if (m_inputDataset.size() == 1)
     151             :             {
     152          59 :                 if (auto poSrcDS = m_inputDataset[0].GetDatasetRef())
     153             :                 {
     154          57 :                     if (poSrcDS->GetRasterCount() > 0)
     155             :                     {
     156             :                         const int nOvrCount =
     157          56 :                             poSrcDS->GetRasterBand(1)->GetOverviewCount();
     158          59 :                         if (m_overview >= 0 && poSrcDS->GetRasterCount() > 0 &&
     159           3 :                             m_overview >= nOvrCount)
     160             :                         {
     161           2 :                             if (nOvrCount == 0)
     162             :                             {
     163           1 :                                 ReportError(CE_Failure, CPLE_IllegalArg,
     164             :                                             "Source dataset has no overviews. "
     165             :                                             "Argument 'overview' must not be "
     166             :                                             "specified.");
     167             :                             }
     168             :                             else
     169             :                             {
     170           1 :                                 ReportError(
     171             :                                     CE_Failure, CPLE_IllegalArg,
     172             :                                     "Source dataset has only %d overview "
     173             :                                     "level%s. "
     174             :                                     "'overview' "
     175             :                                     "value must be strictly lower than this "
     176             :                                     "number.",
     177             :                                     nOvrCount, nOvrCount > 1 ? "s" : "");
     178             :                             }
     179           2 :                             return false;
     180             :                         }
     181             :                     }
     182             :                     else
     183             :                     {
     184           1 :                         ReportError(CE_Failure, CPLE_IllegalArg,
     185             :                                     "Source dataset has no raster band.");
     186           1 :                         return false;
     187             :                     }
     188             :                 }
     189             :             }
     190          60 :             return true;
     191             :         });
     192         120 : }
     193             : 
     194             : /************************************************************************/
     195             : /*    GDALRasterPixelInfoAlgorithm::~GDALRasterPixelInfoAlgorithm()     */
     196             : /************************************************************************/
     197             : 
     198         149 : GDALRasterPixelInfoAlgorithm::~GDALRasterPixelInfoAlgorithm()
     199             : {
     200         120 :     if (!m_osTmpFilename.empty())
     201             :     {
     202           6 :         VSIRmdir(CPLGetPathSafe(m_osTmpFilename.c_str()).c_str());
     203           6 :         VSIUnlink(m_osTmpFilename.c_str());
     204             :     }
     205         149 : }
     206             : 
     207             : /************************************************************************/
     208             : /*               GDALRasterPixelInfoAlgorithm::RunImpl()                */
     209             : /************************************************************************/
     210             : 
     211          43 : bool GDALRasterPixelInfoAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
     212             :                                            void *pProgressData)
     213             : {
     214          43 :     GDALPipelineStepRunContext stepCtxt;
     215          43 :     stepCtxt.m_pfnProgress = pfnProgress;
     216          43 :     stepCtxt.m_pProgressData = pProgressData;
     217          43 :     return RunPreStepPipelineValidations() && RunStep(stepCtxt);
     218             : }
     219             : 
     220             : /************************************************************************/
     221             : /*               GDALRasterPixelInfoAlgorithm::RunStep()                */
     222             : /************************************************************************/
     223             : 
     224          49 : bool GDALRasterPixelInfoAlgorithm::RunStep(GDALPipelineStepRunContext &)
     225             : {
     226          49 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
     227          49 :     CPLAssert(poSrcDS);
     228             : 
     229          49 :     auto poVectorSrcDS = m_vectorDataset.GetDatasetRef();
     230             : 
     231          49 :     if (m_pos.empty() && !poVectorSrcDS && !IsCalledFromCommandLine())
     232             :     {
     233           2 :         ReportError(
     234             :             CE_Failure, CPLE_AppDefined,
     235             :             "Argument 'position' or 'position-dataset' must be specified.");
     236           2 :         return false;
     237             :     }
     238             : 
     239          47 :     if (!m_standaloneStep)
     240             :     {
     241           5 :         m_format = "MEM";
     242             :     }
     243          42 :     else if (m_outputDataset.GetName().empty() && m_format != "MEM")
     244             :     {
     245          25 :         if (m_format.empty())
     246             :         {
     247          16 :             m_format = "GeoJSON";
     248             :         }
     249           9 :         else if (!EQUAL(m_format.c_str(), "CSV") &&
     250           0 :                  !EQUAL(m_format.c_str(), "GeoJSON"))
     251             :         {
     252           0 :             ReportError(CE_Failure, CPLE_AppDefined,
     253             :                         "Only CSV or GeoJSON output format is allowed when "
     254             :                         "'output' dataset is not specified.");
     255           0 :             return false;
     256             :         }
     257             :     }
     258          17 :     else if (m_format.empty())
     259             :     {
     260             :         const std::string osExt =
     261          26 :             CPLGetExtensionSafe(m_outputDataset.GetName().c_str());
     262          13 :         if (EQUAL(osExt.c_str(), "csv"))
     263           1 :             m_format = "CSV";
     264          12 :         else if (EQUAL(osExt.c_str(), "json"))
     265           1 :             m_format = "GeoJSON";
     266             :     }
     267             : 
     268          47 :     const bool bIsCSV = EQUAL(m_format.c_str(), "CSV");
     269          47 :     const bool bIsGeoJSON = EQUAL(m_format.c_str(), "GeoJSON");
     270             : 
     271          47 :     OGRLayer *poSrcLayer = nullptr;
     272          94 :     std::vector<int> anSrcFieldIndicesToInclude;
     273          94 :     std::vector<int> anMapSrcToDstFields;
     274             : 
     275          47 :     if (poVectorSrcDS)
     276             :     {
     277          20 :         if (m_inputLayerNames.empty())
     278             :         {
     279          18 :             const int nLayerCount = poVectorSrcDS->GetLayerCount();
     280          18 :             if (nLayerCount == 0)
     281             :             {
     282           2 :                 ReportError(CE_Failure, CPLE_AppDefined,
     283             :                             "Dataset '%s' has no vector layer",
     284           2 :                             poVectorSrcDS->GetDescription());
     285           2 :                 return false;
     286             :             }
     287          16 :             else if (nLayerCount > 1)
     288             :             {
     289           1 :                 ReportError(CE_Failure, CPLE_AppDefined,
     290             :                             "Dataset '%s' has more than one vector layer. "
     291             :                             "Please specify the 'input-layer' argument",
     292           1 :                             poVectorSrcDS->GetDescription());
     293           1 :                 return false;
     294             :             }
     295          15 :             poSrcLayer = poVectorSrcDS->GetLayer(0);
     296             :         }
     297             :         else
     298             :         {
     299             :             poSrcLayer =
     300           2 :                 poVectorSrcDS->GetLayerByName(m_inputLayerNames[0].c_str());
     301             :         }
     302          17 :         if (!poSrcLayer)
     303             :         {
     304           2 :             ReportError(
     305             :                 CE_Failure, CPLE_AppDefined, "Cannot find layer '%s' in '%s'",
     306           2 :                 m_inputLayerNames.empty() ? "" : m_inputLayerNames[0].c_str(),
     307           1 :                 poVectorSrcDS->GetDescription());
     308           1 :             return false;
     309             :         }
     310          16 :         if (poSrcLayer->GetGeomType() == wkbNone)
     311             :         {
     312           2 :             ReportError(CE_Failure, CPLE_AppDefined,
     313             :                         "Layer '%s' of '%s' has no geometry column",
     314           2 :                         poSrcLayer->GetName(), poVectorSrcDS->GetDescription());
     315           2 :             return false;
     316             :         }
     317             : 
     318          14 :         if (!GetFieldIndices(m_includeFields, OGRLayer::ToHandle(poSrcLayer),
     319             :                              anSrcFieldIndicesToInclude))
     320             :         {
     321           1 :             return false;
     322             :         }
     323             : 
     324          13 :         if (m_posCrs.empty())
     325             :         {
     326          10 :             const auto poVectorLayerSRS = poSrcLayer->GetSpatialRef();
     327          10 :             if (poVectorLayerSRS)
     328             :             {
     329           4 :                 const char *const apszOptions[] = {"FORMAT=WKT2", nullptr};
     330           4 :                 m_posCrs = poVectorLayerSRS->exportToWkt(apszOptions);
     331             :             }
     332             :         }
     333             :     }
     334             : 
     335          40 :     if (m_posCrs.empty())
     336          28 :         m_posCrs = "pixel";
     337             : 
     338             :     const GDALRIOResampleAlg eInterpolation =
     339          40 :         GDALRasterIOGetResampleAlg(m_resampling.c_str());
     340             : 
     341          40 :     const auto poSrcCRS = poSrcDS->GetSpatialRef();
     342          40 :     GDALGeoTransform gt;
     343          40 :     const bool bHasGT = poSrcDS->GetGeoTransform(gt) == CE_None;
     344          40 :     GDALGeoTransform invGT;
     345             : 
     346          40 :     if (m_posCrs != "pixel")
     347             :     {
     348          10 :         if (!poSrcCRS)
     349             :         {
     350           1 :             ReportError(CE_Failure, CPLE_AppDefined,
     351             :                         "Dataset has no CRS. Only 'position-crs' = 'pixel' is "
     352             :                         "supported.");
     353           1 :             return false;
     354             :         }
     355             : 
     356           9 :         if (!bHasGT)
     357             :         {
     358           1 :             ReportError(CE_Failure, CPLE_AppDefined, "Cannot get geotransform");
     359           1 :             return false;
     360             :         }
     361             : 
     362           8 :         if (!gt.GetInverse(invGT))
     363             :         {
     364           1 :             ReportError(CE_Failure, CPLE_AppDefined,
     365             :                         "Cannot invert geotransform");
     366           1 :             return false;
     367             :         }
     368             :     }
     369             : 
     370          37 :     std::unique_ptr<OGRCoordinateTransformation> poCT;
     371          74 :     OGRSpatialReference oUserCRS;
     372          37 :     if (m_posCrs != "pixel" && m_posCrs != "dataset")
     373             :     {
     374           6 :         oUserCRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     375             :         // Already validated due SetIsCRSArg()
     376           6 :         CPL_IGNORE_RET_VAL(oUserCRS.SetFromUserInput(m_posCrs.c_str()));
     377           6 :         poCT.reset(OGRCreateCoordinateTransformation(&oUserCRS, poSrcCRS));
     378           6 :         if (!poCT)
     379           0 :             return false;
     380             :     }
     381             : 
     382          37 :     if (m_band.empty())
     383             :     {
     384          74 :         for (int i = 1; i <= poSrcDS->GetRasterCount(); ++i)
     385          37 :             m_band.push_back(i);
     386             :     }
     387             : 
     388          37 :     std::unique_ptr<GDALDataset> poOutDS;
     389          37 :     OGRLayer *poOutLayer = nullptr;
     390          37 :     std::unique_ptr<OGRCoordinateTransformation> poCTSrcCRSToOutCRS;
     391             : 
     392             :     const bool isInteractive =
     393          61 :         m_pos.empty() && m_outputDataset.GetName().empty() &&
     394          61 :         IsCalledFromCommandLine() && CPLIsInteractive(stdin);
     395             : 
     396          74 :     std::string osOutFilename = m_outputDataset.GetName();
     397          37 :     if (osOutFilename.empty() && bIsCSV)
     398             :     {
     399           6 :         if (isInteractive)
     400             :         {
     401           0 :             osOutFilename = "/vsistdout/";
     402             :         }
     403             :         else
     404             :         {
     405           6 :             osOutFilename = VSIMemGenerateHiddenFilename("subdir");
     406           6 :             osOutFilename += "/out.csv";
     407           6 :             VSIMkdir(CPLGetPathSafe(osOutFilename.c_str()).c_str(), 0755);
     408           6 :             m_osTmpFilename = osOutFilename;
     409             :         }
     410             :     }
     411             : 
     412          37 :     if (!osOutFilename.empty() || m_format == "MEM" || !m_standaloneStep)
     413             :     {
     414          25 :         if (bIsGeoJSON)
     415             :         {
     416           1 :             m_outputFile.reset(VSIFOpenL(osOutFilename.c_str(), "wb"));
     417           1 :             if (!m_outputFile)
     418             :             {
     419           0 :                 ReportError(CE_Failure, CPLE_FileIO, "Cannot create '%s'",
     420             :                             osOutFilename.c_str());
     421           0 :                 return false;
     422             :             }
     423             :         }
     424             :         else
     425             :         {
     426          24 :             if (m_format.empty())
     427             :             {
     428             :                 const auto aosFormats =
     429             :                     CPLStringList(GDALGetOutputDriversForDatasetName(
     430             :                         osOutFilename.c_str(), GDAL_OF_VECTOR,
     431             :                         /* bSingleMatch = */ true,
     432          10 :                         /* bWarn = */ true));
     433          10 :                 if (aosFormats.size() != 1)
     434             :                 {
     435           1 :                     ReportError(CE_Failure, CPLE_AppDefined,
     436             :                                 "Cannot guess driver for %s",
     437             :                                 osOutFilename.c_str());
     438           1 :                     return false;
     439             :                 }
     440           9 :                 m_format = aosFormats[0];
     441             :             }
     442             : 
     443             :             auto poOutDrv =
     444          23 :                 GetGDALDriverManager()->GetDriverByName(m_format.c_str());
     445          23 :             if (!poOutDrv)
     446             :             {
     447           0 :                 ReportError(CE_Failure, CPLE_AppDefined,
     448             :                             "Cannot find driver %s", m_format.c_str());
     449           0 :                 return false;
     450             :             }
     451          23 :             poOutDS.reset(
     452             :                 poOutDrv->Create(osOutFilename.c_str(), 0, 0, 0, GDT_Unknown,
     453          46 :                                  CPLStringList(m_creationOptions).List()));
     454          23 :             if (!poOutDS)
     455           1 :                 return false;
     456             : 
     457          22 :             std::string osOutLayerName;
     458          22 :             if (EQUAL(m_format.c_str(), "ESRI Shapefile") || bIsCSV ||
     459             :                 !poSrcLayer)
     460             :             {
     461          10 :                 osOutLayerName = CPLGetBasenameSafe(osOutFilename.c_str());
     462             :             }
     463             :             else
     464          12 :                 osOutLayerName = poSrcLayer->GetName();
     465             : 
     466          22 :             const OGRSpatialReference *poOutCRS = nullptr;
     467          22 :             if (!oUserCRS.IsEmpty())
     468           5 :                 poOutCRS = &oUserCRS;
     469          17 :             else if (poSrcLayer)
     470             :             {
     471           7 :                 poOutCRS = poSrcLayer->GetSpatialRef();
     472           7 :                 if (!poOutCRS)
     473           7 :                     poOutCRS = poSrcCRS;
     474             :             }
     475          44 :             poOutLayer = poOutDS->CreateLayer(
     476             :                 osOutLayerName.c_str(), poOutCRS, wkbPoint,
     477          44 :                 CPLStringList(m_layerCreationOptions).List());
     478          22 :             if (!poOutLayer)
     479             :             {
     480           1 :                 ReportError(CE_Failure, CPLE_AppDefined,
     481             :                             "Cannot create layer '%s' in '%s'",
     482             :                             osOutLayerName.c_str(), osOutFilename.c_str());
     483           1 :                 return false;
     484             :             }
     485          21 :             if (poSrcCRS && poOutCRS)
     486             :             {
     487          12 :                 poCTSrcCRSToOutCRS.reset(
     488             :                     OGRCreateCoordinateTransformation(poSrcCRS, poOutCRS));
     489          12 :                 if (!poCTSrcCRSToOutCRS)
     490           0 :                     return false;
     491             :             }
     492             :         }
     493             :     }
     494             : 
     495          34 :     if (poOutLayer)
     496             :     {
     497          21 :         bool bOK = true;
     498             : 
     499          21 :         if (bIsCSV)
     500             :         {
     501          16 :             OGRFieldDefn oFieldLine("geom_x", OFTReal);
     502           8 :             bOK &= poOutLayer->CreateField(&oFieldLine) == OGRERR_NONE;
     503             : 
     504           8 :             OGRFieldDefn oFieldColumn("geom_y", OFTReal);
     505           8 :             bOK &= poOutLayer->CreateField(&oFieldColumn) == OGRERR_NONE;
     506             :         }
     507             : 
     508          21 :         if (poSrcLayer)
     509             :         {
     510          24 :             CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     511          12 :             const auto poSrcLayerDefn = poSrcLayer->GetLayerDefn();
     512          12 :             auto poOutLayerDefn = poOutLayer->GetLayerDefn();
     513             : 
     514          12 :             anMapSrcToDstFields.resize(poSrcLayerDefn->GetFieldCount(), -1);
     515             : 
     516          19 :             for (int nSrcIdx : anSrcFieldIndicesToInclude)
     517             :             {
     518             :                 const auto poSrcFieldDefn =
     519           7 :                     poSrcLayerDefn->GetFieldDefn(nSrcIdx);
     520           7 :                 if (poOutLayer->CreateField(poSrcFieldDefn) == OGRERR_NONE)
     521             :                 {
     522           7 :                     const int nDstIdx = poOutLayerDefn->GetFieldIndex(
     523           7 :                         poSrcFieldDefn->GetNameRef());
     524           7 :                     if (nDstIdx >= 0)
     525           7 :                         anMapSrcToDstFields[nSrcIdx] = nDstIdx;
     526             :                 }
     527             :             }
     528             :         }
     529             :         else
     530             :         {
     531           9 :             OGRFieldDefn oFieldExtraInput("extra_content", OFTString);
     532           9 :             bOK &= poOutLayer->CreateField(&oFieldExtraInput) == OGRERR_NONE;
     533             :         }
     534             : 
     535          21 :         OGRFieldDefn oFieldColumn("column", OFTReal);
     536          21 :         bOK &= poOutLayer->CreateField(&oFieldColumn) == OGRERR_NONE;
     537             : 
     538          21 :         OGRFieldDefn oFieldLine("line", OFTReal);
     539          21 :         bOK &= poOutLayer->CreateField(&oFieldLine) == OGRERR_NONE;
     540             : 
     541          42 :         for (int nBand : m_band)
     542             :         {
     543             :             auto hBand =
     544          21 :                 GDALRasterBand::ToHandle(poSrcDS->GetRasterBand(nBand));
     545          21 :             const bool bIsComplex = CPL_TO_BOOL(
     546             :                 GDALDataTypeIsComplex(GDALGetRasterDataType(hBand)));
     547          21 :             if (bIsComplex)
     548             :             {
     549             :                 OGRFieldDefn oFieldReal(CPLSPrintf("band_%d_real_value", nBand),
     550           6 :                                         OFTReal);
     551           3 :                 bOK &= poOutLayer->CreateField(&oFieldReal) == OGRERR_NONE;
     552             : 
     553             :                 OGRFieldDefn oFieldImag(
     554           3 :                     CPLSPrintf("band_%d_imaginary_value", nBand), OFTReal);
     555           3 :                 bOK &= poOutLayer->CreateField(&oFieldImag) == OGRERR_NONE;
     556             :             }
     557             :             else
     558             :             {
     559             :                 OGRFieldDefn oFieldRaw(CPLSPrintf("band_%d_raw_value", nBand),
     560          36 :                                        OFTReal);
     561          18 :                 bOK &= poOutLayer->CreateField(&oFieldRaw) == OGRERR_NONE;
     562             : 
     563             :                 OGRFieldDefn oFieldUnscaled(
     564          18 :                     CPLSPrintf("band_%d_unscaled_value", nBand), OFTReal);
     565          18 :                 bOK &= poOutLayer->CreateField(&oFieldUnscaled) == OGRERR_NONE;
     566             :             }
     567             :         }
     568             : 
     569          21 :         if (!bOK)
     570             :         {
     571           0 :             ReportError(CE_Failure, CPLE_AppDefined,
     572             :                         "Cannot create fields in output layer");
     573           0 :             return false;
     574             :         }
     575             :     }
     576             : 
     577          68 :     CPLJSONObject oCollection;
     578          34 :     oCollection.Add("type", "FeatureCollection");
     579          34 :     std::unique_ptr<OGRCoordinateTransformation> poCTToWGS84;
     580          34 :     bool canOutputGeoJSONGeom = false;
     581          34 :     if (poSrcCRS && bHasGT)
     582             :     {
     583          32 :         const char *pszAuthName = poSrcCRS->GetAuthorityName(nullptr);
     584          32 :         const char *pszAuthCode = poSrcCRS->GetAuthorityCode(nullptr);
     585          32 :         if (pszAuthName && pszAuthCode && EQUAL(pszAuthName, "EPSG"))
     586             :         {
     587          31 :             canOutputGeoJSONGeom = true;
     588          62 :             CPLJSONObject jCRS;
     589          31 :             CPLJSONObject oProperties;
     590          31 :             if (EQUAL(pszAuthCode, "4326"))
     591           2 :                 oProperties.Add("name", "urn:ogc:def:crs:OGC:1.3:CRS84");
     592             :             else
     593          29 :                 oProperties.Add(
     594             :                     "name",
     595          58 :                     std::string("urn:ogc:def:crs:EPSG::").append(pszAuthCode));
     596          31 :             jCRS.Add("type", "name");
     597          31 :             jCRS.Add("properties", oProperties);
     598          62 :             oCollection.Add("crs", jCRS);
     599             :         }
     600             :         else
     601             :         {
     602           2 :             OGRSpatialReference oCRS;
     603           1 :             oCRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     604           1 :             oCRS.importFromEPSG(4326);
     605           1 :             poCTToWGS84.reset(
     606             :                 OGRCreateCoordinateTransformation(poSrcCRS, &oCRS));
     607           1 :             if (poCTToWGS84)
     608             :             {
     609           1 :                 canOutputGeoJSONGeom = true;
     610           2 :                 CPLJSONObject jCRS;
     611           1 :                 CPLJSONObject oProperties;
     612           1 :                 oProperties.Add("name", "urn:ogc:def:crs:OGC:1.3:CRS84");
     613           1 :                 jCRS.Add("type", "name");
     614           1 :                 jCRS.Add("properties", oProperties);
     615           1 :                 oCollection.Add("crs", jCRS);
     616             :             }
     617             :         }
     618             :     }
     619          68 :     CPLJSONArray oFeatures;
     620          34 :     oCollection.Add("features", oFeatures);
     621             : 
     622             :     char szLine[1024];
     623          34 :     int nLine = 0;
     624          34 :     size_t iVal = 0;
     625          16 :     do
     626             :     {
     627          50 :         double x = 0, y = 0;
     628          50 :         std::string osExtraContent;
     629           0 :         std::unique_ptr<OGRFeature> poSrcFeature;
     630          50 :         if (poSrcLayer)
     631             :         {
     632          26 :             poSrcFeature.reset(poSrcLayer->GetNextFeature());
     633          26 :             if (!poSrcFeature)
     634          13 :                 break;
     635          13 :             const auto poGeom = poSrcFeature->GetGeometryRef();
     636          13 :             if (!poGeom || poGeom->IsEmpty())
     637           0 :                 continue;
     638          13 :             if (wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
     639             :             {
     640          13 :                 x = poGeom->toPoint()->getX();
     641          13 :                 y = poGeom->toPoint()->getY();
     642             :             }
     643             :             else
     644             :             {
     645           0 :                 OGRPoint oPoint;
     646           0 :                 if (poGeom->Centroid(&oPoint) != OGRERR_NONE)
     647           0 :                     return false;
     648           0 :                 x = oPoint.getX();
     649           0 :                 y = oPoint.getY();
     650             :             }
     651             :         }
     652          24 :         else if (iVal + 1 < m_pos.size())
     653             :         {
     654          18 :             x = m_pos[iVal++];
     655          18 :             y = m_pos[iVal++];
     656             :         }
     657             :         else
     658             :         {
     659           6 :             if (CPLIsInteractive(stdin))
     660             :             {
     661           0 :                 if (m_posCrs != "pixel")
     662             :                 {
     663           0 :                     fprintf(stderr, "Enter X Y values separated by space, and "
     664             :                                     "press Return.\n");
     665             :                 }
     666             :                 else
     667             :                 {
     668           0 :                     fprintf(stderr,
     669             :                             "Enter pixel line values separated by space, "
     670             :                             "and press Return.\n");
     671             :                 }
     672             :             }
     673             : 
     674           6 :             if (fgets(szLine, sizeof(szLine) - 1, stdin) && szLine[0] != '\n')
     675             :             {
     676           3 :                 const CPLStringList aosTokens(CSLTokenizeString(szLine));
     677           3 :                 const int nCount = aosTokens.size();
     678             : 
     679           3 :                 ++nLine;
     680           3 :                 if (nCount < 2)
     681             :                 {
     682           0 :                     fprintf(stderr, "Not enough values at line %d\n", nLine);
     683           0 :                     return false;
     684             :                 }
     685             :                 else
     686             :                 {
     687           3 :                     x = CPLAtof(aosTokens[0]);
     688           3 :                     y = CPLAtof(aosTokens[1]);
     689             : 
     690           9 :                     for (int i = 2; i < nCount; ++i)
     691             :                     {
     692           6 :                         if (!osExtraContent.empty())
     693           3 :                             osExtraContent += ' ';
     694           6 :                         osExtraContent += aosTokens[i];
     695             :                     }
     696           6 :                     while (!osExtraContent.empty() &&
     697           3 :                            isspace(static_cast<int>(osExtraContent.back())))
     698             :                     {
     699           0 :                         osExtraContent.pop_back();
     700             :                     }
     701             :                 }
     702             :             }
     703             :             else
     704             :             {
     705           3 :                 break;
     706             :             }
     707             :         }
     708             : 
     709          34 :         const double xOri = x;
     710          34 :         const double yOri = y;
     711          34 :         double dfPixel{0}, dfLine{0};
     712             : 
     713          34 :         if (poCT)
     714             :         {
     715           6 :             if (!poCT->Transform(1, &x, &y, nullptr))
     716           0 :                 return false;
     717             :         }
     718             : 
     719          34 :         if (m_posCrs != "pixel")
     720             :         {
     721           7 :             invGT.Apply(x, y, &dfPixel, &dfLine);
     722             :         }
     723             :         else
     724             :         {
     725          27 :             dfPixel = x;
     726          27 :             dfLine = y;
     727             :         }
     728             :         const int iPixel = static_cast<int>(
     729          68 :             std::clamp(std::floor(dfPixel), static_cast<double>(INT_MIN),
     730          34 :                        static_cast<double>(INT_MAX)));
     731             :         const int iLine = static_cast<int>(
     732          68 :             std::clamp(std::floor(dfLine), static_cast<double>(INT_MIN),
     733          34 :                        static_cast<double>(INT_MAX)));
     734             : 
     735          34 :         CPLJSONObject oFeature;
     736          34 :         CPLJSONObject oProperties;
     737           0 :         std::unique_ptr<OGRFeature> poFeature;
     738          34 :         if (bIsGeoJSON)
     739             :         {
     740          13 :             oFeature.Add("type", "Feature");
     741          13 :             oFeature.Add("properties", oProperties);
     742             :             {
     743          13 :                 CPLJSONArray oArray;
     744          13 :                 oArray.Add(xOri);
     745          13 :                 oArray.Add(yOri);
     746          13 :                 oProperties.Add("input_coordinate", oArray);
     747             :             }
     748          13 :             if (!osExtraContent.empty())
     749           1 :                 oProperties.Add("extra_content", osExtraContent);
     750          13 :             oProperties.Add("column", dfPixel);
     751          13 :             oProperties.Add("line", dfLine);
     752             : 
     753          13 :             if (poSrcFeature)
     754             :             {
     755           8 :                 for (int i : anSrcFieldIndicesToInclude)
     756             :                 {
     757           7 :                     const auto *poFieldDefn = poSrcFeature->GetFieldDefnRef(i);
     758           7 :                     const char *pszName = poFieldDefn->GetNameRef();
     759           7 :                     const auto eType = poFieldDefn->GetType();
     760           7 :                     switch (eType)
     761             :                     {
     762           3 :                         case OFTInteger:
     763             :                         case OFTInteger64:
     764             :                         {
     765           3 :                             if (poFieldDefn->GetSubType() == OFSTBoolean)
     766             :                             {
     767           1 :                                 oProperties.Add(
     768             :                                     pszName,
     769           1 :                                     poSrcFeature->GetFieldAsInteger(i) != 0);
     770             :                             }
     771             :                             else
     772             :                             {
     773           2 :                                 oProperties.Add(
     774             :                                     pszName,
     775             :                                     poSrcFeature->GetFieldAsInteger64(i));
     776             :                             }
     777           3 :                             break;
     778             :                         }
     779             : 
     780           1 :                         case OFTReal:
     781             :                         {
     782           1 :                             oProperties.Add(pszName,
     783             :                                             poSrcFeature->GetFieldAsDouble(i));
     784           1 :                             break;
     785             :                         }
     786             : 
     787           2 :                         case OFTString:
     788             :                         {
     789           2 :                             if (poFieldDefn->GetSubType() != OFSTJSON)
     790             :                             {
     791           1 :                                 oProperties.Add(
     792             :                                     pszName, poSrcFeature->GetFieldAsString(i));
     793           1 :                                 break;
     794             :                             }
     795             :                             else
     796             :                             {
     797             :                                 [[fallthrough]];
     798             :                             }
     799             :                         }
     800             : 
     801             :                         default:
     802             :                         {
     803             :                             char *pszJSON =
     804           2 :                                 poSrcFeature->GetFieldAsSerializedJSon(i);
     805           4 :                             CPLJSONDocument oDoc;
     806           2 :                             if (oDoc.LoadMemory(pszJSON))
     807           2 :                                 oProperties.Add(pszName, oDoc.GetRoot());
     808           2 :                             CPLFree(pszJSON);
     809           2 :                             break;
     810             :                         }
     811             :                     }
     812             :                 }
     813             :             }
     814             :         }
     815             :         else
     816             :         {
     817          21 :             CPLAssert(poOutLayer);
     818             :             poFeature =
     819          21 :                 std::make_unique<OGRFeature>(poOutLayer->GetLayerDefn());
     820             : 
     821          21 :             if (poSrcFeature)
     822             :             {
     823          24 :                 CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
     824          24 :                 poFeature->SetFrom(poSrcFeature.get(),
     825          12 :                                    anMapSrcToDstFields.data());
     826             :             }
     827           9 :             else if (!osExtraContent.empty())
     828             :             {
     829           2 :                 poFeature->SetField("extra_content", osExtraContent.c_str());
     830             :             }
     831             : 
     832          21 :             if (poOutLayer->GetSpatialRef() == nullptr)
     833             :             {
     834           9 :                 if (bIsCSV)
     835             :                 {
     836           8 :                     poFeature->SetField("geom_x", xOri);
     837           8 :                     poFeature->SetField("geom_y", yOri);
     838             :                 }
     839             :                 else
     840             :                 {
     841           2 :                     poFeature->SetGeometry(
     842           2 :                         std::make_unique<OGRPoint>(xOri, yOri));
     843             :                 }
     844             :             }
     845          12 :             else if (bHasGT && poCTSrcCRSToOutCRS)
     846             :             {
     847          12 :                 gt.Apply(dfPixel, dfLine, &x, &y);
     848          12 :                 if (poCTSrcCRSToOutCRS->Transform(1, &x, &y))
     849             :                 {
     850          12 :                     if (bIsCSV)
     851             :                     {
     852           0 :                         poFeature->SetField("geom_x", x);
     853           0 :                         poFeature->SetField("geom_y", y);
     854             :                     }
     855             :                     else
     856             :                     {
     857          24 :                         poFeature->SetGeometry(
     858          24 :                             std::make_unique<OGRPoint>(x, y));
     859             :                     }
     860             :                 }
     861             :             }
     862             : 
     863          21 :             poFeature->SetField("column", dfPixel);
     864          21 :             poFeature->SetField("line", dfLine);
     865             :         }
     866             : 
     867          34 :         CPLJSONArray oBands;
     868             : 
     869          34 :         double zValue = std::numeric_limits<double>::quiet_NaN();
     870          68 :         for (int nBand : m_band)
     871             :         {
     872          34 :             CPLJSONObject oBand;
     873          34 :             oBand.Add("band_number", nBand);
     874             : 
     875             :             auto hBand =
     876          34 :                 GDALRasterBand::ToHandle(poSrcDS->GetRasterBand(nBand));
     877             : 
     878          34 :             int iPixelToQuery = iPixel;
     879          34 :             int iLineToQuery = iLine;
     880             : 
     881          34 :             double dfPixelToQuery = dfPixel;
     882          34 :             double dfLineToQuery = dfLine;
     883             : 
     884          34 :             if (m_overview >= 0 && hBand != nullptr)
     885             :             {
     886           1 :                 GDALRasterBandH hOvrBand = GDALGetOverview(hBand, m_overview);
     887           1 :                 if (hOvrBand != nullptr)
     888             :                 {
     889           1 :                     int nOvrXSize = GDALGetRasterBandXSize(hOvrBand);
     890           1 :                     int nOvrYSize = GDALGetRasterBandYSize(hOvrBand);
     891           1 :                     iPixelToQuery = static_cast<int>(
     892           1 :                         0.5 +
     893           1 :                         1.0 * iPixel / poSrcDS->GetRasterXSize() * nOvrXSize);
     894           1 :                     iLineToQuery = static_cast<int>(
     895           1 :                         0.5 +
     896           1 :                         1.0 * iLine / poSrcDS->GetRasterYSize() * nOvrYSize);
     897           1 :                     if (iPixelToQuery >= nOvrXSize)
     898           0 :                         iPixelToQuery = nOvrXSize - 1;
     899           1 :                     if (iLineToQuery >= nOvrYSize)
     900           0 :                         iLineToQuery = nOvrYSize - 1;
     901           1 :                     dfPixelToQuery =
     902           1 :                         dfPixel / poSrcDS->GetRasterXSize() * nOvrXSize;
     903           1 :                     dfLineToQuery =
     904           1 :                         dfLine / poSrcDS->GetRasterYSize() * nOvrYSize;
     905             :                 }
     906             :                 else
     907             :                 {
     908           0 :                     ReportError(CE_Failure, CPLE_AppDefined,
     909             :                                 "Cannot get overview %d of band %d", m_overview,
     910             :                                 nBand);
     911           0 :                     return false;
     912             :                 }
     913           1 :                 hBand = hOvrBand;
     914             :             }
     915             : 
     916          34 :             double adfPixel[2] = {0, 0};
     917          34 :             const bool bIsComplex = CPL_TO_BOOL(
     918             :                 GDALDataTypeIsComplex(GDALGetRasterDataType(hBand)));
     919             :             int bIgnored;
     920          34 :             const double dfOffset = GDALGetRasterOffset(hBand, &bIgnored);
     921          34 :             const double dfScale = GDALGetRasterScale(hBand, &bIgnored);
     922          34 :             if (GDALRasterInterpolateAtPoint(
     923             :                     hBand, dfPixelToQuery, dfLineToQuery, eInterpolation,
     924          34 :                     &adfPixel[0], &adfPixel[1]) == CE_None)
     925             :             {
     926          32 :                 if (!bIsComplex)
     927             :                 {
     928          29 :                     const double dfUnscaledVal =
     929          29 :                         adfPixel[0] * dfScale + dfOffset;
     930          29 :                     if (m_band.size() == 1 && m_promotePixelValueToZ)
     931           1 :                         zValue = dfUnscaledVal;
     932          29 :                     if (bIsGeoJSON)
     933             :                     {
     934          12 :                         if (GDALDataTypeIsInteger(GDALGetRasterDataType(hBand)))
     935             :                         {
     936          11 :                             oBand.Add("raw_value",
     937          11 :                                       static_cast<GInt64>(adfPixel[0]));
     938             :                         }
     939             :                         else
     940             :                         {
     941           1 :                             oBand.Add("raw_value", adfPixel[0]);
     942             :                         }
     943             : 
     944          12 :                         oBand.Add("unscaled_value", dfUnscaledVal);
     945             :                     }
     946             :                     else
     947             :                     {
     948          17 :                         poFeature->SetField(
     949             :                             CPLSPrintf("band_%d_raw_value", nBand),
     950             :                             adfPixel[0]);
     951          17 :                         poFeature->SetField(
     952             :                             CPLSPrintf("band_%d_unscaled_value", nBand),
     953             :                             dfUnscaledVal);
     954             :                     }
     955             :                 }
     956             :                 else
     957             :                 {
     958           3 :                     if (bIsGeoJSON)
     959             :                     {
     960           1 :                         CPLJSONObject oValue;
     961           1 :                         oValue.Add("real", adfPixel[0]);
     962           1 :                         oValue.Add("imaginary", adfPixel[1]);
     963           1 :                         oBand.Add("value", oValue);
     964             :                     }
     965             :                     else
     966             :                     {
     967           2 :                         poFeature->SetField(
     968             :                             CPLSPrintf("band_%d_real_value", nBand),
     969             :                             adfPixel[0]);
     970           2 :                         poFeature->SetField(
     971             :                             CPLSPrintf("band_%d_imaginary_value", nBand),
     972             :                             adfPixel[1]);
     973             :                     }
     974             :                 }
     975             :             }
     976             : 
     977             :             // Request location info for this location (just a few drivers,
     978             :             // like the VRT driver actually supports this).
     979          68 :             CPLString osItem;
     980          34 :             osItem.Printf("Pixel_%d_%d", iPixelToQuery, iLineToQuery);
     981             : 
     982          34 :             if (const char *pszLI =
     983          34 :                     GDALGetMetadataItem(hBand, osItem, "LocationInfo"))
     984             :             {
     985           4 :                 CPLXMLTreeCloser oTree(CPLParseXMLString(pszLI));
     986             : 
     987           4 :                 if (oTree && oTree->psChild != nullptr &&
     988           6 :                     oTree->eType == CXT_Element &&
     989           2 :                     EQUAL(oTree->pszValue, "LocationInfo"))
     990             :                 {
     991           2 :                     CPLJSONArray oFiles;
     992             : 
     993           2 :                     for (const CPLXMLNode *psNode = oTree->psChild;
     994           4 :                          psNode != nullptr; psNode = psNode->psNext)
     995             :                     {
     996           2 :                         if (psNode->eType == CXT_Element &&
     997           2 :                             EQUAL(psNode->pszValue, "File") &&
     998           2 :                             psNode->psChild != nullptr)
     999             :                         {
    1000           4 :                             char *pszUnescaped = CPLUnescapeString(
    1001           2 :                                 psNode->psChild->pszValue, nullptr, CPLES_XML);
    1002           2 :                             oFiles.Add(pszUnescaped);
    1003           2 :                             CPLFree(pszUnescaped);
    1004             :                         }
    1005             :                     }
    1006             : 
    1007           2 :                     oBand.Add("files", oFiles);
    1008             :                 }
    1009             :                 else
    1010             :                 {
    1011           0 :                     oBand.Add("location_info", pszLI);
    1012             :                 }
    1013             :             }
    1014             : 
    1015          34 :             oBands.Add(oBand);
    1016             :         }
    1017             : 
    1018          34 :         if (bIsGeoJSON)
    1019             :         {
    1020          13 :             oProperties.Add("bands", oBands);
    1021             : 
    1022          13 :             if (canOutputGeoJSONGeom)
    1023             :             {
    1024          12 :                 x = dfPixel;
    1025          12 :                 y = dfLine;
    1026             : 
    1027          12 :                 gt.Apply(x, y, &x, &y);
    1028             : 
    1029          12 :                 if (poCTToWGS84)
    1030           1 :                     poCTToWGS84->Transform(1, &x, &y);
    1031             : 
    1032          24 :                 CPLJSONObject oGeometry;
    1033          12 :                 oFeature.Add("geometry", oGeometry);
    1034          12 :                 oGeometry.Add("type", "Point");
    1035          12 :                 CPLJSONArray oCoordinates;
    1036          12 :                 oCoordinates.Add(x);
    1037          12 :                 oCoordinates.Add(y);
    1038          12 :                 if (!std::isnan(zValue))
    1039           1 :                     oCoordinates.Add(zValue);
    1040          12 :                 oGeometry.Add("coordinates", oCoordinates);
    1041             :             }
    1042             :             else
    1043             :             {
    1044           1 :                 oFeature.AddNull("geometry");
    1045             :             }
    1046             : 
    1047          13 :             if (isInteractive)
    1048             :             {
    1049           0 :                 CPLJSONDocument oDoc;
    1050           0 :                 oDoc.SetRoot(oFeature);
    1051           0 :                 printf("%s\n", oDoc.SaveAsString().c_str());
    1052             :             }
    1053             :             else
    1054             :             {
    1055          13 :                 oFeatures.Add(oFeature);
    1056             :             }
    1057             :         }
    1058             :         else
    1059             :         {
    1060          21 :             if (poOutLayer->CreateFeature(std::move(poFeature)) != OGRERR_NONE)
    1061             :             {
    1062           0 :                 return false;
    1063             :             }
    1064             :         }
    1065             : 
    1066          34 :     } while (m_pos.empty() || iVal + 1 < m_pos.size());
    1067             : 
    1068          34 :     if (bIsGeoJSON && !isInteractive)
    1069             :     {
    1070          26 :         CPLJSONDocument oDoc;
    1071          13 :         oDoc.SetRoot(oCollection);
    1072          26 :         std::string osRet = oDoc.SaveAsString();
    1073          13 :         if (m_outputFile)
    1074           1 :             m_outputFile->Write(osRet.data(), osRet.size());
    1075             :         else
    1076          25 :             m_output = std::move(osRet);
    1077             :     }
    1078          21 :     else if (poOutDS)
    1079             :     {
    1080          27 :         if (m_format != "MEM" && m_outputDataset.GetName().empty() &&
    1081           6 :             m_standaloneStep)
    1082             :         {
    1083           6 :             poOutDS.reset();
    1084           6 :             if (!isInteractive)
    1085             :             {
    1086           6 :                 CPLAssert(!m_osTmpFilename.empty());
    1087             :                 const GByte *pabyData =
    1088           6 :                     VSIGetMemFileBuffer(m_osTmpFilename.c_str(), nullptr,
    1089             :                                         /* bUnlinkAndSeize = */ false);
    1090           6 :                 m_output = reinterpret_cast<const char *>(pabyData);
    1091             :             }
    1092             :         }
    1093             :         else
    1094             :         {
    1095          15 :             m_outputDataset.Set(std::move(poOutDS));
    1096             :         }
    1097             :     }
    1098             : 
    1099          34 :     bool bRet = true;
    1100          34 :     if (m_outputFile)
    1101             :     {
    1102           1 :         bRet = m_outputFile->Close() == 0;
    1103           1 :         if (bRet)
    1104             :         {
    1105           1 :             poOutDS.reset(
    1106           1 :                 GDALDataset::Open(m_outputDataset.GetName().c_str(),
    1107             :                                   GDAL_OF_VECTOR | GDAL_OF_VERBOSE_ERROR));
    1108           1 :             bRet = poOutDS != nullptr;
    1109           1 :             m_outputDataset.Set(std::move(poOutDS));
    1110             :         }
    1111             :     }
    1112             : 
    1113          34 :     return bRet;
    1114             : }
    1115             : 
    1116             : GDALRasterPixelInfoAlgorithmStandalone::
    1117             :     ~GDALRasterPixelInfoAlgorithmStandalone() = default;
    1118             : 
    1119             : //! @endcond

Generated by: LCOV version 1.14