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

Generated by: LCOV version 1.14