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

Generated by: LCOV version 1.14