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

Generated by: LCOV version 1.14