Coverage Report

Created: 2026-07-25 06:50

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