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

Generated by: LCOV version 1.14