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