Coverage Report

Created: 2026-04-01 06:20

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