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

Generated by: LCOV version 1.14