LCOV - code coverage report
Current view: top level - apps - gdalalg_raster_pipeline.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 241 248 97.2 %
Date: 2026-02-21 16:21:44 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal "raster pipeline" subcommand
       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_pipeline.h"
      14             : #include "gdalalg_materialize.h"
      15             : #include "gdalalg_raster_read.h"
      16             : #include "gdalalg_raster_calc.h"
      17             : #include "gdalalg_raster_aspect.h"
      18             : #include "gdalalg_raster_blend.h"
      19             : #include "gdalalg_raster_clip.h"
      20             : #include "gdalalg_raster_color_map.h"
      21             : #include "gdalalg_raster_compare.h"
      22             : #include "gdalalg_raster_create.h"
      23             : #include "gdalalg_raster_edit.h"
      24             : #include "gdalalg_raster_fill_nodata.h"
      25             : #include "gdalalg_raster_hillshade.h"
      26             : #include "gdalalg_raster_info.h"
      27             : #include "gdalalg_raster_mosaic.h"
      28             : #include "gdalalg_raster_neighbors.h"
      29             : #include "gdalalg_raster_nodata_to_alpha.h"
      30             : #include "gdalalg_raster_overview.h"
      31             : #include "gdalalg_raster_pansharpen.h"
      32             : #include "gdalalg_raster_proximity.h"
      33             : #include "gdalalg_raster_reclassify.h"
      34             : #include "gdalalg_raster_reproject.h"
      35             : #include "gdalalg_raster_resize.h"
      36             : #include "gdalalg_raster_rgb_to_palette.h"
      37             : #include "gdalalg_raster_roughness.h"
      38             : #include "gdalalg_raster_scale.h"
      39             : #include "gdalalg_raster_select.h"
      40             : #include "gdalalg_raster_set_type.h"
      41             : #include "gdalalg_raster_sieve.h"
      42             : #include "gdalalg_raster_slope.h"
      43             : #include "gdalalg_raster_stack.h"
      44             : #include "gdalalg_raster_tile.h"
      45             : #include "gdalalg_raster_write.h"
      46             : #include "gdalalg_raster_tpi.h"
      47             : #include "gdalalg_raster_tri.h"
      48             : #include "gdalalg_raster_unscale.h"
      49             : #include "gdalalg_raster_update.h"
      50             : #include "gdalalg_raster_viewshed.h"
      51             : #include "gdalalg_tee.h"
      52             : 
      53             : #include "cpl_conv.h"
      54             : #include "cpl_progress.h"
      55             : #include "cpl_string.h"
      56             : #include "cpl_vsi.h"
      57             : #include "gdal_priv.h"
      58             : #include "gdal_utils.h"
      59             : 
      60             : #include <algorithm>
      61             : #include <array>
      62             : #include <cassert>
      63             : 
      64             : //! @cond Doxygen_Suppress
      65             : 
      66             : #ifndef _
      67             : #define _(x) (x)
      68             : #endif
      69             : 
      70             : GDALRasterAlgorithmStepRegistry::~GDALRasterAlgorithmStepRegistry() = default;
      71             : 
      72             : /************************************************************************/
      73             : /*  GDALRasterPipelineStepAlgorithm::GDALRasterPipelineStepAlgorithm()  */
      74             : /************************************************************************/
      75             : 
      76        1988 : GDALRasterPipelineStepAlgorithm::GDALRasterPipelineStepAlgorithm(
      77             :     const std::string &name, const std::string &description,
      78        1988 :     const std::string &helpURL, bool standaloneStep)
      79             :     : GDALRasterPipelineStepAlgorithm(
      80             :           name, description, helpURL,
      81        1988 :           ConstructorOptions().SetStandaloneStep(standaloneStep))
      82             : {
      83        1988 : }
      84             : 
      85             : /************************************************************************/
      86             : /*  GDALRasterPipelineStepAlgorithm::GDALRasterPipelineStepAlgorithm()  */
      87             : /************************************************************************/
      88             : 
      89        5076 : GDALRasterPipelineStepAlgorithm::GDALRasterPipelineStepAlgorithm(
      90             :     const std::string &name, const std::string &description,
      91        5076 :     const std::string &helpURL, const ConstructorOptions &options)
      92        5076 :     : GDALPipelineStepAlgorithm(name, description, helpURL, options)
      93             : {
      94        5076 :     if (m_standaloneStep)
      95             :     {
      96        1622 :         m_supportsStreamedOutput = true;
      97             : 
      98        1622 :         if (m_constructorOptions.addDefaultArguments)
      99             :         {
     100         525 :             AddRasterInputArgs(false, false);
     101         525 :             AddProgressArg();
     102         525 :             AddRasterOutputArgs(false);
     103             :         }
     104             :     }
     105        3454 :     else if (m_constructorOptions.addDefaultArguments)
     106             :     {
     107        1547 :         AddRasterHiddenInputDatasetArg();
     108             :     }
     109        5076 : }
     110             : 
     111             : GDALRasterPipelineStepAlgorithm::~GDALRasterPipelineStepAlgorithm() = default;
     112             : 
     113             : /************************************************************************/
     114             : /*      GDALRasterPipelineStepAlgorithm::SetOutputVRTCompatible()       */
     115             : /************************************************************************/
     116             : 
     117         359 : void GDALRasterPipelineStepAlgorithm::SetOutputVRTCompatible(bool b)
     118             : {
     119         359 :     m_outputVRTCompatible = b;
     120         359 :     if (m_outputFormatArg)
     121             :     {
     122         128 :         m_outputFormatArg->AddMetadataItem(GAAMDI_VRT_COMPATIBLE,
     123         256 :                                            {b ? "true" : "false"});
     124             :     }
     125         359 : }
     126             : 
     127             : /************************************************************************/
     128             : /*      GDALRasterPipelineAlgorithm::GDALRasterPipelineAlgorithm()      */
     129             : /************************************************************************/
     130             : 
     131         146 : GDALRasterPipelineAlgorithm::GDALRasterPipelineAlgorithm(
     132         146 :     bool openForMixedRasterVector)
     133             :     : GDALAbstractPipelineAlgorithm(NAME, DESCRIPTION, HELP_URL,
     134           0 :                                     ConstructorOptions()
     135         146 :                                         .SetAddDefaultArguments(false)
     136         146 :                                         .SetInputDatasetRequired(false)
     137         146 :                                         .SetInputDatasetPositional(false)
     138         292 :                                         .SetInputDatasetMaxCount(INT_MAX))
     139             : {
     140         146 :     m_supportsStreamedOutput = true;
     141             : 
     142         146 :     AddRasterInputArgs(openForMixedRasterVector, /* hiddenForCLI = */ true);
     143         146 :     AddProgressArg();
     144         292 :     AddArg("pipeline", 0, _("Pipeline string"), &m_pipeline)
     145         146 :         .SetHiddenForCLI()
     146         146 :         .SetPositional();
     147         146 :     AddRasterOutputArgs(/* hiddenForCLI = */ true);
     148             : 
     149         146 :     AddOutputStringArg(&m_output).SetHiddenForCLI();
     150         146 :     AddStdoutArg(&m_stdout);
     151             : 
     152         146 :     RegisterAlgorithms(m_stepRegistry, false);
     153         146 : }
     154             : 
     155             : /************************************************************************/
     156             : /*          GDALRasterPipelineAlgorithm::RegisterAlgorithms()           */
     157             : /************************************************************************/
     158             : 
     159             : /* static */
     160         371 : void GDALRasterPipelineAlgorithm::RegisterAlgorithms(
     161             :     GDALRasterAlgorithmStepRegistry &registry, bool forMixedPipeline)
     162             : {
     163         371 :     GDALAlgorithmRegistry::AlgInfo algInfo;
     164             : 
     165             :     const auto addSuffixIfNeeded =
     166        3710 :         [forMixedPipeline](const char *name) -> std::string
     167             :     {
     168        5960 :         return forMixedPipeline ? std::string(name).append(RASTER_SUFFIX)
     169        9670 :                                 : std::string(name);
     170         371 :     };
     171             : 
     172         371 :     registry.Register<GDALRasterReadAlgorithm>(
     173         742 :         addSuffixIfNeeded(GDALRasterReadAlgorithm::NAME));
     174             : 
     175         371 :     registry.Register<GDALRasterCalcAlgorithm>();
     176         371 :     registry.Register<GDALRasterCreateAlgorithm>();
     177             : 
     178         371 :     registry.Register<GDALRasterNeighborsAlgorithm>();
     179             : 
     180         371 :     registry.Register<GDALRasterWriteAlgorithm>(
     181         742 :         addSuffixIfNeeded(GDALRasterWriteAlgorithm::NAME));
     182             : 
     183         371 :     registry.Register<GDALRasterInfoAlgorithm>(
     184         742 :         addSuffixIfNeeded(GDALRasterInfoAlgorithm::NAME));
     185             : 
     186         371 :     registry.Register<GDALRasterAspectAlgorithm>();
     187         371 :     registry.Register<GDALRasterBlendAlgorithm>();
     188             : 
     189         371 :     registry.Register<GDALRasterClipAlgorithm>(
     190         742 :         addSuffixIfNeeded(GDALRasterClipAlgorithm::NAME));
     191             : 
     192         371 :     registry.Register<GDALRasterColorMapAlgorithm>();
     193         371 :     registry.Register<GDALRasterCompareAlgorithm>();
     194             : 
     195         371 :     registry.Register<GDALRasterEditAlgorithm>(
     196         742 :         addSuffixIfNeeded(GDALRasterEditAlgorithm::NAME));
     197             : 
     198         371 :     registry.Register<GDALRasterNoDataToAlphaAlgorithm>();
     199         371 :     registry.Register<GDALRasterFillNodataAlgorithm>();
     200         371 :     registry.Register<GDALRasterHillshadeAlgorithm>();
     201             : 
     202         371 :     registry.Register<GDALMaterializeRasterAlgorithm>(
     203         742 :         addSuffixIfNeeded(GDALMaterializeRasterAlgorithm::NAME));
     204             : 
     205         371 :     registry.Register<GDALRasterMosaicAlgorithm>();
     206         371 :     registry.Register<GDALRasterOverviewAlgorithm>();
     207         371 :     registry.Register<GDALRasterPansharpenAlgorithm>();
     208         371 :     registry.Register<GDALRasterProximityAlgorithm>();
     209         371 :     registry.Register<GDALRasterReclassifyAlgorithm>();
     210             : 
     211         371 :     registry.Register<GDALRasterReprojectAlgorithm>(
     212         742 :         addSuffixIfNeeded(GDALRasterReprojectAlgorithm::NAME));
     213             : 
     214         371 :     registry.Register<GDALRasterResizeAlgorithm>();
     215         371 :     registry.Register<GDALRasterRGBToPaletteAlgorithm>();
     216         371 :     registry.Register<GDALRasterRoughnessAlgorithm>();
     217         371 :     registry.Register<GDALRasterScaleAlgorithm>();
     218             : 
     219         371 :     registry.Register<GDALRasterSelectAlgorithm>(
     220         742 :         addSuffixIfNeeded(GDALRasterSelectAlgorithm::NAME));
     221             : 
     222         371 :     registry.Register<GDALRasterSetTypeAlgorithm>();
     223         371 :     registry.Register<GDALRasterSieveAlgorithm>();
     224         371 :     registry.Register<GDALRasterSlopeAlgorithm>();
     225         371 :     registry.Register<GDALRasterStackAlgorithm>();
     226         371 :     registry.Register<GDALRasterTileAlgorithm>();
     227         371 :     registry.Register<GDALRasterTPIAlgorithm>();
     228         371 :     registry.Register<GDALRasterTRIAlgorithm>();
     229         371 :     registry.Register<GDALRasterUnscaleAlgorithm>();
     230         371 :     registry.Register<GDALRasterUpdateAlgorithm>(
     231         742 :         addSuffixIfNeeded(GDALRasterUpdateAlgorithm::NAME));
     232         371 :     registry.Register<GDALRasterViewshedAlgorithm>();
     233         371 :     registry.Register<GDALTeeRasterAlgorithm>(
     234         742 :         addSuffixIfNeeded(GDALTeeRasterAlgorithm::NAME));
     235         371 : }
     236             : 
     237             : /************************************************************************/
     238             : /*            GDALRasterPipelineAlgorithm::GetUsageForCLI()             */
     239             : /************************************************************************/
     240             : 
     241           8 : std::string GDALRasterPipelineAlgorithm::GetUsageForCLI(
     242             :     bool shortUsage, const UsageOptions &usageOptions) const
     243             : {
     244           8 :     UsageOptions stepUsageOptions;
     245           8 :     stepUsageOptions.isPipelineStep = true;
     246             : 
     247           8 :     if (!m_helpDocCategory.empty() && m_helpDocCategory != "main")
     248             :     {
     249           4 :         auto alg = GetStepAlg(m_helpDocCategory);
     250           2 :         if (alg)
     251             :         {
     252           2 :             alg->SetCallPath({m_helpDocCategory});
     253           1 :             alg->GetArg("help-doc")->Set(true);
     254           1 :             return alg->GetUsageForCLI(shortUsage, stepUsageOptions);
     255             :         }
     256             :         else
     257             :         {
     258           1 :             fprintf(stderr, "ERROR: unknown pipeline step '%s'\n",
     259             :                     m_helpDocCategory.c_str());
     260             :             return CPLSPrintf("ERROR: unknown pipeline step '%s'\n",
     261           1 :                               m_helpDocCategory.c_str());
     262             :         }
     263             :     }
     264             : 
     265           6 :     UsageOptions usageOptionsMain(usageOptions);
     266           6 :     usageOptionsMain.isPipelineMain = true;
     267             :     std::string ret =
     268          12 :         GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptionsMain);
     269           6 :     if (shortUsage)
     270           2 :         return ret;
     271             : 
     272             :     ret += "\n<PIPELINE> is of the form: read|mosaic|stack [READ-OPTIONS] "
     273             :            "( ! <STEP-NAME> [STEP-OPTIONS] )* ! info|compare|tile|write "
     274           4 :            "[WRITE-OPTIONS]\n";
     275             : 
     276           4 :     if (m_helpDocCategory == "main")
     277             :     {
     278           1 :         return ret;
     279             :     }
     280             : 
     281           3 :     ret += '\n';
     282           3 :     ret += "Example: 'gdal raster pipeline --progress ! read in.tif ! \\\n";
     283           3 :     ret += "               reproject --dst-crs=EPSG:32632 ! ";
     284           3 :     ret += "write out.tif --overwrite'\n";
     285           3 :     ret += '\n';
     286           3 :     ret += "Potential steps are:\n";
     287             : 
     288         117 :     for (const std::string &name : m_stepRegistry.GetNames())
     289             :     {
     290         228 :         auto alg = GetStepAlg(name);
     291         114 :         auto [options, maxOptLen] = alg->GetArgNamesForCLI();
     292         114 :         stepUsageOptions.maxOptLen =
     293         114 :             std::max(stepUsageOptions.maxOptLen, maxOptLen);
     294             :     }
     295             : 
     296             :     {
     297           3 :         const auto name = GDALRasterReadAlgorithm::NAME;
     298           3 :         ret += '\n';
     299           6 :         auto alg = GetStepAlg(name);
     300           6 :         alg->SetCallPath({name});
     301           3 :         ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
     302             :     }
     303         117 :     for (const std::string &name : m_stepRegistry.GetNames())
     304             :     {
     305         228 :         auto alg = GetStepAlg(name);
     306         114 :         assert(alg);
     307         129 :         if (alg->CanBeFirstStep() && !alg->CanBeMiddleStep() &&
     308         129 :             !alg->IsHidden() && name != GDALRasterReadAlgorithm::NAME)
     309             :         {
     310           9 :             ret += '\n';
     311          18 :             alg->SetCallPath({name});
     312           9 :             ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
     313             :         }
     314             :     }
     315         117 :     for (const std::string &name : m_stepRegistry.GetNames())
     316             :     {
     317         228 :         auto alg = GetStepAlg(name);
     318         114 :         assert(alg);
     319         114 :         if (alg->CanBeMiddleStep() && !alg->IsHidden())
     320             :         {
     321          90 :             ret += '\n';
     322         180 :             alg->SetCallPath({name});
     323          90 :             ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
     324             :         }
     325             :     }
     326         117 :     for (const std::string &name : m_stepRegistry.GetNames())
     327             :     {
     328         228 :         auto alg = GetStepAlg(name);
     329         114 :         assert(alg);
     330         132 :         if (alg->CanBeLastStep() && !alg->CanBeMiddleStep() &&
     331         132 :             !alg->IsHidden() && name != GDALRasterWriteAlgorithm::NAME)
     332             :         {
     333           9 :             ret += '\n';
     334          18 :             alg->SetCallPath({name});
     335           9 :             ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
     336             :         }
     337             :     }
     338             :     {
     339           3 :         const auto name = GDALRasterWriteAlgorithm::NAME;
     340           3 :         ret += '\n';
     341           6 :         auto alg = GetStepAlg(name);
     342           6 :         alg->SetCallPath({name});
     343           3 :         ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
     344             :     }
     345           3 :     ret += GetUsageForCLIEnd();
     346             : 
     347           3 :     return ret;
     348             : }
     349             : 
     350             : /************************************************************************/
     351             : /*          GDALRasterPipelineNonNativelyStreamingAlgorithm()           */
     352             : /************************************************************************/
     353             : 
     354         305 : GDALRasterPipelineNonNativelyStreamingAlgorithm::
     355             :     GDALRasterPipelineNonNativelyStreamingAlgorithm(
     356             :         const std::string &name, const std::string &description,
     357         305 :         const std::string &helpURL, bool standaloneStep)
     358             :     : GDALRasterPipelineStepAlgorithm(name, description, helpURL,
     359         305 :                                       standaloneStep)
     360             : {
     361         305 : }
     362             : 
     363             : /************************************************************************/
     364             : /*                   IsNativelyStreamingCompatible()                    */
     365             : /************************************************************************/
     366             : 
     367          48 : bool GDALRasterPipelineNonNativelyStreamingAlgorithm::
     368             :     IsNativelyStreamingCompatible() const
     369             : {
     370          48 :     return false;
     371             : }
     372             : 
     373             : /************************************************************************/
     374             : /*                    MustCreateOnDiskTempDataset()                     */
     375             : /************************************************************************/
     376             : 
     377          60 : static bool MustCreateOnDiskTempDataset(int nWidth, int nHeight, int nBands,
     378             :                                         GDALDataType eDT)
     379             : {
     380             :     // Config option mostly for autotest purposes
     381          60 :     if (CPLTestBool(CPLGetConfigOption(
     382             :             "GDAL_RASTER_PIPELINE_USE_GTIFF_FOR_TEMP_DATASET", "NO")))
     383           5 :         return true;
     384             : 
     385             :     // Allow up to 10% of RAM usage for temporary dataset
     386          55 :     const auto nRAM = CPLGetUsablePhysicalRAM() / 10;
     387          55 :     const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
     388          55 :     const bool bOnDisk =
     389         110 :         nBands > 0 && nDTSize > 0 && nRAM > 0 &&
     390          55 :         static_cast<int64_t>(nWidth) * nHeight > nRAM / (nBands * nDTSize);
     391          55 :     return bOnDisk;
     392             : }
     393             : 
     394             : /************************************************************************/
     395             : /*                       CreateTemporaryDataset()                       */
     396             : /************************************************************************/
     397             : 
     398             : std::unique_ptr<GDALDataset>
     399          35 : GDALRasterPipelineNonNativelyStreamingAlgorithm::CreateTemporaryDataset(
     400             :     int nWidth, int nHeight, int nBands, GDALDataType eDT,
     401             :     bool bTiledIfPossible, GDALDataset *poSrcDSForMetadata, bool bCopyMetadata)
     402             : {
     403             :     const bool bOnDisk =
     404          35 :         MustCreateOnDiskTempDataset(nWidth, nHeight, nBands, eDT);
     405          35 :     const char *pszDriverName = bOnDisk ? "GTIFF" : "MEM";
     406             :     GDALDriver *poDriver =
     407          35 :         GetGDALDriverManager()->GetDriverByName(pszDriverName);
     408          70 :     CPLStringList aosOptions;
     409          70 :     std::string osTmpFilename;
     410          35 :     if (bOnDisk)
     411             :     {
     412             :         osTmpFilename =
     413           4 :             CPLGenerateTempFilenameSafe(
     414             :                 poSrcDSForMetadata
     415           4 :                     ? CPLGetBasenameSafe(poSrcDSForMetadata->GetDescription())
     416           2 :                           .c_str()
     417           4 :                     : "") +
     418           2 :             ".tif";
     419           2 :         if (bTiledIfPossible)
     420           2 :             aosOptions.SetNameValue("TILED", "YES");
     421             :         const char *pszCOList =
     422           2 :             poDriver->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
     423             :         aosOptions.SetNameValue("COMPRESS",
     424           2 :                                 pszCOList && strstr(pszCOList, "ZSTD") ? "ZSTD"
     425           4 :                                                                        : "LZW");
     426           2 :         aosOptions.SetNameValue("SPARSE_OK", "YES");
     427             :     }
     428             :     std::unique_ptr<GDALDataset> poOutDS(
     429          35 :         poDriver ? poDriver->Create(osTmpFilename.c_str(), nWidth, nHeight,
     430          35 :                                     nBands, eDT, aosOptions.List())
     431          70 :                  : nullptr);
     432          35 :     if (poOutDS && bOnDisk)
     433             :     {
     434             :         // In file systems that allow it (all but Windows...), we want to
     435             :         // delete the temporary file as soon as soon as possible after
     436             :         // having open it, so that if someone kills the process there are
     437             :         // no temp files left over. If that unlink() doesn't succeed
     438             :         // (on Windows), then the file will eventually be deleted when
     439             :         // poTmpDS is cleaned due to MarkSuppressOnClose().
     440           0 :         VSIUnlink(osTmpFilename.c_str());
     441           0 :         poOutDS->MarkSuppressOnClose();
     442             :     }
     443             : 
     444          35 :     if (poOutDS && poSrcDSForMetadata)
     445             :     {
     446          33 :         poOutDS->SetSpatialRef(poSrcDSForMetadata->GetSpatialRef());
     447          33 :         GDALGeoTransform gt;
     448          33 :         if (poSrcDSForMetadata->GetGeoTransform(gt) == CE_None)
     449          30 :             poOutDS->SetGeoTransform(gt);
     450          33 :         if (const int nGCPCount = poSrcDSForMetadata->GetGCPCount())
     451             :         {
     452           0 :             const auto apsGCPs = poSrcDSForMetadata->GetGCPs();
     453           0 :             if (apsGCPs)
     454             :             {
     455           0 :                 poOutDS->SetGCPs(nGCPCount, apsGCPs,
     456           0 :                                  poSrcDSForMetadata->GetGCPSpatialRef());
     457             :             }
     458             :         }
     459          33 :         if (bCopyMetadata)
     460             :         {
     461          19 :             poOutDS->SetMetadata(poSrcDSForMetadata->GetMetadata());
     462             :         }
     463             :     }
     464             : 
     465          70 :     return poOutDS;
     466             : }
     467             : 
     468             : /************************************************************************/
     469             : /*                        CreateTemporaryCopy()                         */
     470             : /************************************************************************/
     471             : 
     472             : std::unique_ptr<GDALDataset>
     473          25 : GDALRasterPipelineNonNativelyStreamingAlgorithm::CreateTemporaryCopy(
     474             :     GDALAlgorithm *poAlg, GDALDataset *poSrcDS, int nSingleBand,
     475             :     bool bTiledIfPossible, GDALProgressFunc pfnProgress, void *pProgressData)
     476             : {
     477          25 :     const int nBands = nSingleBand > 0 ? 1 : poSrcDS->GetRasterCount();
     478             :     const auto eDT =
     479          25 :         nBands ? poSrcDS->GetRasterBand(1)->GetRasterDataType() : GDT_Unknown;
     480          25 :     const bool bOnDisk = MustCreateOnDiskTempDataset(
     481             :         poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(), nBands, eDT);
     482          25 :     const char *pszDriverName = bOnDisk ? "GTIFF" : "MEM";
     483             : 
     484          50 :     CPLStringList options;
     485          25 :     if (nSingleBand > 0)
     486             :     {
     487          25 :         options.AddString("-b");
     488          25 :         options.AddString(CPLSPrintf("%d", nSingleBand));
     489             :     }
     490             : 
     491          25 :     options.AddString("-of");
     492          25 :     options.AddString(pszDriverName);
     493             : 
     494          50 :     std::string osTmpFilename;
     495          25 :     if (bOnDisk)
     496             :     {
     497             :         osTmpFilename =
     498           3 :             CPLGenerateTempFilenameSafe(
     499           9 :                 CPLGetBasenameSafe(poSrcDS->GetDescription()).c_str()) +
     500           3 :             ".tif";
     501           3 :         if (bTiledIfPossible)
     502             :         {
     503           3 :             options.AddString("-co");
     504           3 :             options.AddString("TILED=YES");
     505             :         }
     506             : 
     507             :         GDALDriver *poDriver =
     508           3 :             GetGDALDriverManager()->GetDriverByName(pszDriverName);
     509             :         const char *pszCOList =
     510           3 :             poDriver ? poDriver->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST)
     511           3 :                      : nullptr;
     512           3 :         options.AddString("-co");
     513           3 :         options.AddString(pszCOList && strstr(pszCOList, "ZSTD")
     514             :                               ? "COMPRESS=ZSTD"
     515           6 :                               : "COMPRESS=LZW");
     516             :     }
     517             : 
     518             :     GDALTranslateOptions *translateOptions =
     519          25 :         GDALTranslateOptionsNew(options.List(), nullptr);
     520             : 
     521          25 :     if (pfnProgress)
     522          12 :         GDALTranslateOptionsSetProgress(translateOptions, pfnProgress,
     523             :                                         pProgressData);
     524             : 
     525             :     std::unique_ptr<GDALDataset> poOutDS(GDALDataset::FromHandle(
     526             :         GDALTranslate(osTmpFilename.c_str(), GDALDataset::ToHandle(poSrcDS),
     527          25 :                       translateOptions, nullptr)));
     528          25 :     GDALTranslateOptionsFree(translateOptions);
     529             : 
     530          25 :     if (!poOutDS)
     531             :     {
     532           2 :         poAlg->ReportError(CE_Failure, CPLE_AppDefined,
     533             :                            "Failed to create temporary dataset");
     534             :     }
     535          23 :     else if (bOnDisk)
     536             :     {
     537             :         // In file systems that allow it (all but Windows...), we want to
     538             :         // delete the temporary file as soon as soon as possible after
     539             :         // having open it, so that if someone kills the process there are
     540             :         // no temp files left over. If that unlink() doesn't succeed
     541             :         // (on Windows), then the file will eventually be deleted when
     542             :         // poTmpDS is cleaned due to MarkSuppressOnClose().
     543           1 :         VSIUnlink(osTmpFilename.c_str());
     544           1 :         poOutDS->MarkSuppressOnClose();
     545             :     }
     546          50 :     return poOutDS;
     547             : }
     548             : 
     549             : //! @endcond

Generated by: LCOV version 1.14