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