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