Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: High Performance Image Reprojector
4 : * Purpose: Implementation of high level convenience APIs for warper.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "gdalwarper.h"
16 :
17 : #include <stdlib.h>
18 : #include <string.h>
19 :
20 : #include <algorithm>
21 : #include <cmath>
22 : #include <limits>
23 :
24 : #include "cpl_conv.h"
25 : #include "cpl_error.h"
26 : #include "cpl_float.h"
27 : #include "cpl_mask.h"
28 : #include "cpl_minixml.h"
29 : #include "cpl_progress.h"
30 : #include "cpl_string.h"
31 : #include "cpl_vsi.h"
32 : #include "gdal.h"
33 : #include "gdal_priv.h"
34 : #include "ogr_api.h"
35 : #include "ogr_core.h"
36 : #include "vrtdataset.h" // for VRTSerializeNoData
37 :
38 : #if (defined(__x86_64) || defined(_M_X64))
39 : #include <emmintrin.h>
40 : #endif
41 :
42 : /************************************************************************/
43 : /* GDALReprojectImage() */
44 : /************************************************************************/
45 :
46 : /**
47 : * Reproject image.
48 : *
49 : * This is a convenience function utilizing the GDALWarpOperation class to
50 : * reproject an image from a source to a destination. In particular, this
51 : * function takes care of establishing the transformation function to
52 : * implement the reprojection, and will default a variety of other
53 : * warp options.
54 : *
55 : * Nodata values set on destination dataset are taken into account.
56 : *
57 : * No metadata, projection info, or color tables are transferred
58 : * to the output file. Source overviews are not considered.
59 : *
60 : * For more advanced warping capabilities, consider using GDALWarp().
61 : *
62 : * @param hSrcDS the source image file.
63 : * @param pszSrcWKT the source projection. If NULL the source projection
64 : * is read from from hSrcDS.
65 : * @param hDstDS the destination image file.
66 : * @param pszDstWKT the destination projection. If NULL the destination
67 : * projection will be read from hDstDS.
68 : * @param eResampleAlg the type of resampling to use.
69 : * @param dfWarpMemoryLimit the amount of memory (in bytes) that the warp
70 : * API is allowed to use for caching. This is in addition to the memory
71 : * already allocated to the GDAL caching (as per GDALSetCacheMax()). May be
72 : * 0.0 to use default memory settings.
73 : * @param dfMaxError maximum error measured in input pixels that is allowed
74 : * in approximating the transformation (0.0 for exact calculations).
75 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
76 : * reporting progress or NULL.
77 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
78 : * @param psOptions warp options, normally NULL.
79 : *
80 : * @return CE_None on success or CE_Failure if something goes wrong.
81 : * @see GDALWarp()
82 : */
83 :
84 52 : CPLErr CPL_STDCALL GDALReprojectImage(
85 : GDALDatasetH hSrcDS, const char *pszSrcWKT, GDALDatasetH hDstDS,
86 : const char *pszDstWKT, GDALResampleAlg eResampleAlg,
87 : CPL_UNUSED double dfWarpMemoryLimit, double dfMaxError,
88 : GDALProgressFunc pfnProgress, void *pProgressArg,
89 : GDALWarpOptions *psOptions)
90 :
91 : {
92 : /* -------------------------------------------------------------------- */
93 : /* Setup a reprojection based transformer. */
94 : /* -------------------------------------------------------------------- */
95 52 : void *hTransformArg = GDALCreateGenImgProjTransformer(
96 : hSrcDS, pszSrcWKT, hDstDS, pszDstWKT, TRUE, 1000.0, 0);
97 :
98 52 : if (hTransformArg == nullptr)
99 0 : return CE_Failure;
100 :
101 : /* -------------------------------------------------------------------- */
102 : /* Create a copy of the user provided options, or a defaulted */
103 : /* options structure. */
104 : /* -------------------------------------------------------------------- */
105 : GDALWarpOptions *psWOptions = psOptions == nullptr
106 52 : ? GDALCreateWarpOptions()
107 1 : : GDALCloneWarpOptions(psOptions);
108 :
109 52 : psWOptions->eResampleAlg = eResampleAlg;
110 :
111 : /* -------------------------------------------------------------------- */
112 : /* Set transform. */
113 : /* -------------------------------------------------------------------- */
114 52 : if (dfMaxError > 0.0)
115 : {
116 3 : psWOptions->pTransformerArg = GDALCreateApproxTransformer(
117 : GDALGenImgProjTransform, hTransformArg, dfMaxError);
118 :
119 3 : psWOptions->pfnTransformer = GDALApproxTransform;
120 : }
121 : else
122 : {
123 49 : psWOptions->pfnTransformer = GDALGenImgProjTransform;
124 49 : psWOptions->pTransformerArg = hTransformArg;
125 : }
126 :
127 : /* -------------------------------------------------------------------- */
128 : /* Set file and band mapping. */
129 : /* -------------------------------------------------------------------- */
130 52 : psWOptions->hSrcDS = hSrcDS;
131 52 : psWOptions->hDstDS = hDstDS;
132 :
133 52 : int nSrcBands = GDALGetRasterCount(hSrcDS);
134 : {
135 52 : GDALRasterBandH hBand = GDALGetRasterBand(hSrcDS, nSrcBands);
136 52 : if (hBand && GDALGetRasterColorInterpretation(hBand) == GCI_AlphaBand)
137 : {
138 2 : psWOptions->nSrcAlphaBand = nSrcBands;
139 2 : nSrcBands--;
140 : }
141 : }
142 :
143 52 : int nDstBands = GDALGetRasterCount(hDstDS);
144 : {
145 52 : GDALRasterBandH hBand = GDALGetRasterBand(hDstDS, nDstBands);
146 52 : if (hBand && GDALGetRasterColorInterpretation(hBand) == GCI_AlphaBand)
147 : {
148 2 : psWOptions->nDstAlphaBand = nDstBands;
149 2 : nDstBands--;
150 : }
151 : }
152 :
153 52 : GDALWarpInitDefaultBandMapping(psWOptions, std::min(nSrcBands, nDstBands));
154 :
155 : /* -------------------------------------------------------------------- */
156 : /* Set source nodata values if the source dataset seems to have */
157 : /* any. Same for target nodata values */
158 : /* -------------------------------------------------------------------- */
159 108 : for (int iBand = 0; iBand < psWOptions->nBandCount; iBand++)
160 : {
161 56 : GDALRasterBandH hBand = GDALGetRasterBand(hSrcDS, iBand + 1);
162 :
163 56 : int bGotNoData = FALSE;
164 56 : double dfNoDataValue = GDALGetRasterNoDataValue(hBand, &bGotNoData);
165 56 : if (bGotNoData)
166 : {
167 2 : GDALWarpInitSrcNoDataReal(psWOptions, -1.1e20);
168 2 : psWOptions->padfSrcNoDataReal[iBand] = dfNoDataValue;
169 : }
170 :
171 : // Deal with target band.
172 56 : hBand = GDALGetRasterBand(hDstDS, iBand + 1);
173 :
174 56 : dfNoDataValue = GDALGetRasterNoDataValue(hBand, &bGotNoData);
175 56 : if (bGotNoData)
176 : {
177 2 : GDALWarpInitDstNoDataReal(psWOptions, -1.1e20);
178 2 : psWOptions->padfDstNoDataReal[iBand] = dfNoDataValue;
179 : }
180 : }
181 :
182 : /* -------------------------------------------------------------------- */
183 : /* Set the progress function. */
184 : /* -------------------------------------------------------------------- */
185 52 : if (pfnProgress != nullptr)
186 : {
187 3 : psWOptions->pfnProgress = pfnProgress;
188 3 : psWOptions->pProgressArg = pProgressArg;
189 : }
190 :
191 : /* -------------------------------------------------------------------- */
192 : /* Create a warp options based on the options. */
193 : /* -------------------------------------------------------------------- */
194 52 : GDALWarpOperation oWarper;
195 52 : CPLErr eErr = oWarper.Initialize(psWOptions);
196 :
197 52 : if (eErr == CE_None)
198 52 : eErr = oWarper.ChunkAndWarpImage(0, 0, GDALGetRasterXSize(hDstDS),
199 : GDALGetRasterYSize(hDstDS));
200 :
201 : /* -------------------------------------------------------------------- */
202 : /* Cleanup. */
203 : /* -------------------------------------------------------------------- */
204 52 : GDALDestroyGenImgProjTransformer(hTransformArg);
205 :
206 52 : if (dfMaxError > 0.0)
207 3 : GDALDestroyApproxTransformer(psWOptions->pTransformerArg);
208 :
209 52 : GDALDestroyWarpOptions(psWOptions);
210 :
211 52 : return eErr;
212 : }
213 :
214 : /************************************************************************/
215 : /* GDALCreateAndReprojectImage() */
216 : /* */
217 : /* This is a "quickie" reprojection API. */
218 : /************************************************************************/
219 :
220 : /** Reproject an image and create the target reprojected image */
221 0 : CPLErr CPL_STDCALL GDALCreateAndReprojectImage(
222 : GDALDatasetH hSrcDS, const char *pszSrcWKT, const char *pszDstFilename,
223 : const char *pszDstWKT, GDALDriverH hDstDriver, char **papszCreateOptions,
224 : GDALResampleAlg eResampleAlg, double dfWarpMemoryLimit, double dfMaxError,
225 : GDALProgressFunc pfnProgress, void *pProgressArg,
226 : GDALWarpOptions *psOptions)
227 :
228 : {
229 0 : VALIDATE_POINTER1(hSrcDS, "GDALCreateAndReprojectImage", CE_Failure);
230 :
231 : /* -------------------------------------------------------------------- */
232 : /* Default a few parameters. */
233 : /* -------------------------------------------------------------------- */
234 0 : if (hDstDriver == nullptr)
235 : {
236 0 : hDstDriver = GDALGetDriverByName("GTiff");
237 0 : if (hDstDriver == nullptr)
238 : {
239 0 : CPLError(CE_Failure, CPLE_AppDefined,
240 : "GDALCreateAndReprojectImage needs GTiff driver");
241 0 : return CE_Failure;
242 : }
243 : }
244 :
245 0 : if (pszSrcWKT == nullptr)
246 0 : pszSrcWKT = GDALGetProjectionRef(hSrcDS);
247 :
248 0 : if (pszDstWKT == nullptr)
249 0 : pszDstWKT = pszSrcWKT;
250 :
251 : /* -------------------------------------------------------------------- */
252 : /* Create a transformation object from the source to */
253 : /* destination coordinate system. */
254 : /* -------------------------------------------------------------------- */
255 0 : void *hTransformArg = GDALCreateGenImgProjTransformer(
256 : hSrcDS, pszSrcWKT, nullptr, pszDstWKT, TRUE, 1000.0, 0);
257 :
258 0 : if (hTransformArg == nullptr)
259 0 : return CE_Failure;
260 :
261 : /* -------------------------------------------------------------------- */
262 : /* Get approximate output definition. */
263 : /* -------------------------------------------------------------------- */
264 0 : double adfDstGeoTransform[6] = {};
265 0 : int nPixels = 0;
266 0 : int nLines = 0;
267 :
268 : CPLErr eErr =
269 0 : GDALSuggestedWarpOutput(hSrcDS, GDALGenImgProjTransform, hTransformArg,
270 : adfDstGeoTransform, &nPixels, &nLines);
271 :
272 0 : GDALDestroyGenImgProjTransformer(hTransformArg);
273 :
274 0 : if (eErr != CE_None)
275 0 : return eErr;
276 :
277 : /* -------------------------------------------------------------------- */
278 : /* Create the output file. */
279 : /* -------------------------------------------------------------------- */
280 0 : GDALDatasetH hDstDS = GDALCreate(
281 : hDstDriver, pszDstFilename, nPixels, nLines, GDALGetRasterCount(hSrcDS),
282 : GDALGetRasterDataType(GDALGetRasterBand(hSrcDS, 1)),
283 : papszCreateOptions);
284 :
285 0 : if (hDstDS == nullptr)
286 0 : return CE_Failure;
287 :
288 : /* -------------------------------------------------------------------- */
289 : /* Write out the projection definition. */
290 : /* -------------------------------------------------------------------- */
291 0 : GDALSetProjection(hDstDS, pszDstWKT);
292 0 : GDALSetGeoTransform(hDstDS, adfDstGeoTransform);
293 :
294 : /* -------------------------------------------------------------------- */
295 : /* Perform the reprojection. */
296 : /* -------------------------------------------------------------------- */
297 0 : eErr = GDALReprojectImage(hSrcDS, pszSrcWKT, hDstDS, pszDstWKT,
298 : eResampleAlg, dfWarpMemoryLimit, dfMaxError,
299 : pfnProgress, pProgressArg, psOptions);
300 :
301 0 : GDALClose(hDstDS);
302 :
303 0 : return eErr;
304 : }
305 :
306 : /************************************************************************/
307 : /* GDALWarpNoDataMaskerT() */
308 : /************************************************************************/
309 :
310 : template <class T>
311 760 : static CPLErr GDALWarpNoDataMaskerT(const double *padfNoData, size_t nPixels,
312 : const T *pData, GUInt32 *panValidityMask,
313 : int *pbOutAllValid)
314 : {
315 : // Nothing to do if value is out of range.
316 760 : if (padfNoData[0] < cpl::NumericLimits<T>::min() ||
317 1473 : padfNoData[0] > cpl::NumericLimits<T>::max() + 0.000001 ||
318 713 : padfNoData[1] != 0.0)
319 : {
320 47 : *pbOutAllValid = TRUE;
321 47 : return CE_None;
322 : }
323 :
324 713 : const int nNoData = static_cast<int>(floor(padfNoData[0] + 0.000001));
325 713 : int bAllValid = TRUE;
326 115341239 : for (size_t iOffset = 0; iOffset < nPixels; ++iOffset)
327 : {
328 115341089 : if (pData[iOffset] == nNoData)
329 : {
330 110875912 : bAllValid = FALSE;
331 110875912 : CPLMaskClear(panValidityMask, iOffset);
332 : }
333 : }
334 713 : *pbOutAllValid = bAllValid;
335 :
336 713 : return CE_None;
337 : }
338 :
339 : /************************************************************************/
340 : /* GDALWarpNoDataMasker() */
341 : /* */
342 : /* GDALMaskFunc for establishing a validity mask for a source */
343 : /* band based on a provided NODATA value. */
344 : /************************************************************************/
345 :
346 1025 : CPLErr GDALWarpNoDataMasker(void *pMaskFuncArg, int nBandCount,
347 : GDALDataType eType, int /* nXOff */,
348 : int /* nYOff */, int nXSize, int nYSize,
349 : GByte **ppImageData, int bMaskIsFloat,
350 : void *pValidityMask, int *pbOutAllValid)
351 :
352 : {
353 1025 : const double *padfNoData = static_cast<double *>(pMaskFuncArg);
354 1025 : GUInt32 *panValidityMask = static_cast<GUInt32 *>(pValidityMask);
355 1025 : const size_t nPixels = static_cast<size_t>(nXSize) * nYSize;
356 :
357 1025 : *pbOutAllValid = FALSE;
358 :
359 1025 : if (nBandCount != 1 || bMaskIsFloat)
360 : {
361 0 : CPLError(
362 : CE_Failure, CPLE_AppDefined,
363 : "Invalid nBandCount or bMaskIsFloat argument in SourceNoDataMask");
364 0 : return CE_Failure;
365 : }
366 :
367 1025 : CPLErr eErr = CE_None;
368 :
369 1025 : switch (eType)
370 : {
371 608 : case GDT_UInt8:
372 608 : return GDALWarpNoDataMaskerT(padfNoData, nPixels,
373 : *ppImageData, // Already a GByte *.
374 608 : panValidityMask, pbOutAllValid);
375 :
376 28 : case GDT_Int8:
377 28 : return GDALWarpNoDataMaskerT(
378 : padfNoData, nPixels, reinterpret_cast<int8_t *>(*ppImageData),
379 28 : panValidityMask, pbOutAllValid);
380 :
381 97 : case GDT_Int16:
382 97 : return GDALWarpNoDataMaskerT(
383 : padfNoData, nPixels, reinterpret_cast<GInt16 *>(*ppImageData),
384 97 : panValidityMask, pbOutAllValid);
385 :
386 27 : case GDT_UInt16:
387 27 : return GDALWarpNoDataMaskerT(
388 : padfNoData, nPixels, reinterpret_cast<GUInt16 *>(*ppImageData),
389 27 : panValidityMask, pbOutAllValid);
390 :
391 116 : case GDT_Float32:
392 : {
393 116 : const float fNoData = static_cast<float>(padfNoData[0]);
394 116 : const float *pafData = reinterpret_cast<float *>(*ppImageData);
395 116 : const bool bIsNoDataNan = CPL_TO_BOOL(std::isnan(fNoData));
396 :
397 : // Nothing to do if value is out of range.
398 116 : if (padfNoData[1] != 0.0)
399 : {
400 0 : *pbOutAllValid = TRUE;
401 0 : return CE_None;
402 : }
403 :
404 116 : int bAllValid = TRUE;
405 219554 : for (size_t iOffset = 0; iOffset < nPixels; ++iOffset)
406 : {
407 219438 : float fVal = pafData[iOffset];
408 438628 : if ((bIsNoDataNan && std::isnan(fVal)) ||
409 219190 : (!bIsNoDataNan && ARE_REAL_EQUAL(fVal, fNoData)))
410 : {
411 123734 : bAllValid = FALSE;
412 123734 : CPLMaskClear(panValidityMask, iOffset);
413 : }
414 : }
415 116 : *pbOutAllValid = bAllValid;
416 : }
417 116 : break;
418 :
419 41 : case GDT_Float64:
420 : {
421 41 : const double dfNoData = padfNoData[0];
422 41 : const double *padfData = reinterpret_cast<double *>(*ppImageData);
423 41 : const bool bIsNoDataNan = CPL_TO_BOOL(std::isnan(dfNoData));
424 :
425 : // Nothing to do if value is out of range.
426 41 : if (padfNoData[1] != 0.0)
427 : {
428 0 : *pbOutAllValid = TRUE;
429 0 : return CE_None;
430 : }
431 :
432 41 : int bAllValid = TRUE;
433 5912470 : for (size_t iOffset = 0; iOffset < nPixels; ++iOffset)
434 : {
435 5912430 : double dfVal = padfData[iOffset];
436 5913270 : if ((bIsNoDataNan && std::isnan(dfVal)) ||
437 840 : (!bIsNoDataNan && ARE_REAL_EQUAL(dfVal, dfNoData)))
438 : {
439 5912040 : bAllValid = FALSE;
440 5912040 : CPLMaskClear(panValidityMask, iOffset);
441 : }
442 : }
443 41 : *pbOutAllValid = bAllValid;
444 : }
445 41 : break;
446 :
447 108 : default:
448 : {
449 108 : const int nWordSize = GDALGetDataTypeSizeBytes(eType);
450 :
451 : const bool bIsNoDataRealNan =
452 108 : CPL_TO_BOOL(std::isnan(padfNoData[0]));
453 :
454 108 : eErr = CE_Failure;
455 : double *padfWrk = static_cast<double *>(
456 108 : VSI_MALLOC2_VERBOSE(nXSize, sizeof(double) * 2));
457 108 : if (padfWrk)
458 : {
459 108 : eErr = CE_None;
460 108 : bool bAllValid = true;
461 714 : for (int iLine = 0; iLine < nYSize; iLine++)
462 : {
463 606 : GDALCopyWords((*ppImageData) + nWordSize * iLine * nXSize,
464 : eType, nWordSize, padfWrk, GDT_CFloat64, 16,
465 : nXSize);
466 :
467 8122 : for (int iPixel = 0; iPixel < nXSize; ++iPixel)
468 : {
469 0 : if (((bIsNoDataRealNan &&
470 15032 : std::isnan(padfWrk[iPixel * 2])) ||
471 15032 : (!bIsNoDataRealNan &&
472 7516 : ARE_REAL_EQUAL(padfWrk[iPixel * 2],
473 : padfNoData[0]))))
474 : {
475 2213 : size_t iOffset =
476 2213 : iPixel + static_cast<size_t>(iLine) * nXSize;
477 :
478 2213 : bAllValid = false;
479 2213 : CPLMaskClear(panValidityMask, iOffset);
480 : }
481 : }
482 : }
483 108 : *pbOutAllValid = bAllValid;
484 :
485 108 : VSIFree(padfWrk);
486 : }
487 : }
488 108 : break;
489 : }
490 :
491 265 : return eErr;
492 : }
493 :
494 : /************************************************************************/
495 : /* GDALWarpSrcAlphaMasker() */
496 : /* */
497 : /* GDALMaskFunc for reading source simple 8bit alpha mask */
498 : /* information and building a floating point density mask from */
499 : /* it. */
500 : /************************************************************************/
501 :
502 142 : CPLErr GDALWarpSrcAlphaMasker(void *pMaskFuncArg, int /* nBandCount */,
503 : GDALDataType /* eType */, int nXOff, int nYOff,
504 : int nXSize, int nYSize, GByte ** /*ppImageData */,
505 : int bMaskIsFloat, void *pValidityMask,
506 : int *pbOutAllOpaque)
507 :
508 : {
509 142 : GDALWarpOptions *psWO = static_cast<GDALWarpOptions *>(pMaskFuncArg);
510 142 : float *pafMask = static_cast<float *>(pValidityMask);
511 142 : *pbOutAllOpaque = FALSE;
512 142 : const size_t nPixels = static_cast<size_t>(nXSize) * nYSize;
513 :
514 : /* -------------------------------------------------------------------- */
515 : /* Do some minimal checking. */
516 : /* -------------------------------------------------------------------- */
517 142 : if (!bMaskIsFloat)
518 : {
519 0 : CPLAssert(false);
520 : return CE_Failure;
521 : }
522 :
523 142 : if (psWO == nullptr || psWO->nSrcAlphaBand < 1)
524 : {
525 0 : CPLAssert(false);
526 : return CE_Failure;
527 : }
528 :
529 : /* -------------------------------------------------------------------- */
530 : /* Read the alpha band. */
531 : /* -------------------------------------------------------------------- */
532 : GDALRasterBandH hAlphaBand =
533 142 : GDALGetRasterBand(psWO->hSrcDS, psWO->nSrcAlphaBand);
534 142 : if (hAlphaBand == nullptr)
535 0 : return CE_Failure;
536 :
537 : // Rescale.
538 142 : const float inv_alpha_max = static_cast<float>(
539 142 : 1.0 / CPLAtof(CSLFetchNameValueDef(psWO->papszWarpOptions,
540 142 : "SRC_ALPHA_MAX", "255")));
541 142 : bool bOutAllOpaque = true;
542 :
543 142 : size_t iPixel = 0;
544 : CPLErr eErr;
545 :
546 : #if (defined(__x86_64) || defined(_M_X64))
547 142 : GDALDataType eDT = GDALGetRasterDataType(hAlphaBand);
548 : // Make sure that pafMask is at least 8-byte aligned, which should
549 : // normally be always the case if being a ptr returned by malloc().
550 142 : if ((eDT == GDT_UInt8 || eDT == GDT_UInt16) && CPL_IS_ALIGNED(pafMask, 8))
551 : {
552 : // Read data.
553 262 : eErr = GDALRasterIOEx(
554 : hAlphaBand, GF_Read, nXOff, nYOff, nXSize, nYSize, pafMask, nXSize,
555 : nYSize, eDT, static_cast<GSpacing>(sizeof(int)),
556 131 : static_cast<GSpacing>(sizeof(int)) * nXSize, nullptr);
557 :
558 131 : if (eErr != CE_None)
559 0 : return eErr;
560 :
561 : // Make sure we have the correct alignment before doing SSE
562 : // On Linux x86_64, the alignment should be always correct due
563 : // the alignment of malloc() being 16 byte.
564 131 : const GUInt32 mask = (eDT == GDT_UInt8) ? 0xff : 0xffff;
565 131 : if (!CPL_IS_ALIGNED(pafMask, 16))
566 : {
567 0 : pafMask[iPixel] =
568 0 : (reinterpret_cast<GUInt32 *>(pafMask)[iPixel] & mask) *
569 0 : inv_alpha_max;
570 0 : if (pafMask[iPixel] >= 1.0f)
571 0 : pafMask[iPixel] = 1.0f;
572 : else
573 0 : bOutAllOpaque = false;
574 0 : iPixel++;
575 : }
576 131 : CPLAssert(CPL_IS_ALIGNED(pafMask + iPixel, 16));
577 131 : const __m128 xmm_inverse_alpha_max = _mm_load1_ps(&inv_alpha_max);
578 131 : const float one_single = 1.0f;
579 131 : const __m128 xmm_one = _mm_load1_ps(&one_single);
580 262 : const __m128i xmm_i_mask = _mm_set1_epi32(mask);
581 131 : __m128 xmmMaskNonOpaque0 = _mm_setzero_ps();
582 131 : __m128 xmmMaskNonOpaque1 = _mm_setzero_ps();
583 131 : __m128 xmmMaskNonOpaque2 = _mm_setzero_ps();
584 231086 : for (; iPixel + 6 * 4 - 1 < nPixels; iPixel += 6 * 4)
585 : {
586 461910 : __m128 xmm_mask0 = _mm_cvtepi32_ps(_mm_and_si128(
587 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
588 230955 : pafMask + iPixel + 4 * 0))));
589 461910 : __m128 xmm_mask1 = _mm_cvtepi32_ps(_mm_and_si128(
590 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
591 230955 : pafMask + iPixel + 4 * 1))));
592 461910 : __m128 xmm_mask2 = _mm_cvtepi32_ps(_mm_and_si128(
593 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
594 230955 : pafMask + iPixel + 4 * 2))));
595 461910 : __m128 xmm_mask3 = _mm_cvtepi32_ps(_mm_and_si128(
596 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
597 230955 : pafMask + iPixel + 4 * 3))));
598 461910 : __m128 xmm_mask4 = _mm_cvtepi32_ps(_mm_and_si128(
599 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
600 230955 : pafMask + iPixel + 4 * 4))));
601 692865 : __m128 xmm_mask5 = _mm_cvtepi32_ps(_mm_and_si128(
602 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
603 230955 : pafMask + iPixel + 4 * 5))));
604 230955 : xmm_mask0 = _mm_mul_ps(xmm_mask0, xmm_inverse_alpha_max);
605 230955 : xmm_mask1 = _mm_mul_ps(xmm_mask1, xmm_inverse_alpha_max);
606 230955 : xmm_mask2 = _mm_mul_ps(xmm_mask2, xmm_inverse_alpha_max);
607 230955 : xmm_mask3 = _mm_mul_ps(xmm_mask3, xmm_inverse_alpha_max);
608 230955 : xmm_mask4 = _mm_mul_ps(xmm_mask4, xmm_inverse_alpha_max);
609 230955 : xmm_mask5 = _mm_mul_ps(xmm_mask5, xmm_inverse_alpha_max);
610 : xmmMaskNonOpaque0 =
611 461910 : _mm_or_ps(xmmMaskNonOpaque0, _mm_cmplt_ps(xmm_mask0, xmm_one));
612 : xmmMaskNonOpaque1 =
613 461910 : _mm_or_ps(xmmMaskNonOpaque1, _mm_cmplt_ps(xmm_mask1, xmm_one));
614 : xmmMaskNonOpaque2 =
615 461910 : _mm_or_ps(xmmMaskNonOpaque2, _mm_cmplt_ps(xmm_mask2, xmm_one));
616 : xmmMaskNonOpaque0 =
617 461910 : _mm_or_ps(xmmMaskNonOpaque0, _mm_cmplt_ps(xmm_mask3, xmm_one));
618 : xmmMaskNonOpaque1 =
619 461910 : _mm_or_ps(xmmMaskNonOpaque1, _mm_cmplt_ps(xmm_mask4, xmm_one));
620 : xmmMaskNonOpaque2 =
621 461910 : _mm_or_ps(xmmMaskNonOpaque2, _mm_cmplt_ps(xmm_mask5, xmm_one));
622 230955 : xmm_mask0 = _mm_min_ps(xmm_mask0, xmm_one);
623 230955 : xmm_mask1 = _mm_min_ps(xmm_mask1, xmm_one);
624 230955 : xmm_mask2 = _mm_min_ps(xmm_mask2, xmm_one);
625 230955 : xmm_mask3 = _mm_min_ps(xmm_mask3, xmm_one);
626 230955 : xmm_mask4 = _mm_min_ps(xmm_mask4, xmm_one);
627 230955 : xmm_mask5 = _mm_min_ps(xmm_mask5, xmm_one);
628 230955 : _mm_store_ps(pafMask + iPixel + 4 * 0, xmm_mask0);
629 230955 : _mm_store_ps(pafMask + iPixel + 4 * 1, xmm_mask1);
630 230955 : _mm_store_ps(pafMask + iPixel + 4 * 2, xmm_mask2);
631 230955 : _mm_store_ps(pafMask + iPixel + 4 * 3, xmm_mask3);
632 230955 : _mm_store_ps(pafMask + iPixel + 4 * 4, xmm_mask4);
633 230955 : _mm_store_ps(pafMask + iPixel + 4 * 5, xmm_mask5);
634 : }
635 262 : if (_mm_movemask_ps(
636 : _mm_or_ps(_mm_or_ps(xmmMaskNonOpaque0, xmmMaskNonOpaque1),
637 131 : xmmMaskNonOpaque2)))
638 : {
639 93 : bOutAllOpaque = false;
640 : }
641 1519 : for (; iPixel < nPixels; iPixel++)
642 : {
643 1388 : pafMask[iPixel] =
644 1388 : (reinterpret_cast<GUInt32 *>(pafMask)[iPixel] & mask) *
645 1388 : inv_alpha_max;
646 1388 : if (pafMask[iPixel] >= 1.0f)
647 406 : pafMask[iPixel] = 1.0f;
648 : else
649 982 : bOutAllOpaque = false;
650 131 : }
651 : }
652 : else
653 : #endif
654 : {
655 : // Read data.
656 11 : eErr = GDALRasterIO(hAlphaBand, GF_Read, nXOff, nYOff, nXSize, nYSize,
657 : pafMask, nXSize, nYSize, GDT_Float32, 0, 0);
658 :
659 11 : if (eErr != CE_None)
660 0 : return eErr;
661 :
662 : // TODO(rouault): Is loop unrolling by hand (r34564) actually helpful?
663 12969 : for (; iPixel + 3 < nPixels; iPixel += 4)
664 : {
665 12958 : pafMask[iPixel] = pafMask[iPixel] * inv_alpha_max;
666 12958 : if (pafMask[iPixel] >= 1.0f)
667 3028 : pafMask[iPixel] = 1.0f;
668 : else
669 9930 : bOutAllOpaque = false;
670 12958 : pafMask[iPixel + 1] = pafMask[iPixel + 1] * inv_alpha_max;
671 12958 : if (pafMask[iPixel + 1] >= 1.0f)
672 3018 : pafMask[iPixel + 1] = 1.0f;
673 : else
674 9940 : bOutAllOpaque = false;
675 12958 : pafMask[iPixel + 2] = pafMask[iPixel + 2] * inv_alpha_max;
676 12958 : if (pafMask[iPixel + 2] >= 1.0f)
677 3066 : pafMask[iPixel + 2] = 1.0f;
678 : else
679 9892 : bOutAllOpaque = false;
680 12958 : pafMask[iPixel + 3] = pafMask[iPixel + 3] * inv_alpha_max;
681 12958 : if (pafMask[iPixel + 3] >= 1.0f)
682 3016 : pafMask[iPixel + 3] = 1.0f;
683 : else
684 9942 : bOutAllOpaque = false;
685 : }
686 :
687 12 : for (; iPixel < nPixels; iPixel++)
688 : {
689 1 : pafMask[iPixel] = pafMask[iPixel] * inv_alpha_max;
690 1 : if (pafMask[iPixel] >= 1.0f)
691 0 : pafMask[iPixel] = 1.0f;
692 : else
693 1 : bOutAllOpaque = false;
694 : }
695 : }
696 :
697 142 : *pbOutAllOpaque = bOutAllOpaque;
698 :
699 142 : return CE_None;
700 : }
701 :
702 : /************************************************************************/
703 : /* GDALWarpSrcMaskMasker() */
704 : /* */
705 : /* GDALMaskFunc for reading source simple 8bit validity mask */
706 : /* information and building a one bit validity mask. */
707 : /************************************************************************/
708 :
709 2 : CPLErr GDALWarpSrcMaskMasker(void *pMaskFuncArg, int /* nBandCount */,
710 : GDALDataType /* eType */, int nXOff, int nYOff,
711 : int nXSize, int nYSize, GByte ** /*ppImageData */,
712 : int bMaskIsFloat, void *pValidityMask)
713 :
714 : {
715 2 : GDALWarpOptions *psWO = static_cast<GDALWarpOptions *>(pMaskFuncArg);
716 2 : GUInt32 *panMask = static_cast<GUInt32 *>(pValidityMask);
717 :
718 : /* -------------------------------------------------------------------- */
719 : /* Do some minimal checking. */
720 : /* -------------------------------------------------------------------- */
721 2 : if (bMaskIsFloat)
722 : {
723 0 : CPLAssert(false);
724 : return CE_Failure;
725 : }
726 :
727 2 : if (psWO == nullptr)
728 : {
729 0 : CPLAssert(false);
730 : return CE_Failure;
731 : }
732 :
733 : /* -------------------------------------------------------------------- */
734 : /* Allocate a temporary buffer to read mask byte data into. */
735 : /* -------------------------------------------------------------------- */
736 : GByte *pabySrcMask =
737 2 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXSize, nYSize));
738 2 : if (pabySrcMask == nullptr)
739 : {
740 0 : return CE_Failure;
741 : }
742 :
743 : /* -------------------------------------------------------------------- */
744 : /* Fetch our mask band. */
745 : /* -------------------------------------------------------------------- */
746 2 : GDALRasterBandH hMaskBand = nullptr;
747 : GDALRasterBandH hSrcBand =
748 2 : GDALGetRasterBand(psWO->hSrcDS, psWO->panSrcBands[0]);
749 2 : if (hSrcBand != nullptr)
750 2 : hMaskBand = GDALGetMaskBand(hSrcBand);
751 :
752 2 : if (hMaskBand == nullptr)
753 : {
754 0 : CPLAssert(false);
755 : return CE_Failure;
756 : }
757 :
758 : /* -------------------------------------------------------------------- */
759 : /* Read the mask band. */
760 : /* -------------------------------------------------------------------- */
761 2 : CPLErr eErr = GDALRasterIO(hMaskBand, GF_Read, nXOff, nYOff, nXSize, nYSize,
762 : pabySrcMask, nXSize, nYSize, GDT_UInt8, 0, 0);
763 :
764 2 : if (eErr != CE_None)
765 : {
766 0 : CPLFree(pabySrcMask);
767 0 : return eErr;
768 : }
769 :
770 : /* -------------------------------------------------------------------- */
771 : /* Pack into 1 bit per pixel for validity. */
772 : /* -------------------------------------------------------------------- */
773 2 : const size_t nPixels = static_cast<size_t>(nXSize) * nYSize;
774 234579 : for (size_t iPixel = 0; iPixel < nPixels; iPixel++)
775 : {
776 234577 : if (pabySrcMask[iPixel] == 0)
777 31660 : CPLMaskClear(panMask, iPixel);
778 : }
779 :
780 2 : CPLFree(pabySrcMask);
781 :
782 2 : return CE_None;
783 : }
784 :
785 : /************************************************************************/
786 : /* GDALWarpDstAlphaMasker() */
787 : /* */
788 : /* GDALMaskFunc for reading or writing the destination simple */
789 : /* 8bit alpha mask information and building a floating point */
790 : /* density mask from it. Note, writing is distinguished */
791 : /* negative bandcount. */
792 : /************************************************************************/
793 :
794 3426 : CPLErr GDALWarpDstAlphaMasker(void *pMaskFuncArg, int nBandCount,
795 : CPL_UNUSED GDALDataType /* eType */, int nXOff,
796 : int nYOff, int nXSize, int nYSize,
797 : GByte ** /*ppImageData */, int bMaskIsFloat,
798 : void *pValidityMask)
799 : {
800 : /* -------------------------------------------------------------------- */
801 : /* Do some minimal checking. */
802 : /* -------------------------------------------------------------------- */
803 3426 : if (!bMaskIsFloat)
804 : {
805 0 : CPLAssert(false);
806 : return CE_Failure;
807 : }
808 :
809 3426 : GDALWarpOptions *psWO = static_cast<GDALWarpOptions *>(pMaskFuncArg);
810 3426 : if (psWO == nullptr || psWO->nDstAlphaBand < 1)
811 : {
812 0 : CPLAssert(false);
813 : return CE_Failure;
814 : }
815 :
816 3426 : float *pafMask = static_cast<float *>(pValidityMask);
817 3426 : const size_t nPixels = static_cast<size_t>(nXSize) * nYSize;
818 :
819 : GDALRasterBandH hAlphaBand =
820 3426 : GDALGetRasterBand(psWO->hDstDS, psWO->nDstAlphaBand);
821 3426 : if (hAlphaBand == nullptr)
822 0 : return CE_Failure;
823 :
824 3426 : size_t iPixel = 0;
825 :
826 : /* -------------------------------------------------------------------- */
827 : /* Read alpha case. */
828 : /* -------------------------------------------------------------------- */
829 3426 : if (nBandCount >= 0)
830 : {
831 : const char *pszInitDest =
832 1713 : CSLFetchNameValue(psWO->papszWarpOptions, "INIT_DEST");
833 :
834 : // Special logic for destinations being initialized on-the-fly.
835 1713 : if (pszInitDest != nullptr)
836 : {
837 883 : memset(pafMask, 0, nPixels * sizeof(float));
838 883 : return CE_None;
839 : }
840 :
841 : // Rescale.
842 830 : const float inv_alpha_max = static_cast<float>(
843 830 : 1.0 / CPLAtof(CSLFetchNameValueDef(psWO->papszWarpOptions,
844 830 : "DST_ALPHA_MAX", "255")));
845 :
846 : #if (defined(__x86_64) || defined(_M_X64))
847 830 : const GDALDataType eDT = GDALGetRasterDataType(hAlphaBand);
848 : // Make sure that pafMask is at least 8-byte aligned, which should
849 : // normally be always the case if being a ptr returned by malloc().
850 830 : if ((eDT == GDT_UInt8 || eDT == GDT_UInt16) &&
851 821 : CPL_IS_ALIGNED(pafMask, 8))
852 : {
853 : // Read data.
854 1642 : const CPLErr eErr = GDALRasterIOEx(
855 : hAlphaBand, GF_Read, nXOff, nYOff, nXSize, nYSize, pafMask,
856 : nXSize, nYSize, eDT, static_cast<GSpacing>(sizeof(int)),
857 821 : static_cast<GSpacing>(sizeof(int)) * nXSize, nullptr);
858 :
859 821 : if (eErr != CE_None)
860 0 : return eErr;
861 :
862 : // Make sure we have the correct alignment before doing SSE
863 : // On Linux x86_64, the alignment should be always correct due
864 : // the alignment of malloc() being 16 byte.
865 821 : const GUInt32 mask = (eDT == GDT_UInt8) ? 0xff : 0xffff;
866 821 : if (!CPL_IS_ALIGNED(pafMask, 16))
867 : {
868 0 : pafMask[iPixel] =
869 0 : (reinterpret_cast<GUInt32 *>(pafMask)[iPixel] & mask) *
870 0 : inv_alpha_max;
871 0 : pafMask[iPixel] = std::min(1.0f, pafMask[iPixel]);
872 0 : iPixel++;
873 : }
874 821 : CPLAssert(CPL_IS_ALIGNED(pafMask + iPixel, 16));
875 821 : const __m128 xmm_inverse_alpha_max = _mm_load1_ps(&inv_alpha_max);
876 821 : const float one_single = 1.0f;
877 821 : const __m128 xmm_one = _mm_load1_ps(&one_single);
878 1642 : const __m128i xmm_i_mask = _mm_set1_epi32(mask);
879 1679200 : for (; iPixel + 31 < nPixels; iPixel += 32)
880 : {
881 3356750 : __m128 xmm_mask0 = _mm_cvtepi32_ps(_mm_and_si128(
882 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
883 1678380 : pafMask + iPixel + 4 * 0))));
884 3356750 : __m128 xmm_mask1 = _mm_cvtepi32_ps(_mm_and_si128(
885 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
886 1678380 : pafMask + iPixel + 4 * 1))));
887 3356750 : __m128 xmm_mask2 = _mm_cvtepi32_ps(_mm_and_si128(
888 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
889 1678380 : pafMask + iPixel + 4 * 2))));
890 3356750 : __m128 xmm_mask3 = _mm_cvtepi32_ps(_mm_and_si128(
891 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
892 1678380 : pafMask + iPixel + 4 * 3))));
893 3356750 : __m128 xmm_mask4 = _mm_cvtepi32_ps(_mm_and_si128(
894 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
895 1678380 : pafMask + iPixel + 4 * 4))));
896 3356750 : __m128 xmm_mask5 = _mm_cvtepi32_ps(_mm_and_si128(
897 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
898 1678380 : pafMask + iPixel + 4 * 5))));
899 3356750 : __m128 xmm_mask6 = _mm_cvtepi32_ps(_mm_and_si128(
900 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
901 1678380 : pafMask + iPixel + 4 * 6))));
902 5035130 : __m128 xmm_mask7 = _mm_cvtepi32_ps(_mm_and_si128(
903 : xmm_i_mask, _mm_load_si128(reinterpret_cast<__m128i *>(
904 1678380 : pafMask + iPixel + 4 * 7))));
905 1678380 : xmm_mask0 = _mm_mul_ps(xmm_mask0, xmm_inverse_alpha_max);
906 1678380 : xmm_mask1 = _mm_mul_ps(xmm_mask1, xmm_inverse_alpha_max);
907 1678380 : xmm_mask2 = _mm_mul_ps(xmm_mask2, xmm_inverse_alpha_max);
908 1678380 : xmm_mask3 = _mm_mul_ps(xmm_mask3, xmm_inverse_alpha_max);
909 1678380 : xmm_mask4 = _mm_mul_ps(xmm_mask4, xmm_inverse_alpha_max);
910 1678380 : xmm_mask5 = _mm_mul_ps(xmm_mask5, xmm_inverse_alpha_max);
911 1678380 : xmm_mask6 = _mm_mul_ps(xmm_mask6, xmm_inverse_alpha_max);
912 1678380 : xmm_mask7 = _mm_mul_ps(xmm_mask7, xmm_inverse_alpha_max);
913 1678380 : xmm_mask0 = _mm_min_ps(xmm_mask0, xmm_one);
914 1678380 : xmm_mask1 = _mm_min_ps(xmm_mask1, xmm_one);
915 1678380 : xmm_mask2 = _mm_min_ps(xmm_mask2, xmm_one);
916 1678380 : xmm_mask3 = _mm_min_ps(xmm_mask3, xmm_one);
917 1678380 : xmm_mask4 = _mm_min_ps(xmm_mask4, xmm_one);
918 1678380 : xmm_mask5 = _mm_min_ps(xmm_mask5, xmm_one);
919 1678380 : xmm_mask6 = _mm_min_ps(xmm_mask6, xmm_one);
920 1678380 : xmm_mask7 = _mm_min_ps(xmm_mask7, xmm_one);
921 1678380 : _mm_store_ps(pafMask + iPixel + 4 * 0, xmm_mask0);
922 1678380 : _mm_store_ps(pafMask + iPixel + 4 * 1, xmm_mask1);
923 1678380 : _mm_store_ps(pafMask + iPixel + 4 * 2, xmm_mask2);
924 1678380 : _mm_store_ps(pafMask + iPixel + 4 * 3, xmm_mask3);
925 1678380 : _mm_store_ps(pafMask + iPixel + 4 * 4, xmm_mask4);
926 1678380 : _mm_store_ps(pafMask + iPixel + 4 * 5, xmm_mask5);
927 1678380 : _mm_store_ps(pafMask + iPixel + 4 * 6, xmm_mask6);
928 1678380 : _mm_store_ps(pafMask + iPixel + 4 * 7, xmm_mask7);
929 : }
930 1565 : for (; iPixel < nPixels; iPixel++)
931 : {
932 744 : pafMask[iPixel] =
933 744 : (reinterpret_cast<GUInt32 *>(pafMask)[iPixel] & mask) *
934 744 : inv_alpha_max;
935 744 : pafMask[iPixel] = std::min(1.0f, pafMask[iPixel]);
936 821 : }
937 : }
938 : else
939 : #endif
940 : {
941 : // Read data.
942 : const CPLErr eErr =
943 9 : GDALRasterIO(hAlphaBand, GF_Read, nXOff, nYOff, nXSize, nYSize,
944 : pafMask, nXSize, nYSize, GDT_Float32, 0, 0);
945 :
946 9 : if (eErr != CE_None)
947 0 : return eErr;
948 :
949 842 : for (; iPixel < nPixels; iPixel++)
950 : {
951 833 : pafMask[iPixel] = pafMask[iPixel] * inv_alpha_max;
952 833 : pafMask[iPixel] = std::min(1.0f, pafMask[iPixel]);
953 : }
954 : }
955 :
956 830 : return CE_None;
957 : }
958 :
959 : /* -------------------------------------------------------------------- */
960 : /* Write alpha case. */
961 : /* -------------------------------------------------------------------- */
962 : else
963 : {
964 1713 : GDALDataType eDT = GDALGetRasterDataType(hAlphaBand);
965 : const float cst_alpha_max =
966 1713 : static_cast<float>(CPLAtof(CSLFetchNameValueDef(
967 1713 : psWO->papszWarpOptions, "DST_ALPHA_MAX", "255"))) +
968 30 : ((eDT == GDT_UInt8 || eDT == GDT_Int16 || eDT == GDT_UInt16 ||
969 1 : eDT == GDT_Int32 || eDT == GDT_UInt32)
970 1743 : ? 0.1f
971 1713 : : 0.0f);
972 :
973 1713 : CPLErr eErr = CE_None;
974 :
975 : #if (defined(__x86_64) || defined(_M_X64))
976 : // Make sure that pafMask is at least 8-byte aligned, which should
977 : // normally be always the case if being a ptr returned by malloc()
978 1713 : if ((eDT == GDT_UInt8 || eDT == GDT_Int16 || eDT == GDT_UInt16) &&
979 1712 : CPL_IS_ALIGNED(pafMask, 8))
980 : {
981 : // Make sure we have the correct alignment before doing SSE
982 : // On Linux x86_64, the alignment should be always correct due
983 : // the alignment of malloc() being 16 byte
984 1712 : if (!CPL_IS_ALIGNED(pafMask, 16))
985 : {
986 0 : reinterpret_cast<int *>(pafMask)[iPixel] =
987 0 : static_cast<int>(pafMask[iPixel] * cst_alpha_max);
988 0 : iPixel++;
989 : }
990 1712 : CPLAssert(CPL_IS_ALIGNED(pafMask + iPixel, 16));
991 1712 : const __m128 xmm_alpha_max = _mm_load1_ps(&cst_alpha_max);
992 3349370 : for (; iPixel + 31 < nPixels; iPixel += 32)
993 : {
994 3347660 : __m128 xmm_mask0 = _mm_load_ps(pafMask + iPixel + 4 * 0);
995 3347660 : __m128 xmm_mask1 = _mm_load_ps(pafMask + iPixel + 4 * 1);
996 3347660 : __m128 xmm_mask2 = _mm_load_ps(pafMask + iPixel + 4 * 2);
997 3347660 : __m128 xmm_mask3 = _mm_load_ps(pafMask + iPixel + 4 * 3);
998 3347660 : __m128 xmm_mask4 = _mm_load_ps(pafMask + iPixel + 4 * 4);
999 3347660 : __m128 xmm_mask5 = _mm_load_ps(pafMask + iPixel + 4 * 5);
1000 3347660 : __m128 xmm_mask6 = _mm_load_ps(pafMask + iPixel + 4 * 6);
1001 6695320 : __m128 xmm_mask7 = _mm_load_ps(pafMask + iPixel + 4 * 7);
1002 3347660 : xmm_mask0 = _mm_mul_ps(xmm_mask0, xmm_alpha_max);
1003 3347660 : xmm_mask1 = _mm_mul_ps(xmm_mask1, xmm_alpha_max);
1004 3347660 : xmm_mask2 = _mm_mul_ps(xmm_mask2, xmm_alpha_max);
1005 3347660 : xmm_mask3 = _mm_mul_ps(xmm_mask3, xmm_alpha_max);
1006 3347660 : xmm_mask4 = _mm_mul_ps(xmm_mask4, xmm_alpha_max);
1007 3347660 : xmm_mask5 = _mm_mul_ps(xmm_mask5, xmm_alpha_max);
1008 3347660 : xmm_mask6 = _mm_mul_ps(xmm_mask6, xmm_alpha_max);
1009 3347660 : xmm_mask7 = _mm_mul_ps(xmm_mask7, xmm_alpha_max);
1010 : // Truncate to int.
1011 3347660 : _mm_store_si128(
1012 3347660 : reinterpret_cast<__m128i *>(pafMask + iPixel + 4 * 0),
1013 : _mm_cvttps_epi32(xmm_mask0));
1014 3347660 : _mm_store_si128(
1015 3347660 : reinterpret_cast<__m128i *>(pafMask + iPixel + 4 * 1),
1016 : _mm_cvttps_epi32(xmm_mask1));
1017 3347660 : _mm_store_si128(
1018 3347660 : reinterpret_cast<__m128i *>(pafMask + iPixel + 4 * 2),
1019 : _mm_cvttps_epi32(xmm_mask2));
1020 3347660 : _mm_store_si128(
1021 3347660 : reinterpret_cast<__m128i *>(pafMask + iPixel + 4 * 3),
1022 : _mm_cvttps_epi32(xmm_mask3));
1023 3347660 : _mm_store_si128(
1024 3347660 : reinterpret_cast<__m128i *>(pafMask + iPixel + 4 * 4),
1025 : _mm_cvttps_epi32(xmm_mask4));
1026 3347660 : _mm_store_si128(
1027 3347660 : reinterpret_cast<__m128i *>(pafMask + iPixel + 4 * 5),
1028 : _mm_cvttps_epi32(xmm_mask5));
1029 3347660 : _mm_store_si128(
1030 3347660 : reinterpret_cast<__m128i *>(pafMask + iPixel + 4 * 6),
1031 : _mm_cvttps_epi32(xmm_mask6));
1032 3347660 : _mm_store_si128(
1033 3347660 : reinterpret_cast<__m128i *>(pafMask + iPixel + 4 * 7),
1034 : _mm_cvttps_epi32(xmm_mask7));
1035 : }
1036 3052 : for (; iPixel < nPixels; iPixel++)
1037 1340 : reinterpret_cast<int *>(pafMask)[iPixel] =
1038 1340 : static_cast<int>(pafMask[iPixel] * cst_alpha_max);
1039 :
1040 : // Write data.
1041 : // Assumes little endianness here.
1042 3424 : eErr = GDALRasterIOEx(
1043 : hAlphaBand, GF_Write, nXOff, nYOff, nXSize, nYSize, pafMask,
1044 : nXSize, nYSize, eDT, static_cast<GSpacing>(sizeof(int)),
1045 1712 : static_cast<GSpacing>(sizeof(int)) * nXSize, nullptr);
1046 : }
1047 : else
1048 : #endif
1049 : {
1050 9 : for (; iPixel + 3 < nPixels; iPixel += 4)
1051 : {
1052 8 : pafMask[iPixel + 0] = static_cast<float>(
1053 8 : static_cast<int>(pafMask[iPixel + 0] * cst_alpha_max));
1054 8 : pafMask[iPixel + 1] = static_cast<float>(
1055 8 : static_cast<int>(pafMask[iPixel + 1] * cst_alpha_max));
1056 8 : pafMask[iPixel + 2] = static_cast<float>(
1057 8 : static_cast<int>(pafMask[iPixel + 2] * cst_alpha_max));
1058 8 : pafMask[iPixel + 3] = static_cast<float>(
1059 8 : static_cast<int>(pafMask[iPixel + 3] * cst_alpha_max));
1060 : }
1061 2 : for (; iPixel < nPixels; iPixel++)
1062 1 : pafMask[iPixel] = static_cast<float>(
1063 1 : static_cast<int>(pafMask[iPixel] * cst_alpha_max));
1064 :
1065 : // Write data.
1066 :
1067 : eErr =
1068 1 : GDALRasterIO(hAlphaBand, GF_Write, nXOff, nYOff, nXSize, nYSize,
1069 : pafMask, nXSize, nYSize, GDT_Float32, 0, 0);
1070 : }
1071 1713 : return eErr;
1072 : }
1073 : }
1074 :
1075 : /************************************************************************/
1076 : /* GDALWarpGetOptionList() */
1077 : /************************************************************************/
1078 :
1079 : /** Return a XML string describing options accepted by
1080 : * GDALWarpOptions::papszWarpOptions.
1081 : *
1082 : * @since 3.11
1083 : */
1084 1777 : const char *GDALWarpGetOptionList(void)
1085 : {
1086 : return "<OptionList>"
1087 : "<Option name='INIT_DEST' type='string' description='"
1088 : "Numeric value or NO_DATA. This option forces the destination image "
1089 : "to be initialized to the indicated value (for all bands) "
1090 : "or indicates that it should be initialized to the NO_DATA value in "
1091 : "padfDstNoDataReal/padfDstNoDataImag. If this value is not set, the "
1092 : "destination image will be read and overlaid.'/>"
1093 : "<Option name='RESET_DEST_PIXELS' type='boolean' description='"
1094 : "Whether the whole destination image must be re-initialized to the "
1095 : "destination nodata value of padfDstNoDataReal/padfDstNoDataImag "
1096 : "if set, or 0 otherwise. The main difference with INIT_DEST is that "
1097 : "it also affects regions not related to the source dataset.' "
1098 : "default='NO'/>"
1099 : "<Option name='WRITE_FLUSH' type='boolean' description='"
1100 : "This option forces a flush to disk of data after "
1101 : "each chunk is processed. In some cases this helps ensure a serial "
1102 : " writing of the output data otherwise a block of data may be "
1103 : "written to disk each time a block of data is read for the input "
1104 : "buffer resulting in a lot of extra seeking around the disk, and "
1105 : "reduced IO throughput.' default='NO'/>"
1106 : "<Option name='SKIP_NOSOURCE' type='boolean' description='"
1107 : "Skip all processing for chunks for which there is no corresponding "
1108 : "input data. This will disable initializing the destination "
1109 : "(INIT_DEST) and all other processing, and so should be used "
1110 : "carefully. Mostly useful to short circuit a lot of extra work "
1111 : "in mosaicing situations. gdalwarp will automatically enable this "
1112 : "option when it is assumed to be safe to do so.' default='NO'/>"
1113 : #ifdef undocumented
1114 : "<Option name='ERROR_OUT_IF_EMPTY_SOURCE_WINDOW' type='boolean' "
1115 : "description='By default, if the source window corresponding to the "
1116 : "current target window fails to be determined due to reprojection "
1117 : "errors, the warping fails. Setting this option to NO prevent such "
1118 : "failure from happening. The warped VRT mechanism automatically "
1119 : "sets it to NO.'/>"
1120 : #endif
1121 : "<Option name='UNIFIED_SRC_NODATA' type='string-select' "
1122 : "description='"
1123 : "This setting determines how to take into account nodata values "
1124 : "when there are several input bands. Consult "
1125 : "GDALWarpOptions::papszWarpOptions documentation for more details.'>"
1126 : " <Value>AUTO</Value>"
1127 : " <Value>PARTIAL</Value>"
1128 : " <Value>YES</Value>"
1129 : " <Value>NO</Value>"
1130 : "</Option>"
1131 : "<Option name='CUTLINE' type='string' description='"
1132 : "This may contain the WKT geometry for a cutline. It will be "
1133 : "converted into a geometry by GDALWarpOperation::Initialize() and "
1134 : "assigned to the GDALWarpOptions hCutline field. The coordinates "
1135 : "must be expressed in source pixel/line coordinates. Note: this is "
1136 : "different from the assumptions made for the -cutline option "
1137 : "of the gdalwarp utility !'/>"
1138 : "<Option name='CUTLINE_BLEND_DIST' type='float' description='"
1139 : "This may be set with a distance in pixels which will be assigned "
1140 : "to the dfCutlineBlendDist field in the GDALWarpOptions.'/>"
1141 : "<Option name='CUTLINE_ALL_TOUCHED' type='boolean' description='"
1142 : "This may be set to TRUE to enable ALL_TOUCHED mode when "
1143 : "rasterizing cutline polygons. This is useful to ensure that that "
1144 : "all pixels overlapping the cutline polygon will be selected, not "
1145 : "just those whose center point falls within the polygon.' "
1146 : "default='NO'/>"
1147 : "<Option name='XSCALE' type='float' description='"
1148 : "Ratio expressing the resampling factor (number of destination "
1149 : "pixels per source pixel) along the target horizontal axis. The "
1150 : "scale is used to determine the number of source pixels along the "
1151 : "x-axis that are considered by the resampling algorithm. "
1152 : "Equals to one for no resampling, below one for downsampling "
1153 : "and above one for upsampling. This is automatically computed, "
1154 : "for each processing chunk, and may thus vary among them, depending "
1155 : "on the shape of output regions vs input regions. Such variations "
1156 : "can be undesired in some situations. If the resampling factor "
1157 : "can be considered as constant over the warped area, setting a "
1158 : "constant value can lead to more reproducible pixel output.'/>"
1159 : "<Option name='YSCALE' type='float' description='"
1160 : "Same as XSCALE, but along the horizontal axis.'/>"
1161 : "<Option name='OPTIMIZE_SIZE' type='boolean' description='"
1162 : "This defaults to FALSE, but may be set to TRUE typically when "
1163 : "writing to a compressed dataset (GeoTIFF with COMPRESS creation "
1164 : "option set for example) for achieving a smaller file size. This "
1165 : "is achieved by writing at once data aligned on full blocks of the "
1166 : "target dataset, which avoids partial writes of compressed blocks "
1167 : "and lost space when they are rewritten at the end of the file. "
1168 : "However sticking to target block size may cause major processing "
1169 : "slowdown for some particular reprojections. OPTIMIZE_SIZE mode "
1170 : "is automatically enabled when it is safe to do so. "
1171 : "As this parameter influences the shape of warping chunk, and by "
1172 : "default the XSCALE and YSCALE parameters are computed per warping "
1173 : "chunk, this parameter may influence the pixel output.' "
1174 : "default='NO'/>"
1175 : "<Option name='NUM_THREADS' type='string' description='"
1176 : "Can be set to a numeric value or ALL_CPUS to set the number of "
1177 : "threads to use to parallelize the computation part of the warping. "
1178 : "If not set, computation will be done in a single thread..'/>"
1179 : "<Option name='STREAMABLE_OUTPUT' type='boolean' description='"
1180 : "This defaults to FALSE, but may be set to TRUE typically when "
1181 : "writing to a streamed file. The gdalwarp utility automatically "
1182 : "sets this option when writing to /vsistdout/ or a named pipe "
1183 : "(on Unix). This option has performance impacts for some "
1184 : "reprojections. Note: band interleaved output is "
1185 : "not currently supported by the warping algorithm in a streamable "
1186 : "compatible way.' default='NO'/>"
1187 : "<Option name='SRC_COORD_PRECISION' type='float' description='"
1188 : "Advanced setting. This defaults to 0, to indicate that no rounding "
1189 : "of computing source image coordinates corresponding to the target "
1190 : "image must be done. If greater than 0 (and typically below 1), "
1191 : "this value, expressed in pixel, will be used to round computed "
1192 : "source image coordinates. The purpose of this option is to make "
1193 : "the results of warping with the approximated transformer more "
1194 : "reproducible and not sensitive to changes in warping memory size. "
1195 : "To achieve that, SRC_COORD_PRECISION must be at least 10 times "
1196 : "greater than the error threshold. The higher the "
1197 : "SRC_COORD_PRECISION/error_threshold ratio, the higher the "
1198 : "performance will be, since exact reprojections must statistically "
1199 : "be done with a frequency of "
1200 : "4*error_threshold/SRC_COORD_PRECISION.' default='0'/>"
1201 : "<Option name='SRC_ALPHA_MAX' type='float' description='"
1202 : "Maximum value for the alpha band of the source dataset. If the "
1203 : "value is not set and the alpha band has a NBITS metadata item, "
1204 : "it is used to set SRC_ALPHA_MAX = 2^NBITS-1. Otherwise, if the "
1205 : "value is not set and the alpha band is of type UInt16 "
1206 : "(resp Int16), 65535 (resp 32767) is used. "
1207 : "Otherwise, 255 is used.'/>"
1208 : "<Option name='DST_ALPHA_MAX' type='float' description='"
1209 : "Maximum value for the alpha band of the destination dataset. "
1210 : "If the value is not set and the alpha band has a NBITS metadata "
1211 : "item, it is used to set SRC_ALPHA_MAX = 2^NBITS-1. Otherwise, if "
1212 : "the value is not set and the alpha band is of type UInt16 "
1213 : "(resp Int16), 65535 (resp 32767) is used. "
1214 : "Otherwise, 255 is used.'/>"
1215 : "<Option name='SAMPLE_GRID' type='boolean' description='"
1216 : "Setting this option to YES will force the sampling to "
1217 : "include internal points as well as edge points which can be "
1218 : "important if the transformation is esoteric inside out, or if "
1219 : "large sections of the destination image are not transformable into "
1220 : "the source coordinate system.' default='NO'/>"
1221 : "<Option name='SAMPLE_STEPS' type='string' description='"
1222 : "Modifies the density of the sampling grid. Increasing this can "
1223 : "increase the computational cost, but improves the accuracy with "
1224 : "which the source region is computed. This can be set to ALL to "
1225 : "mean to sample along all edge points of the destination region "
1226 : "(if SAMPLE_GRID=NO or not specified), or all points of the "
1227 : "destination region if SAMPLE_GRID=YES.' default='21'/>"
1228 : "<Option name='SOURCE_EXTRA' type='int' description='"
1229 : "This is a number of extra pixels added around the source "
1230 : "window for a given request, and by default it is 1 to take care "
1231 : "of rounding error. Setting this larger will increase the amount of "
1232 : "data that needs to be read, but can avoid missing source data.' "
1233 : "default='1'/>"
1234 : "<Option name='APPLY_VERTICAL_SHIFT' type='boolean' description='"
1235 : "Force the use of vertical shift. This option is generally not "
1236 : "necessary, except when using an explicit coordinate transformation "
1237 : "(COORDINATE_OPERATION), and not specifying an explicit source and "
1238 : "target SRS.'/>"
1239 : "<Option name='MULT_FACTOR_VERTICAL_SHIFT' type='float' "
1240 : "description='"
1241 : "Multiplication factor for the vertical shift' default='1.0'/>"
1242 : "<Option name='EXCLUDED_VALUES' type='string' "
1243 : "description='"
1244 : "Comma-separated tuple of values (thus typically \"R,G,B\"), that "
1245 : "are ignored as contributing source pixels during resampling. "
1246 : "The number of values in the tuple must be the same as the number "
1247 : "of bands, excluding the alpha band. Several tuples of excluded "
1248 : "values may be specified using the \"(R1,G1,B2),(R2,G2,B2)\" syntax."
1249 : " Only taken into account by Average currently. This concept is a "
1250 : "bit similar to nodata/alpha, but the main difference is that "
1251 : "pixels matching one of the excluded value tuples are still "
1252 : "considered as valid, when determining the target pixel "
1253 : "validity/density.'/>"
1254 : "<Option name='EXCLUDED_VALUES_PCT_THRESHOLD' type='float' "
1255 : "min='0' max='100' description='"
1256 : "Minimum percentage of source pixels that must be set at one of "
1257 : "the EXCLUDED_VALUES to cause the excluded value, that is in "
1258 : "majority among source pixels, to be used as the target pixel "
1259 : "value. Only taken into account by Average currently.' "
1260 : "default='50'/>"
1261 : "<Option name='NODATA_VALUES_PCT_THRESHOLD' type='float' "
1262 : "min='0' max='100' description='"
1263 : "Minimum percentage of source pixels that must be at nodata (or "
1264 : "alpha=0 or any other way to express transparent pixel) to cause "
1265 : "the target pixel value to not be set. Default value is 100 (%), "
1266 : "which means that a target pixel is not set only if all "
1267 : "contributing source pixels are not set. Note that "
1268 : "NODATA_VALUES_PCT_THRESHOLD is taken into account before "
1269 : "EXCLUDED_VALUES_PCT_THRESHOLD. Only taken into account by Average "
1270 : "currently.' default='100'/>"
1271 : "<Option name='MODE_TIES' type='string-select' "
1272 : "description='"
1273 : "Strategy to use when breaking ties with MODE resampling. "
1274 : "By default, the first value encountered will be used. "
1275 : "Alternatively, the minimum or maximum value can be selected.' "
1276 : "default='FIRST'>"
1277 : " <Value>FIRST</Value>"
1278 : " <Value>MIN</Value>"
1279 : " <Value>MAX</Value>"
1280 : "</Option>"
1281 1777 : "</OptionList>";
1282 : }
1283 :
1284 : /************************************************************************/
1285 : /* ==================================================================== */
1286 : /* GDALWarpOptions */
1287 : /* ==================================================================== */
1288 : /************************************************************************/
1289 :
1290 : /**
1291 : * \var char **GDALWarpOptions::papszWarpOptions;
1292 : *
1293 : * A string list of additional options controlling the warp operation in
1294 : * name=value format. A suitable string list can be prepared with
1295 : * CSLSetNameValue().
1296 : *
1297 : * The available options can also be retrieved programmatically with
1298 : * GDALWarpGetOptionList().
1299 : *
1300 : * The following values are currently supported:
1301 : * <ul>
1302 : * <li>INIT_DEST=[value] or INIT_DEST=NO_DATA: This option forces the
1303 : * destination image to be initialized to the indicated value (for all bands)
1304 : * or indicates that it should be initialized to the NO_DATA value in
1305 : * padfDstNoDataReal/padfDstNoDataImag. If this value isn't set the
1306 : * destination image will be read and overlaid.</li>
1307 : *
1308 : * <li>RESET_DEST_PIXELS=YES/NO (since GDAL 3.13): Defaults to NO.
1309 : * Whether the whole destination image must be re-initialized to the
1310 : * destination nodata value of padfDstNoDataReal/padfDstNoDataImag if set,
1311 : * or 0 otherwise.
1312 : * The main difference with INIT_DEST is that it also affects regions
1313 : * not related to the source dataset.
1314 : * </li>
1315 : *
1316 : * <li>WRITE_FLUSH=YES/NO: This option forces a flush to disk of data after
1317 : * each chunk is processed. In some cases this helps ensure a serial
1318 : * writing of the output data otherwise a block of data may be written to disk
1319 : * each time a block of data is read for the input buffer resulting in a lot
1320 : * of extra seeking around the disk, and reduced IO throughput. The default
1321 : * is NO.</li>
1322 : *
1323 : * <li>SKIP_NOSOURCE=YES/NO: Skip all processing for chunks for which there
1324 : * is no corresponding input data. This will disable initializing the
1325 : * destination (INIT_DEST) and all other processing, and so should be used
1326 : * carefully. Mostly useful to short circuit a lot of extra work in mosaicing
1327 : * situations. gdalwarp will automatically enable this
1328 : * option when it is assumed to be safe to do so.</li>
1329 : *
1330 : * <li>UNIFIED_SRC_NODATA=YES/NO/PARTIAL: This setting determines
1331 : * how to take into account nodata values when there are several input bands.
1332 : * <ul>
1333 : * <li>When YES, all bands are considered as nodata if and only if, all bands
1334 : * match the corresponding nodata values.
1335 : * Note: UNIFIED_SRC_NODATA=YES is set by default, when called from gdalwarp
1336 : * / GDALWarp() with an explicit -srcnodata setting.
1337 : *
1338 : * Example with nodata values at (1, 2, 3) and target alpha band requested.
1339 : * <ul>
1340 : * <li>input pixel = (1, 2, 3) ==> output pixel = (0, 0, 0, 0)</li>
1341 : * <li>input pixel = (1, 2, 127) ==> output pixel = (1, 2, 127, 255)</li>
1342 : * </ul>
1343 : * </li>
1344 : * <li>When NO, nodata masking values is considered independently for each band.
1345 : * A potential target alpha band will always be valid if there are multiple
1346 : * bands.
1347 : *
1348 : * Example with nodata values at (1, 2, 3) and target alpha band requested.
1349 : * <ul>
1350 : * <li>input pixel = (1, 2, 3) ==> output pixel = (0, 0, 0, 255)</li>
1351 : * <li>input pixel = (1, 2, 127) ==> output pixel = (0, 0, 127, 255)</li>
1352 : * </ul>
1353 : *
1354 : * Note: NO was the default behavior before GDAL 3.3.2
1355 : * </li>
1356 : * <li>When PARTIAL, or not specified at all (default behavior),
1357 : * nodata masking values is considered independently for each band.
1358 : * But, and this is the difference with NO, if for a given pixel, it
1359 : * evaluates to the nodata value of each band, the target pixel is
1360 : * considered as globally invalid, which impacts the value of a potential
1361 : * target alpha band.
1362 : *
1363 : * Note: PARTIAL is new to GDAL 3.3.2 and should not be used with
1364 : * earlier versions. The default behavior of GDAL < 3.3.2 was NO.
1365 : *
1366 : * Example with nodata values at (1, 2, 3) and target alpha band requested.
1367 : * <ul>
1368 : * <li>input pixel = (1, 2, 3) ==> output pixel = (0, 0, 0, 0)</li>
1369 : * <li>input pixel = (1, 2, 127) ==> output pixel = (0, 0, 127, 255)</li>
1370 : * </ul>
1371 : * </li>
1372 : * </ul>
1373 : * </li>
1374 : *
1375 : * <li>CUTLINE: This may contain the WKT geometry for a cutline. It will
1376 : * be converted into a geometry by GDALWarpOperation::Initialize() and assigned
1377 : * to the GDALWarpOptions hCutline field. The coordinates must be expressed
1378 : * in source pixel/line coordinates. Note: this is different from the
1379 : * assumptions made for the -cutline option of the gdalwarp utility !</li>
1380 : *
1381 : * <li>CUTLINE_BLEND_DIST: This may be set with a distance in pixels which
1382 : * will be assigned to the dfCutlineBlendDist field in the GDALWarpOptions.</li>
1383 : *
1384 : * <li>CUTLINE_ALL_TOUCHED: This defaults to FALSE, but may be set to TRUE
1385 : * to enable ALL_TOUCHED mode when rasterizing cutline polygons. This is
1386 : * useful to ensure that that all pixels overlapping the cutline polygon
1387 : * will be selected, not just those whose center point falls within the
1388 : * polygon.</li>
1389 : *
1390 : * <li>XSCALE: Ratio expressing the resampling factor (number of destination
1391 : * pixels per source pixel) along the target horizontal axis.
1392 : * The scale is used to determine the number of source pixels along the x-axis
1393 : * that are considered by the resampling algorithm.
1394 : * Equals to one for no resampling, below one for downsampling
1395 : * and above one for upsampling. This is automatically computed, for each
1396 : * processing chunk, and may thus vary among them, depending on the
1397 : * shape of output regions vs input regions. Such variations can be undesired
1398 : * in some situations. If the resampling factor can be considered as constant
1399 : * over the warped area, setting a constant value can lead to more reproducible
1400 : * pixel output.</li>
1401 : *
1402 : * <li>YSCALE: Same as XSCALE, but along the horizontal axis.</li>
1403 : *
1404 : * <li>OPTIMIZE_SIZE: This defaults to FALSE, but may be set to TRUE
1405 : * typically when writing to a compressed dataset (GeoTIFF with
1406 : * COMPRESS creation option set for example) for achieving a smaller
1407 : * file size. This is achieved by writing at once data aligned on full
1408 : * blocks of the target dataset, which avoids partial writes of
1409 : * compressed blocks and lost space when they are rewritten at the end
1410 : * of the file. However sticking to target block size may cause major
1411 : * processing slowdown for some particular reprojections. Starting
1412 : * with GDAL 3.8, OPTIMIZE_SIZE mode is automatically enabled when it is safe
1413 : * to do so.
1414 : * As this parameter influences the shape of warping chunk, and by default the
1415 : * XSCALE and YSCALE parameters are computed per warping chunk, this parameter may
1416 : * influence the pixel output.
1417 : * </li>
1418 : *
1419 : * <li>NUM_THREADS: (GDAL >= 1.10) Can be set to a numeric value or ALL_CPUS to
1420 : * set the number of threads to use to parallelize the computation part of the
1421 : * warping. If not set, computation will be done in a single thread.</li>
1422 : *
1423 : * <li>STREAMABLE_OUTPUT: This defaults to FALSE, but may
1424 : * be set to TRUE typically when writing to a streamed file. The
1425 : * gdalwarp utility automatically sets this option when writing to
1426 : * /vsistdout/ or a named pipe (on Unix). This option has performance
1427 : * impacts for some reprojections. Note: band interleaved output is
1428 : * not currently supported by the warping algorithm in a streamable
1429 : * compatible way.</li>
1430 : *
1431 : * <li>SRC_COORD_PRECISION: Advanced setting. This
1432 : * defaults to 0, to indicate that no rounding of computing source
1433 : * image coordinates corresponding to the target image must be
1434 : * done. If greater than 0 (and typically below 1), this value,
1435 : * expressed in pixel, will be used to round computed source image
1436 : * coordinates. The purpose of this option is to make the results of
1437 : * warping with the approximated transformer more reproducible and not
1438 : * sensitive to changes in warping memory size. To achieve that,
1439 : * SRC_COORD_PRECISION must be at least 10 times greater than the
1440 : * error threshold. The higher the SRC_COORD_PRECISION/error_threshold
1441 : * ratio, the higher the performance will be, since exact
1442 : * reprojections must statistically be done with a frequency of
1443 : * 4*error_threshold/SRC_COORD_PRECISION.</li>
1444 : *
1445 : * <li>SRC_ALPHA_MAX: Maximum value for the alpha band of the
1446 : * source dataset. If the value is not set and the alpha band has a NBITS
1447 : * metadata item, it is used to set SRC_ALPHA_MAX = 2^NBITS-1. Otherwise, if the
1448 : * value is not set and the alpha band is of type UInt16 (resp Int16), 65535
1449 : * (resp 32767) is used. Otherwise, 255 is used.</li>
1450 : *
1451 : * <li>DST_ALPHA_MAX: Maximum value for the alpha band of the
1452 : * destination dataset. If the value is not set and the alpha band has a NBITS
1453 : * metadata item, it is used to set DST_ALPHA_MAX = 2^NBITS-1. Otherwise, if the
1454 : * value is not set and the alpha band is of type UInt16 (resp Int16), 65535
1455 : * (resp 32767) is used. Otherwise, 255 is used.</li>
1456 : * </ul>
1457 : *
1458 : * Normally when computing the source raster data to
1459 : * load to generate a particular output area, the warper samples transforms
1460 : * 21 points along each edge of the destination region back onto the source
1461 : * file, and uses this to compute a bounding window on the source image that
1462 : * is sufficient. Depending on the transformation in effect, the source
1463 : * window may be a bit too small, or even missing large areas. Problem
1464 : * situations are those where the transformation is very non-linear or
1465 : * "inside out". Examples are transforming from WGS84 to Polar Stereographic
1466 : * for areas around the pole, or transformations where some of the image is
1467 : * untransformable. The following options provide some additional control
1468 : * to deal with errors in computing the source window:
1469 : * <ul>
1470 : *
1471 : * <li>SAMPLE_GRID=YES/NO: Setting this option to YES will force the sampling to
1472 : * include internal points as well as edge points which can be important if
1473 : * the transformation is esoteric inside out, or if large sections of the
1474 : * destination image are not transformable into the source coordinate
1475 : * system.</li>
1476 : *
1477 : * <li>SAMPLE_STEPS: Modifies the density of the sampling grid. The default
1478 : * number of steps is 21. Increasing this can increase the computational
1479 : * cost, but improves the accuracy with which the source region is
1480 : * computed.
1481 : * Starting with GDAL 3.7, this can be set to ALL to mean to sample
1482 : * along all edge points of the destination region (if SAMPLE_GRID=NO or not
1483 : * specified), or all points of the destination region if SAMPLE_GRID=YES.</li>
1484 : *
1485 : * <li>SOURCE_EXTRA: This is a number of extra pixels added around the source
1486 : * window for a given request, and by default it is 1 to take care of rounding
1487 : * error. Setting this larger will increase the amount of data that needs to
1488 : * be read, but can avoid missing source data.</li>
1489 : * <li>APPLY_VERTICAL_SHIFT=YES/NO: Force the use of vertical shift.
1490 : * This option is generally not necessary, except when using an explicit
1491 : * coordinate transformation (COORDINATE_OPERATION), and not specifying
1492 : * an explicit source and target SRS.</li>
1493 : * <li>MULT_FACTOR_VERTICAL_SHIFT: Multiplication factor for the vertical
1494 : * shift. Default 1.0</li>
1495 : *
1496 : * <li>EXCLUDED_VALUES: (GDAL >= 3.9) Comma-separated tuple of values
1497 : * (thus typically "R,G,B"), that are ignored as contributing source
1498 : * pixels during resampling. The number of values in the tuple must be the same
1499 : * as the number of bands, excluding the alpha band.
1500 : * Several tuples of excluded values may be specified using the
1501 : * "(R1,G1,B2),(R2,G2,B2)" syntax.
1502 : * Only taken into account by Average currently.
1503 : * This concept is a bit similar to nodata/alpha, but the main difference is
1504 : * that pixels matching one of the excluded value tuples are still considered
1505 : * as valid, when determining the target pixel validity/density.
1506 : * </li>
1507 : *
1508 : * <li>EXCLUDED_VALUES_PCT_THRESHOLD=[0-100]: (GDAL >= 3.9) Minimum percentage
1509 : * of source pixels that must be set at one of the EXCLUDED_VALUES to cause
1510 : * the excluded value, that is in majority among source pixels, to be used as the
1511 : * target pixel value. Default value is 50 (%).
1512 : * Only taken into account by Average currently.</li>
1513 : *
1514 : * <li>NODATA_VALUES_PCT_THRESHOLD=[0-100]: (GDAL >= 3.9) Minimum percentage
1515 : * of source pixels that must be at nodata (or alpha=0 or any other way to express
1516 : * transparent pixel) to cause the target pixel value to not be set. Default
1517 : * value is 100 (%), which means that a target pixel is not set only if all
1518 : * contributing source pixels are not set.
1519 : * Note that NODATA_VALUES_PCT_THRESHOLD is taken into account before
1520 : * EXCLUDED_VALUES_PCT_THRESHOLD.
1521 : * Only taken into account by Average currently.</li>
1522 : *
1523 : * <li>MODE_TIES=FIRST/MIN/MAX: (GDAL >= 3.11) Strategy to use when breaking
1524 : * ties with MODE resampling. By default, the first value encountered will be used.
1525 : * Alternatively, the minimum or maximum value can be selected.</li>
1526 : *
1527 : * </ul>
1528 : */
1529 :
1530 : /************************************************************************/
1531 : /* GDALCreateWarpOptions() */
1532 : /************************************************************************/
1533 :
1534 : /** Create a warp options structure.
1535 : *
1536 : * Must be deallocated with GDALDestroyWarpOptions()
1537 : */
1538 3788 : GDALWarpOptions *CPL_STDCALL GDALCreateWarpOptions()
1539 :
1540 : {
1541 : GDALWarpOptions *psOptions =
1542 3788 : static_cast<GDALWarpOptions *>(CPLCalloc(sizeof(GDALWarpOptions), 1));
1543 :
1544 3788 : psOptions->nBandCount = 0;
1545 3788 : psOptions->eResampleAlg = GRA_NearestNeighbour;
1546 3788 : psOptions->pfnProgress = GDALDummyProgress;
1547 3788 : psOptions->eWorkingDataType = GDT_Unknown;
1548 3788 : psOptions->eTieStrategy = GWKTS_First;
1549 :
1550 3788 : return psOptions;
1551 : }
1552 :
1553 : /************************************************************************/
1554 : /* GDALDestroyWarpOptions() */
1555 : /************************************************************************/
1556 :
1557 : /** Destroy a warp options structure. */
1558 3788 : void CPL_STDCALL GDALDestroyWarpOptions(GDALWarpOptions *psOptions)
1559 :
1560 : {
1561 3788 : if (psOptions == nullptr)
1562 0 : return;
1563 :
1564 3788 : CSLDestroy(psOptions->papszWarpOptions);
1565 3788 : CPLFree(psOptions->panSrcBands);
1566 3788 : CPLFree(psOptions->panDstBands);
1567 3788 : CPLFree(psOptions->padfSrcNoDataReal);
1568 3788 : CPLFree(psOptions->padfSrcNoDataImag);
1569 3788 : CPLFree(psOptions->padfDstNoDataReal);
1570 3788 : CPLFree(psOptions->padfDstNoDataImag);
1571 3788 : CPLFree(psOptions->papfnSrcPerBandValidityMaskFunc);
1572 3788 : CPLFree(psOptions->papSrcPerBandValidityMaskFuncArg);
1573 :
1574 3788 : if (psOptions->hCutline != nullptr)
1575 54 : delete static_cast<OGRGeometry *>(psOptions->hCutline);
1576 :
1577 3788 : CPLFree(psOptions);
1578 : }
1579 :
1580 : #define COPY_MEM(target, type, count) \
1581 : do \
1582 : { \
1583 : if ((psSrcOptions->target) != nullptr && (count) != 0) \
1584 : { \
1585 : (psDstOptions->target) = \
1586 : static_cast<type *>(CPLMalloc(sizeof(type) * (count))); \
1587 : memcpy((psDstOptions->target), (psSrcOptions->target), \
1588 : sizeof(type) * (count)); \
1589 : } \
1590 : else \
1591 : (psDstOptions->target) = nullptr; \
1592 : } while (false)
1593 :
1594 : /************************************************************************/
1595 : /* GDALCloneWarpOptions() */
1596 : /************************************************************************/
1597 :
1598 : /** Clone a warp options structure.
1599 : *
1600 : * Must be deallocated with GDALDestroyWarpOptions()
1601 : */
1602 : GDALWarpOptions *CPL_STDCALL
1603 2047 : GDALCloneWarpOptions(const GDALWarpOptions *psSrcOptions)
1604 :
1605 : {
1606 2047 : GDALWarpOptions *psDstOptions = GDALCreateWarpOptions();
1607 :
1608 2047 : memcpy(psDstOptions, psSrcOptions, sizeof(GDALWarpOptions));
1609 :
1610 2047 : if (psSrcOptions->papszWarpOptions != nullptr)
1611 1826 : psDstOptions->papszWarpOptions =
1612 1826 : CSLDuplicate(psSrcOptions->papszWarpOptions);
1613 :
1614 2047 : COPY_MEM(panSrcBands, int, psSrcOptions->nBandCount);
1615 2047 : COPY_MEM(panDstBands, int, psSrcOptions->nBandCount);
1616 2047 : COPY_MEM(padfSrcNoDataReal, double, psSrcOptions->nBandCount);
1617 2047 : COPY_MEM(padfSrcNoDataImag, double, psSrcOptions->nBandCount);
1618 2047 : COPY_MEM(padfDstNoDataReal, double, psSrcOptions->nBandCount);
1619 2047 : COPY_MEM(padfDstNoDataImag, double, psSrcOptions->nBandCount);
1620 : // cppcheck-suppress pointerSize
1621 2047 : COPY_MEM(papfnSrcPerBandValidityMaskFunc, GDALMaskFunc,
1622 : psSrcOptions->nBandCount);
1623 2047 : psDstOptions->papSrcPerBandValidityMaskFuncArg = nullptr;
1624 :
1625 2047 : if (psSrcOptions->hCutline != nullptr)
1626 10 : psDstOptions->hCutline =
1627 10 : OGR_G_Clone(static_cast<OGRGeometryH>(psSrcOptions->hCutline));
1628 2047 : psDstOptions->dfCutlineBlendDist = psSrcOptions->dfCutlineBlendDist;
1629 :
1630 2047 : return psDstOptions;
1631 : }
1632 :
1633 : namespace
1634 : {
1635 138 : void InitNoData(int nBandCount, double **ppdNoDataReal, double dDataReal)
1636 : {
1637 138 : if (nBandCount <= 0)
1638 : {
1639 0 : return;
1640 : }
1641 138 : if (*ppdNoDataReal != nullptr)
1642 : {
1643 32 : return;
1644 : }
1645 :
1646 106 : *ppdNoDataReal =
1647 106 : static_cast<double *>(CPLMalloc(sizeof(double) * nBandCount));
1648 :
1649 244 : for (int i = 0; i < nBandCount; ++i)
1650 : {
1651 138 : (*ppdNoDataReal)[i] = dDataReal;
1652 : }
1653 : }
1654 : } // namespace
1655 :
1656 : /************************************************************************/
1657 : /* GDALWarpInitDstNoDataReal() */
1658 : /************************************************************************/
1659 :
1660 : /**
1661 : * \brief Initialize padfDstNoDataReal with specified value.
1662 : *
1663 : * @param psOptionsIn options to initialize.
1664 : * @param dNoDataReal value to initialize to.
1665 : *
1666 : */
1667 38 : void CPL_STDCALL GDALWarpInitDstNoDataReal(GDALWarpOptions *psOptionsIn,
1668 : double dNoDataReal)
1669 : {
1670 38 : VALIDATE_POINTER0(psOptionsIn, "GDALWarpInitDstNoDataReal");
1671 38 : InitNoData(psOptionsIn->nBandCount, &psOptionsIn->padfDstNoDataReal,
1672 : dNoDataReal);
1673 : }
1674 :
1675 : /************************************************************************/
1676 : /* GDALWarpInitSrcNoDataReal() */
1677 : /************************************************************************/
1678 :
1679 : /**
1680 : * \brief Initialize padfSrcNoDataReal with specified value.
1681 : *
1682 : * @param psOptionsIn options to initialize.
1683 : * @param dNoDataReal value to initialize to.
1684 : *
1685 : */
1686 34 : void CPL_STDCALL GDALWarpInitSrcNoDataReal(GDALWarpOptions *psOptionsIn,
1687 : double dNoDataReal)
1688 : {
1689 34 : VALIDATE_POINTER0(psOptionsIn, "GDALWarpInitSrcNoDataReal");
1690 34 : InitNoData(psOptionsIn->nBandCount, &psOptionsIn->padfSrcNoDataReal,
1691 : dNoDataReal);
1692 : }
1693 :
1694 : /************************************************************************/
1695 : /* GDALWarpInitNoDataReal() */
1696 : /************************************************************************/
1697 :
1698 : /**
1699 : * \brief Initialize padfSrcNoDataReal and padfDstNoDataReal with specified
1700 : * value.
1701 : *
1702 : * @param psOptionsIn options to initialize.
1703 : * @param dNoDataReal value to initialize to.
1704 : *
1705 : */
1706 1 : void CPL_STDCALL GDALWarpInitNoDataReal(GDALWarpOptions *psOptionsIn,
1707 : double dNoDataReal)
1708 : {
1709 1 : GDALWarpInitDstNoDataReal(psOptionsIn, dNoDataReal);
1710 1 : GDALWarpInitSrcNoDataReal(psOptionsIn, dNoDataReal);
1711 1 : }
1712 :
1713 : /************************************************************************/
1714 : /* GDALWarpInitDstNoDataImag() */
1715 : /************************************************************************/
1716 :
1717 : /**
1718 : * \brief Initialize padfDstNoDataImag with specified value.
1719 : *
1720 : * @param psOptionsIn options to initialize.
1721 : * @param dNoDataImag value to initialize to.
1722 : *
1723 : */
1724 35 : void CPL_STDCALL GDALWarpInitDstNoDataImag(GDALWarpOptions *psOptionsIn,
1725 : double dNoDataImag)
1726 : {
1727 35 : VALIDATE_POINTER0(psOptionsIn, "GDALWarpInitDstNoDataImag");
1728 35 : InitNoData(psOptionsIn->nBandCount, &psOptionsIn->padfDstNoDataImag,
1729 : dNoDataImag);
1730 : }
1731 :
1732 : /************************************************************************/
1733 : /* GDALWarpInitSrcNoDataImag() */
1734 : /************************************************************************/
1735 :
1736 : /**
1737 : * \brief Initialize padfSrcNoDataImag with specified value.
1738 : *
1739 : * @param psOptionsIn options to initialize.
1740 : * @param dNoDataImag value to initialize to.
1741 : *
1742 : */
1743 31 : void CPL_STDCALL GDALWarpInitSrcNoDataImag(GDALWarpOptions *psOptionsIn,
1744 : double dNoDataImag)
1745 : {
1746 31 : VALIDATE_POINTER0(psOptionsIn, "GDALWarpInitSrcNoDataImag");
1747 31 : InitNoData(psOptionsIn->nBandCount, &psOptionsIn->padfSrcNoDataImag,
1748 : dNoDataImag);
1749 : }
1750 :
1751 : /************************************************************************/
1752 : /* GDALWarpResolveWorkingDataType() */
1753 : /************************************************************************/
1754 :
1755 : /**
1756 : * \brief If the working data type is unknown, this method will determine
1757 : * a valid working data type to support the data in the src and dest
1758 : * data sets and any noData values.
1759 : *
1760 : * @param psOptions options to initialize.
1761 : *
1762 : */
1763 1845 : void CPL_STDCALL GDALWarpResolveWorkingDataType(GDALWarpOptions *psOptions)
1764 : {
1765 1845 : if (psOptions == nullptr)
1766 : {
1767 0 : return;
1768 : }
1769 : /* -------------------------------------------------------------------- */
1770 : /* If no working data type was provided, set one now. */
1771 : /* */
1772 : /* Ensure that the working data type can encapsulate any value */
1773 : /* in the target, source, and the no data for either. */
1774 : /* -------------------------------------------------------------------- */
1775 1845 : if (psOptions->eWorkingDataType != GDT_Unknown)
1776 : {
1777 472 : return;
1778 : }
1779 :
1780 : // If none of the provided input nodata values can be represented in the
1781 : // data type of the corresponding source band, ignore them.
1782 1373 : if (psOptions->hSrcDS && psOptions->padfSrcNoDataReal)
1783 : {
1784 140 : int nCountInvalidSrcNoDataReal = 0;
1785 349 : for (int iBand = 0; iBand < psOptions->nBandCount; iBand++)
1786 : {
1787 418 : GDALRasterBandH hSrcBand = GDALGetRasterBand(
1788 209 : psOptions->hSrcDS, psOptions->panSrcBands[iBand]);
1789 :
1790 418 : if (hSrcBand &&
1791 209 : !GDALIsValueExactAs(psOptions->padfSrcNoDataReal[iBand],
1792 : GDALGetRasterDataType(hSrcBand)))
1793 : {
1794 2 : nCountInvalidSrcNoDataReal++;
1795 : }
1796 : }
1797 140 : if (nCountInvalidSrcNoDataReal == psOptions->nBandCount)
1798 : {
1799 2 : CPLFree(psOptions->padfSrcNoDataReal);
1800 2 : psOptions->padfSrcNoDataReal = nullptr;
1801 2 : CPLFree(psOptions->padfSrcNoDataImag);
1802 2 : psOptions->padfSrcNoDataImag = nullptr;
1803 : }
1804 : }
1805 :
1806 3139 : for (int iBand = 0; iBand < psOptions->nBandCount; iBand++)
1807 : {
1808 1766 : if (psOptions->hDstDS != nullptr)
1809 : {
1810 3442 : GDALRasterBandH hDstBand = GDALGetRasterBand(
1811 1721 : psOptions->hDstDS, psOptions->panDstBands[iBand]);
1812 :
1813 1721 : if (hDstBand != nullptr)
1814 : {
1815 1721 : psOptions->eWorkingDataType =
1816 1721 : GDALDataTypeUnion(psOptions->eWorkingDataType,
1817 : GDALGetRasterDataType(hDstBand));
1818 : }
1819 : }
1820 :
1821 1766 : if (psOptions->hSrcDS != nullptr)
1822 : {
1823 3492 : GDALRasterBandH hSrcBand = GDALGetRasterBand(
1824 1746 : psOptions->hSrcDS, psOptions->panSrcBands[iBand]);
1825 :
1826 1746 : if (hSrcBand != nullptr)
1827 : {
1828 1746 : psOptions->eWorkingDataType =
1829 1746 : GDALDataTypeUnion(psOptions->eWorkingDataType,
1830 : GDALGetRasterDataType(hSrcBand));
1831 : }
1832 : }
1833 :
1834 1766 : if (psOptions->padfSrcNoDataReal != nullptr)
1835 : {
1836 217 : psOptions->eWorkingDataType = GDALDataTypeUnionWithValue(
1837 : psOptions->eWorkingDataType,
1838 217 : psOptions->padfSrcNoDataReal[iBand], false);
1839 : }
1840 :
1841 1766 : if (psOptions->padfSrcNoDataImag != nullptr &&
1842 4 : psOptions->padfSrcNoDataImag[iBand] != 0.0)
1843 : {
1844 3 : psOptions->eWorkingDataType = GDALDataTypeUnionWithValue(
1845 : psOptions->eWorkingDataType,
1846 3 : psOptions->padfSrcNoDataImag[iBand], true);
1847 : }
1848 :
1849 1766 : if (psOptions->padfDstNoDataReal != nullptr)
1850 : {
1851 341 : psOptions->eWorkingDataType = GDALDataTypeUnionWithValue(
1852 : psOptions->eWorkingDataType,
1853 341 : psOptions->padfDstNoDataReal[iBand], false);
1854 : }
1855 :
1856 1766 : if (psOptions->padfDstNoDataImag != nullptr &&
1857 231 : psOptions->padfDstNoDataImag[iBand] != 0.0)
1858 : {
1859 3 : psOptions->eWorkingDataType = GDALDataTypeUnionWithValue(
1860 : psOptions->eWorkingDataType,
1861 3 : psOptions->padfDstNoDataImag[iBand], true);
1862 : }
1863 : }
1864 :
1865 1373 : if (psOptions->eWorkingDataType == GDT_Unknown)
1866 1 : psOptions->eWorkingDataType = GDT_UInt8;
1867 :
1868 2746 : const bool bApplyVerticalShift = CPLFetchBool(
1869 1373 : psOptions->papszWarpOptions, "APPLY_VERTICAL_SHIFT", false);
1870 1392 : if (bApplyVerticalShift &&
1871 19 : GDALDataTypeIsInteger(psOptions->eWorkingDataType))
1872 : {
1873 16 : const double dfMultFactorVerticalShift = CPLAtof(CSLFetchNameValueDef(
1874 16 : psOptions->papszWarpOptions, "MULT_FACTOR_VERTICAL_SHIFT", "1.0"));
1875 16 : if (dfMultFactorVerticalShift != 1)
1876 : {
1877 0 : psOptions->eWorkingDataType =
1878 0 : GDALDataTypeUnion(psOptions->eWorkingDataType, GDT_Float32);
1879 : }
1880 : }
1881 : }
1882 :
1883 : /************************************************************************/
1884 : /* GDALWarpInitDefaultBandMapping() */
1885 : /************************************************************************/
1886 :
1887 : /**
1888 : * \brief Init src and dst band mappings such that Bands[i] = i+1
1889 : * for nBandCount
1890 : * Does nothing if psOptionsIn->nBandCount is non-zero.
1891 : *
1892 : * @param psOptionsIn options to initialize.
1893 : * @param nBandCount bands to initialize for.
1894 : *
1895 : */
1896 222 : void CPL_STDCALL GDALWarpInitDefaultBandMapping(GDALWarpOptions *psOptionsIn,
1897 : int nBandCount)
1898 : {
1899 222 : if (psOptionsIn->nBandCount != 0)
1900 : {
1901 0 : return;
1902 : }
1903 :
1904 222 : psOptionsIn->nBandCount = nBandCount;
1905 :
1906 222 : psOptionsIn->panSrcBands =
1907 222 : static_cast<int *>(CPLMalloc(sizeof(int) * psOptionsIn->nBandCount));
1908 222 : psOptionsIn->panDstBands =
1909 222 : static_cast<int *>(CPLMalloc(sizeof(int) * psOptionsIn->nBandCount));
1910 :
1911 525 : for (int i = 0; i < psOptionsIn->nBandCount; i++)
1912 : {
1913 303 : psOptionsIn->panSrcBands[i] = i + 1;
1914 303 : psOptionsIn->panDstBands[i] = i + 1;
1915 : }
1916 : }
1917 :
1918 : /************************************************************************/
1919 : /* GDALSerializeWarpOptions() */
1920 : /************************************************************************/
1921 :
1922 43 : CPLXMLNode *CPL_STDCALL GDALSerializeWarpOptions(const GDALWarpOptions *psWO)
1923 :
1924 : {
1925 : /* -------------------------------------------------------------------- */
1926 : /* Create root. */
1927 : /* -------------------------------------------------------------------- */
1928 : CPLXMLNode *psTree =
1929 43 : CPLCreateXMLNode(nullptr, CXT_Element, "GDALWarpOptions");
1930 :
1931 : /* -------------------------------------------------------------------- */
1932 : /* WarpMemoryLimit */
1933 : /* -------------------------------------------------------------------- */
1934 43 : CPLCreateXMLElementAndValue(
1935 : psTree, "WarpMemoryLimit",
1936 86 : CPLString().Printf("%g", psWO->dfWarpMemoryLimit));
1937 :
1938 : /* -------------------------------------------------------------------- */
1939 : /* ResampleAlg */
1940 : /* -------------------------------------------------------------------- */
1941 43 : const char *pszAlgName = nullptr;
1942 :
1943 43 : if (psWO->eResampleAlg == GRA_NearestNeighbour)
1944 43 : pszAlgName = "NearestNeighbour";
1945 0 : else if (psWO->eResampleAlg == GRA_Bilinear)
1946 0 : pszAlgName = "Bilinear";
1947 0 : else if (psWO->eResampleAlg == GRA_Cubic)
1948 0 : pszAlgName = "Cubic";
1949 0 : else if (psWO->eResampleAlg == GRA_CubicSpline)
1950 0 : pszAlgName = "CubicSpline";
1951 0 : else if (psWO->eResampleAlg == GRA_Lanczos)
1952 0 : pszAlgName = "Lanczos";
1953 0 : else if (psWO->eResampleAlg == GRA_Average)
1954 0 : pszAlgName = "Average";
1955 0 : else if (psWO->eResampleAlg == GRA_RMS)
1956 0 : pszAlgName = "RootMeanSquare";
1957 0 : else if (psWO->eResampleAlg == GRA_Mode)
1958 0 : pszAlgName = "Mode";
1959 0 : else if (psWO->eResampleAlg == GRA_Max)
1960 0 : pszAlgName = "Maximum";
1961 0 : else if (psWO->eResampleAlg == GRA_Min)
1962 0 : pszAlgName = "Minimum";
1963 0 : else if (psWO->eResampleAlg == GRA_Med)
1964 0 : pszAlgName = "Median";
1965 0 : else if (psWO->eResampleAlg == GRA_Q1)
1966 0 : pszAlgName = "Quartile1";
1967 0 : else if (psWO->eResampleAlg == GRA_Q3)
1968 0 : pszAlgName = "Quartile3";
1969 0 : else if (psWO->eResampleAlg == GRA_Sum)
1970 0 : pszAlgName = "Sum";
1971 : else
1972 0 : pszAlgName = "Unknown";
1973 :
1974 43 : CPLCreateXMLElementAndValue(psTree, "ResampleAlg", pszAlgName);
1975 :
1976 : /* -------------------------------------------------------------------- */
1977 : /* Working Data Type */
1978 : /* -------------------------------------------------------------------- */
1979 43 : CPLCreateXMLElementAndValue(psTree, "WorkingDataType",
1980 43 : GDALGetDataTypeName(psWO->eWorkingDataType));
1981 :
1982 : /* -------------------------------------------------------------------- */
1983 : /* Name/value warp options. */
1984 : /* -------------------------------------------------------------------- */
1985 179 : for (int iWO = 0; psWO->papszWarpOptions != nullptr &&
1986 179 : psWO->papszWarpOptions[iWO] != nullptr;
1987 : iWO++)
1988 : {
1989 136 : char *pszName = nullptr;
1990 : const char *pszValue =
1991 136 : CPLParseNameValue(psWO->papszWarpOptions[iWO], &pszName);
1992 :
1993 : // EXTRA_ELTS is an internal detail that we will recover
1994 : // no need to serialize it.
1995 : // And CUTLINE is also serialized in a special way
1996 136 : if (pszName != nullptr && !EQUAL(pszName, "EXTRA_ELTS") &&
1997 93 : !EQUAL(pszName, "CUTLINE"))
1998 : {
1999 : CPLXMLNode *psOption =
2000 93 : CPLCreateXMLElementAndValue(psTree, "Option", pszValue);
2001 :
2002 93 : CPLCreateXMLNode(CPLCreateXMLNode(psOption, CXT_Attribute, "name"),
2003 : CXT_Text, pszName);
2004 : }
2005 :
2006 136 : CPLFree(pszName);
2007 : }
2008 :
2009 : /* -------------------------------------------------------------------- */
2010 : /* Source and Destination Data Source */
2011 : /* -------------------------------------------------------------------- */
2012 43 : if (psWO->hSrcDS != nullptr)
2013 : {
2014 43 : CPLCreateXMLElementAndValue(psTree, "SourceDataset",
2015 43 : GDALGetDescription(psWO->hSrcDS));
2016 :
2017 : CSLConstList papszOpenOptions =
2018 43 : GDALDataset::FromHandle(psWO->hSrcDS)->GetOpenOptions();
2019 43 : GDALSerializeOpenOptionsToXML(psTree, papszOpenOptions);
2020 : }
2021 :
2022 86 : if (psWO->hDstDS != nullptr &&
2023 43 : strlen(GDALGetDescription(psWO->hDstDS)) != 0)
2024 : {
2025 0 : CPLCreateXMLElementAndValue(psTree, "DestinationDataset",
2026 0 : GDALGetDescription(psWO->hDstDS));
2027 : }
2028 :
2029 : /* -------------------------------------------------------------------- */
2030 : /* Serialize transformer. */
2031 : /* -------------------------------------------------------------------- */
2032 43 : if (psWO->pfnTransformer != nullptr)
2033 : {
2034 : CPLXMLNode *psTransformerContainer =
2035 43 : CPLCreateXMLNode(psTree, CXT_Element, "Transformer");
2036 :
2037 86 : CPLXMLNode *psTransformerTree = GDALSerializeTransformer(
2038 43 : psWO->pfnTransformer, psWO->pTransformerArg);
2039 :
2040 43 : if (psTransformerTree != nullptr)
2041 43 : CPLAddXMLChild(psTransformerContainer, psTransformerTree);
2042 : }
2043 :
2044 : /* -------------------------------------------------------------------- */
2045 : /* Band count and lists. */
2046 : /* -------------------------------------------------------------------- */
2047 43 : CPLXMLNode *psBandList = nullptr;
2048 :
2049 43 : if (psWO->nBandCount != 0)
2050 43 : psBandList = CPLCreateXMLNode(psTree, CXT_Element, "BandList");
2051 :
2052 109 : for (int i = 0; i < psWO->nBandCount; i++)
2053 : {
2054 : CPLXMLNode *psBand;
2055 :
2056 66 : psBand = CPLCreateXMLNode(psBandList, CXT_Element, "BandMapping");
2057 66 : if (psWO->panSrcBands != nullptr)
2058 66 : CPLCreateXMLNode(CPLCreateXMLNode(psBand, CXT_Attribute, "src"),
2059 : CXT_Text,
2060 132 : CPLString().Printf("%d", psWO->panSrcBands[i]));
2061 66 : if (psWO->panDstBands != nullptr)
2062 66 : CPLCreateXMLNode(CPLCreateXMLNode(psBand, CXT_Attribute, "dst"),
2063 : CXT_Text,
2064 132 : CPLString().Printf("%d", psWO->panDstBands[i]));
2065 :
2066 66 : if (psWO->padfSrcNoDataReal != nullptr)
2067 : {
2068 13 : CPLCreateXMLElementAndValue(
2069 : psBand, "SrcNoDataReal",
2070 13 : VRTSerializeNoData(psWO->padfSrcNoDataReal[i],
2071 13 : psWO->eWorkingDataType, 16)
2072 : .c_str());
2073 : }
2074 :
2075 66 : if (psWO->padfSrcNoDataImag != nullptr)
2076 : {
2077 2 : if (std::isnan(psWO->padfSrcNoDataImag[i]))
2078 0 : CPLCreateXMLElementAndValue(psBand, "SrcNoDataImag", "nan");
2079 : else
2080 2 : CPLCreateXMLElementAndValue(
2081 : psBand, "SrcNoDataImag",
2082 4 : CPLString().Printf("%.16g", psWO->padfSrcNoDataImag[i]));
2083 : }
2084 : // Compatibility with GDAL <= 2.2: if we serialize a SrcNoDataReal,
2085 : // it needs a SrcNoDataImag as well
2086 64 : else if (psWO->padfSrcNoDataReal != nullptr)
2087 : {
2088 11 : CPLCreateXMLElementAndValue(psBand, "SrcNoDataImag", "0");
2089 : }
2090 :
2091 66 : if (psWO->padfDstNoDataReal != nullptr)
2092 : {
2093 13 : CPLCreateXMLElementAndValue(
2094 : psBand, "DstNoDataReal",
2095 13 : VRTSerializeNoData(psWO->padfDstNoDataReal[i],
2096 13 : psWO->eWorkingDataType, 16)
2097 : .c_str());
2098 : }
2099 :
2100 66 : if (psWO->padfDstNoDataImag != nullptr)
2101 : {
2102 2 : if (std::isnan(psWO->padfDstNoDataImag[i]))
2103 0 : CPLCreateXMLElementAndValue(psBand, "DstNoDataImag", "nan");
2104 : else
2105 2 : CPLCreateXMLElementAndValue(
2106 : psBand, "DstNoDataImag",
2107 4 : CPLString().Printf("%.16g", psWO->padfDstNoDataImag[i]));
2108 : }
2109 : // Compatibility with GDAL <= 2.2: if we serialize a DstNoDataReal,
2110 : // it needs a SrcNoDataImag as well
2111 64 : else if (psWO->padfDstNoDataReal != nullptr)
2112 : {
2113 11 : CPLCreateXMLElementAndValue(psBand, "DstNoDataImag", "0");
2114 : }
2115 : }
2116 :
2117 : /* -------------------------------------------------------------------- */
2118 : /* Alpha bands. */
2119 : /* -------------------------------------------------------------------- */
2120 43 : if (psWO->nSrcAlphaBand > 0)
2121 0 : CPLCreateXMLElementAndValue(
2122 : psTree, "SrcAlphaBand",
2123 0 : CPLString().Printf("%d", psWO->nSrcAlphaBand));
2124 :
2125 43 : if (psWO->nDstAlphaBand > 0)
2126 6 : CPLCreateXMLElementAndValue(
2127 : psTree, "DstAlphaBand",
2128 12 : CPLString().Printf("%d", psWO->nDstAlphaBand));
2129 :
2130 : /* -------------------------------------------------------------------- */
2131 : /* Cutline. */
2132 : /* -------------------------------------------------------------------- */
2133 43 : if (psWO->hCutline != nullptr)
2134 : {
2135 0 : char *pszWKT = nullptr;
2136 0 : if (OGR_G_ExportToWkt(static_cast<OGRGeometryH>(psWO->hCutline),
2137 0 : &pszWKT) == OGRERR_NONE)
2138 : {
2139 0 : CPLCreateXMLElementAndValue(psTree, "Cutline", pszWKT);
2140 : }
2141 0 : CPLFree(pszWKT);
2142 : }
2143 :
2144 43 : if (psWO->dfCutlineBlendDist != 0.0)
2145 0 : CPLCreateXMLElementAndValue(
2146 : psTree, "CutlineBlendDist",
2147 0 : CPLString().Printf("%.5g", psWO->dfCutlineBlendDist));
2148 :
2149 43 : return psTree;
2150 : }
2151 :
2152 : /************************************************************************/
2153 : /* GDALDeserializeWarpOptions() */
2154 : /************************************************************************/
2155 :
2156 148 : GDALWarpOptions *CPL_STDCALL GDALDeserializeWarpOptions(CPLXMLNode *psTree)
2157 :
2158 : {
2159 148 : CPLErrorReset();
2160 :
2161 : /* -------------------------------------------------------------------- */
2162 : /* Verify this is the right kind of object. */
2163 : /* -------------------------------------------------------------------- */
2164 148 : if (psTree == nullptr || psTree->eType != CXT_Element ||
2165 148 : !EQUAL(psTree->pszValue, "GDALWarpOptions"))
2166 : {
2167 0 : CPLError(CE_Failure, CPLE_AppDefined,
2168 : "Wrong node, unable to deserialize GDALWarpOptions.");
2169 0 : return nullptr;
2170 : }
2171 :
2172 : /* -------------------------------------------------------------------- */
2173 : /* Create pre-initialized warp options. */
2174 : /* -------------------------------------------------------------------- */
2175 148 : GDALWarpOptions *psWO = GDALCreateWarpOptions();
2176 :
2177 : /* -------------------------------------------------------------------- */
2178 : /* Warp memory limit. */
2179 : /* -------------------------------------------------------------------- */
2180 148 : psWO->dfWarpMemoryLimit =
2181 148 : CPLAtof(CPLGetXMLValue(psTree, "WarpMemoryLimit", "0.0"));
2182 :
2183 : /* -------------------------------------------------------------------- */
2184 : /* resample algorithm */
2185 : /* -------------------------------------------------------------------- */
2186 148 : const char *pszValue = CPLGetXMLValue(psTree, "ResampleAlg", "Default");
2187 :
2188 148 : if (EQUAL(pszValue, "NearestNeighbour"))
2189 90 : psWO->eResampleAlg = GRA_NearestNeighbour;
2190 58 : else if (EQUAL(pszValue, "Bilinear"))
2191 8 : psWO->eResampleAlg = GRA_Bilinear;
2192 50 : else if (EQUAL(pszValue, "Cubic"))
2193 9 : psWO->eResampleAlg = GRA_Cubic;
2194 41 : else if (EQUAL(pszValue, "CubicSpline"))
2195 9 : psWO->eResampleAlg = GRA_CubicSpline;
2196 32 : else if (EQUAL(pszValue, "Lanczos"))
2197 4 : psWO->eResampleAlg = GRA_Lanczos;
2198 28 : else if (EQUAL(pszValue, "Average"))
2199 6 : psWO->eResampleAlg = GRA_Average;
2200 22 : else if (EQUAL(pszValue, "RootMeanSquare"))
2201 5 : psWO->eResampleAlg = GRA_RMS;
2202 17 : else if (EQUAL(pszValue, "Mode"))
2203 4 : psWO->eResampleAlg = GRA_Mode;
2204 13 : else if (EQUAL(pszValue, "Maximum"))
2205 3 : psWO->eResampleAlg = GRA_Max;
2206 10 : else if (EQUAL(pszValue, "Minimum"))
2207 2 : psWO->eResampleAlg = GRA_Min;
2208 8 : else if (EQUAL(pszValue, "Median"))
2209 3 : psWO->eResampleAlg = GRA_Med;
2210 5 : else if (EQUAL(pszValue, "Quartile1"))
2211 2 : psWO->eResampleAlg = GRA_Q1;
2212 3 : else if (EQUAL(pszValue, "Quartile3"))
2213 2 : psWO->eResampleAlg = GRA_Q3;
2214 1 : else if (EQUAL(pszValue, "Sum"))
2215 1 : psWO->eResampleAlg = GRA_Sum;
2216 0 : else if (EQUAL(pszValue, "Default"))
2217 : /* leave as is */;
2218 : else
2219 : {
2220 0 : CPLError(CE_Failure, CPLE_AppDefined,
2221 : "Unrecognised ResampleAlg value '%s'.", pszValue);
2222 : }
2223 :
2224 : /* -------------------------------------------------------------------- */
2225 : /* Working data type. */
2226 : /* -------------------------------------------------------------------- */
2227 148 : psWO->eWorkingDataType = GDALGetDataTypeByName(
2228 : CPLGetXMLValue(psTree, "WorkingDataType", "Unknown"));
2229 :
2230 : /* -------------------------------------------------------------------- */
2231 : /* Name/value warp options. */
2232 : /* -------------------------------------------------------------------- */
2233 1334 : for (CPLXMLNode *psItem = psTree->psChild; psItem != nullptr;
2234 1186 : psItem = psItem->psNext)
2235 : {
2236 1186 : if (psItem->eType == CXT_Element && EQUAL(psItem->pszValue, "Option"))
2237 : {
2238 230 : const char *pszName = CPLGetXMLValue(psItem, "Name", nullptr);
2239 230 : pszValue = CPLGetXMLValue(psItem, "", nullptr);
2240 :
2241 230 : if (pszName != nullptr && pszValue != nullptr)
2242 : {
2243 230 : psWO->papszWarpOptions =
2244 230 : CSLSetNameValue(psWO->papszWarpOptions, pszName, pszValue);
2245 : }
2246 : }
2247 : }
2248 :
2249 : /* -------------------------------------------------------------------- */
2250 : /* Source Dataset. */
2251 : /* -------------------------------------------------------------------- */
2252 148 : pszValue = CPLGetXMLValue(psTree, "SourceDataset", nullptr);
2253 :
2254 148 : if (pszValue != nullptr)
2255 : {
2256 : CPLXMLNode *psGeoLocNode =
2257 148 : CPLSearchXMLNode(psTree, "GeoLocTransformer");
2258 148 : if (psGeoLocNode)
2259 : {
2260 1 : CPLCreateXMLElementAndValue(psGeoLocNode, "SourceDataset",
2261 : pszValue);
2262 : }
2263 :
2264 296 : CPLConfigOptionSetter oSetter("CPL_ALLOW_VSISTDIN", "NO", true);
2265 :
2266 148 : char **papszOpenOptions = GDALDeserializeOpenOptionsFromXML(psTree);
2267 148 : psWO->hSrcDS =
2268 148 : GDALOpenEx(pszValue, GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
2269 : nullptr, papszOpenOptions, nullptr);
2270 148 : CSLDestroy(papszOpenOptions);
2271 : }
2272 :
2273 : /* -------------------------------------------------------------------- */
2274 : /* Destination Dataset. */
2275 : /* -------------------------------------------------------------------- */
2276 148 : pszValue = CPLGetXMLValue(psTree, "DestinationDataset", nullptr);
2277 :
2278 148 : if (pszValue != nullptr)
2279 : {
2280 0 : psWO->hDstDS = GDALOpenShared(pszValue, GA_Update);
2281 : }
2282 :
2283 : /* -------------------------------------------------------------------- */
2284 : /* First, count band mappings so we can establish the bandcount. */
2285 : /* -------------------------------------------------------------------- */
2286 148 : CPLXMLNode *psBandTree = CPLGetXMLNode(psTree, "BandList");
2287 :
2288 148 : int nBandCount = 0;
2289 148 : CPLXMLNode *psBand = psBandTree ? psBandTree->psChild : nullptr;
2290 371 : for (; psBand != nullptr; psBand = psBand->psNext)
2291 : {
2292 223 : if (psBand->eType != CXT_Element ||
2293 223 : !EQUAL(psBand->pszValue, "BandMapping"))
2294 0 : continue;
2295 :
2296 223 : nBandCount++;
2297 : }
2298 :
2299 148 : GDALWarpInitDefaultBandMapping(psWO, nBandCount);
2300 :
2301 : /* ==================================================================== */
2302 : /* Now actually process each bandmapping. */
2303 : /* ==================================================================== */
2304 148 : int iBand = 0;
2305 :
2306 148 : psBand = psBandTree ? psBandTree->psChild : nullptr;
2307 :
2308 371 : for (; psBand != nullptr; psBand = psBand->psNext)
2309 : {
2310 223 : if (psBand->eType != CXT_Element ||
2311 223 : !EQUAL(psBand->pszValue, "BandMapping"))
2312 0 : continue;
2313 :
2314 : /* --------------------------------------------------------------------
2315 : */
2316 : /* Source band */
2317 : /* --------------------------------------------------------------------
2318 : */
2319 223 : pszValue = CPLGetXMLValue(psBand, "src", nullptr);
2320 223 : if (pszValue != nullptr)
2321 223 : psWO->panSrcBands[iBand] = atoi(pszValue);
2322 :
2323 : /* --------------------------------------------------------------------
2324 : */
2325 : /* Destination band. */
2326 : /* --------------------------------------------------------------------
2327 : */
2328 223 : pszValue = CPLGetXMLValue(psBand, "dst", nullptr);
2329 223 : if (pszValue != nullptr)
2330 223 : psWO->panDstBands[iBand] = atoi(pszValue);
2331 :
2332 66 : const auto NormalizeValue = [](const char *pszValueIn,
2333 : GDALDataType eDataType) -> double
2334 : {
2335 78 : if (eDataType == GDT_Float32 &&
2336 78 : CPLString().Printf("%.16g",
2337 : static_cast<double>(
2338 12 : std::numeric_limits<float>::lowest())) ==
2339 : pszValueIn)
2340 : {
2341 : return static_cast<double>(
2342 0 : std::numeric_limits<float>::lowest());
2343 : }
2344 78 : else if (eDataType == GDT_Float32 &&
2345 78 : CPLString().Printf(
2346 : "%.16g", static_cast<double>(
2347 12 : std::numeric_limits<float>::max())) ==
2348 : pszValueIn)
2349 : {
2350 0 : return static_cast<double>(std::numeric_limits<float>::max());
2351 : }
2352 : else
2353 : {
2354 66 : return CPLAtof(pszValueIn);
2355 : }
2356 : };
2357 :
2358 : /* --------------------------------------------------------------------
2359 : */
2360 : /* Source nodata. */
2361 : /* --------------------------------------------------------------------
2362 : */
2363 223 : pszValue = CPLGetXMLValue(psBand, "SrcNoDataReal", nullptr);
2364 223 : if (pszValue != nullptr)
2365 : {
2366 31 : GDALWarpInitSrcNoDataReal(psWO, -1.1e20);
2367 62 : psWO->padfSrcNoDataReal[iBand] =
2368 31 : NormalizeValue(pszValue, psWO->eWorkingDataType);
2369 : }
2370 :
2371 223 : pszValue = CPLGetXMLValue(psBand, "SrcNoDataImag", nullptr);
2372 223 : if (pszValue != nullptr)
2373 : {
2374 31 : GDALWarpInitSrcNoDataImag(psWO, 0);
2375 31 : psWO->padfSrcNoDataImag[iBand] = CPLAtof(pszValue);
2376 : }
2377 :
2378 : /* --------------------------------------------------------------------
2379 : */
2380 : /* Destination nodata. */
2381 : /* --------------------------------------------------------------------
2382 : */
2383 223 : pszValue = CPLGetXMLValue(psBand, "DstNoDataReal", nullptr);
2384 223 : if (pszValue != nullptr)
2385 : {
2386 35 : GDALWarpInitDstNoDataReal(psWO, -1.1e20);
2387 70 : psWO->padfDstNoDataReal[iBand] =
2388 35 : NormalizeValue(pszValue, psWO->eWorkingDataType);
2389 : }
2390 :
2391 223 : pszValue = CPLGetXMLValue(psBand, "DstNoDataImag", nullptr);
2392 223 : if (pszValue != nullptr)
2393 : {
2394 35 : GDALWarpInitDstNoDataImag(psWO, 0);
2395 35 : psWO->padfDstNoDataImag[iBand] = CPLAtof(pszValue);
2396 : }
2397 :
2398 223 : iBand++;
2399 : }
2400 :
2401 : /* -------------------------------------------------------------------- */
2402 : /* Alpha bands. */
2403 : /* -------------------------------------------------------------------- */
2404 148 : psWO->nSrcAlphaBand = atoi(CPLGetXMLValue(psTree, "SrcAlphaBand", "0"));
2405 148 : psWO->nDstAlphaBand = atoi(CPLGetXMLValue(psTree, "DstAlphaBand", "0"));
2406 :
2407 : /* -------------------------------------------------------------------- */
2408 : /* Cutline. */
2409 : /* -------------------------------------------------------------------- */
2410 148 : const char *pszWKT = CPLGetXMLValue(psTree, "Cutline", nullptr);
2411 148 : if (pszWKT)
2412 : {
2413 7 : char *pszWKTTemp = const_cast<char *>(pszWKT);
2414 7 : OGRGeometryH hCutline = nullptr;
2415 7 : OGR_G_CreateFromWkt(&pszWKTTemp, nullptr, &hCutline);
2416 7 : psWO->hCutline = hCutline;
2417 : }
2418 :
2419 148 : psWO->dfCutlineBlendDist =
2420 148 : CPLAtof(CPLGetXMLValue(psTree, "CutlineBlendDist", "0"));
2421 :
2422 : /* -------------------------------------------------------------------- */
2423 : /* Transformation. */
2424 : /* -------------------------------------------------------------------- */
2425 148 : CPLXMLNode *psTransformer = CPLGetXMLNode(psTree, "Transformer");
2426 :
2427 148 : if (psTransformer != nullptr && psTransformer->psChild != nullptr)
2428 : {
2429 148 : GDALDeserializeTransformer(psTransformer->psChild,
2430 : &(psWO->pfnTransformer),
2431 : &(psWO->pTransformerArg));
2432 : }
2433 :
2434 : /* -------------------------------------------------------------------- */
2435 : /* If any error has occurred, cleanup else return success. */
2436 : /* -------------------------------------------------------------------- */
2437 148 : if (CPLGetLastErrorType() != CE_None)
2438 : {
2439 0 : if (psWO->pTransformerArg)
2440 : {
2441 0 : GDALDestroyTransformer(psWO->pTransformerArg);
2442 0 : psWO->pTransformerArg = nullptr;
2443 : }
2444 0 : if (psWO->hSrcDS != nullptr)
2445 : {
2446 0 : GDALClose(psWO->hSrcDS);
2447 0 : psWO->hSrcDS = nullptr;
2448 : }
2449 0 : if (psWO->hDstDS != nullptr)
2450 : {
2451 0 : GDALClose(psWO->hDstDS);
2452 0 : psWO->hDstDS = nullptr;
2453 : }
2454 0 : GDALDestroyWarpOptions(psWO);
2455 0 : return nullptr;
2456 : }
2457 :
2458 148 : return psWO;
2459 : }
2460 :
2461 : /************************************************************************/
2462 : /* GDALGetWarpResampleAlg() */
2463 : /************************************************************************/
2464 :
2465 : /** Return a GDALResampleAlg from a string */
2466 865 : bool GDALGetWarpResampleAlg(const char *pszResampling,
2467 : GDALResampleAlg &eResampleAlg, bool bThrow)
2468 : {
2469 865 : if (STARTS_WITH_CI(pszResampling, "near"))
2470 177 : eResampleAlg = GRA_NearestNeighbour;
2471 688 : else if (EQUAL(pszResampling, "bilinear"))
2472 149 : eResampleAlg = GRA_Bilinear;
2473 539 : else if (EQUAL(pszResampling, "cubic"))
2474 255 : eResampleAlg = GRA_Cubic;
2475 284 : else if (EQUAL(pszResampling, "cubicspline"))
2476 54 : eResampleAlg = GRA_CubicSpline;
2477 230 : else if (EQUAL(pszResampling, "lanczos"))
2478 52 : eResampleAlg = GRA_Lanczos;
2479 178 : else if (EQUAL(pszResampling, "average"))
2480 92 : eResampleAlg = GRA_Average;
2481 86 : else if (EQUAL(pszResampling, "rms"))
2482 3 : eResampleAlg = GRA_RMS;
2483 83 : else if (EQUAL(pszResampling, "mode"))
2484 42 : eResampleAlg = GRA_Mode;
2485 41 : else if (EQUAL(pszResampling, "max"))
2486 3 : eResampleAlg = GRA_Max;
2487 38 : else if (EQUAL(pszResampling, "min"))
2488 3 : eResampleAlg = GRA_Min;
2489 35 : else if (EQUAL(pszResampling, "med"))
2490 3 : eResampleAlg = GRA_Med;
2491 32 : else if (EQUAL(pszResampling, "q1"))
2492 8 : eResampleAlg = GRA_Q1;
2493 24 : else if (EQUAL(pszResampling, "q3"))
2494 3 : eResampleAlg = GRA_Q3;
2495 21 : else if (EQUAL(pszResampling, "sum"))
2496 20 : eResampleAlg = GRA_Sum;
2497 : else
2498 : {
2499 1 : if (bThrow)
2500 : {
2501 1 : throw std::invalid_argument("Unknown resampling method");
2502 : }
2503 : else
2504 : {
2505 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2506 : "Unknown resampling method: %s.", pszResampling);
2507 0 : return false;
2508 : }
2509 : }
2510 864 : return true;
2511 : }
|