Coverage Report

Created: 2026-07-25 06:50

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