1 : /******************************************************************************
2 : * $Id: gdalwarper.cpp 22888 2011-08-07 13:06:36Z rouault $
3 : *
4 : * Project: High Performance Image Reprojector
5 : * Purpose: Implementation of high level convenience APIs for warper.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.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 "gdalwarper.h"
31 : #include "cpl_string.h"
32 : #include "cpl_minixml.h"
33 : #include "ogr_api.h"
34 : #include "gdal_priv.h"
35 :
36 : CPL_CVSID("$Id: gdalwarper.cpp 22888 2011-08-07 13:06:36Z rouault $");
37 :
38 : /************************************************************************/
39 : /* GDALReprojectImage() */
40 : /************************************************************************/
41 :
42 : /**
43 : * Reproject image.
44 : *
45 : * This is a convenience function utilizing the GDALWarpOperation class to
46 : * reproject an image from a source to a destination. In particular, this
47 : * function takes care of establishing the transformation function to
48 : * implement the reprojection, and will default a variety of other
49 : * warp options.
50 : *
51 : * No metadata, projection info, or color tables are transferred
52 : * to the output file.
53 : *
54 : * @param hSrcDS the source image file.
55 : * @param pszSrcWKT the source projection. If NULL the source projection
56 : * is read from from hSrcDS.
57 : * @param hDstDS the destination image file.
58 : * @param pszDstWKT the destination projection. If NULL the destination
59 : * projection will be read from hDstDS.
60 : * @param eResampleAlg the type of resampling to use.
61 : * @param dfWarpMemoryLimit the amount of memory (in bytes) that the warp
62 : * API is allowed to use for caching. This is in addition to the memory
63 : * already allocated to the GDAL caching (as per GDALSetCacheMax()). May be
64 : * 0.0 to use default memory settings.
65 : * @param dfMaxError maximum error measured in input pixels that is allowed
66 : * in approximating the transformation (0.0 for exact calculations).
67 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
68 : * reporting progress or NULL.
69 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
70 : * @param psOptions warp options, normally NULL.
71 : *
72 : * @return CE_None on success or CE_Failure if something goes wrong.
73 : */
74 :
75 : CPLErr CPL_STDCALL
76 50 : GDALReprojectImage( GDALDatasetH hSrcDS, const char *pszSrcWKT,
77 : GDALDatasetH hDstDS, const char *pszDstWKT,
78 : GDALResampleAlg eResampleAlg,
79 : double dfWarpMemoryLimit,
80 : double dfMaxError,
81 : GDALProgressFunc pfnProgress, void *pProgressArg,
82 : GDALWarpOptions *psOptions )
83 :
84 : {
85 : GDALWarpOptions *psWOptions;
86 :
87 : /* -------------------------------------------------------------------- */
88 : /* Setup a reprojection based transformer. */
89 : /* -------------------------------------------------------------------- */
90 : void *hTransformArg;
91 :
92 : hTransformArg =
93 : GDALCreateGenImgProjTransformer( hSrcDS, pszSrcWKT, hDstDS, pszDstWKT,
94 50 : TRUE, 1000.0, 0 );
95 :
96 50 : if( hTransformArg == NULL )
97 0 : return CE_Failure;
98 :
99 : /* -------------------------------------------------------------------- */
100 : /* Create a copy of the user provided options, or a defaulted */
101 : /* options structure. */
102 : /* -------------------------------------------------------------------- */
103 50 : if( psOptions == NULL )
104 50 : psWOptions = GDALCreateWarpOptions();
105 : else
106 0 : psWOptions = GDALCloneWarpOptions( psOptions );
107 :
108 50 : psWOptions->eResampleAlg = eResampleAlg;
109 :
110 : /* -------------------------------------------------------------------- */
111 : /* Set transform. */
112 : /* -------------------------------------------------------------------- */
113 50 : if( dfMaxError > 0.0 )
114 : {
115 : psWOptions->pTransformerArg =
116 : GDALCreateApproxTransformer( GDALGenImgProjTransform,
117 2 : hTransformArg, dfMaxError );
118 :
119 2 : psWOptions->pfnTransformer = GDALApproxTransform;
120 : }
121 : else
122 : {
123 48 : psWOptions->pfnTransformer = GDALGenImgProjTransform;
124 48 : psWOptions->pTransformerArg = hTransformArg;
125 : }
126 :
127 : /* -------------------------------------------------------------------- */
128 : /* Set file and band mapping. */
129 : /* -------------------------------------------------------------------- */
130 : int iBand;
131 :
132 50 : psWOptions->hSrcDS = hSrcDS;
133 50 : psWOptions->hDstDS = hDstDS;
134 :
135 50 : if( psWOptions->nBandCount == 0 )
136 : {
137 : psWOptions->nBandCount = MIN(GDALGetRasterCount(hSrcDS),
138 50 : GDALGetRasterCount(hDstDS));
139 :
140 : psWOptions->panSrcBands = (int *)
141 50 : CPLMalloc(sizeof(int) * psWOptions->nBandCount);
142 : psWOptions->panDstBands = (int *)
143 50 : CPLMalloc(sizeof(int) * psWOptions->nBandCount);
144 :
145 112 : for( iBand = 0; iBand < psWOptions->nBandCount; iBand++ )
146 : {
147 62 : psWOptions->panSrcBands[iBand] = iBand+1;
148 62 : psWOptions->panDstBands[iBand] = iBand+1;
149 : }
150 : }
151 :
152 : /* -------------------------------------------------------------------- */
153 : /* Set source nodata values if the source dataset seems to have */
154 : /* any. */
155 : /* -------------------------------------------------------------------- */
156 112 : for( iBand = 0; iBand < psWOptions->nBandCount; iBand++ )
157 : {
158 62 : GDALRasterBandH hBand = GDALGetRasterBand( hSrcDS, iBand+1 );
159 62 : int bGotNoData = FALSE;
160 : double dfNoDataValue;
161 :
162 62 : if (GDALGetRasterColorInterpretation(hBand) == GCI_AlphaBand)
163 : {
164 4 : psWOptions->nSrcAlphaBand = iBand + 1;
165 : }
166 :
167 62 : dfNoDataValue = GDALGetRasterNoDataValue( hBand, &bGotNoData );
168 62 : if( bGotNoData )
169 : {
170 10 : if( psWOptions->padfSrcNoDataReal == NULL )
171 : {
172 : int ii;
173 :
174 : psWOptions->padfSrcNoDataReal = (double *)
175 10 : CPLMalloc(sizeof(double) * psWOptions->nBandCount);
176 : psWOptions->padfSrcNoDataImag = (double *)
177 10 : CPLMalloc(sizeof(double) * psWOptions->nBandCount);
178 :
179 20 : for( ii = 0; ii < psWOptions->nBandCount; ii++ )
180 : {
181 10 : psWOptions->padfSrcNoDataReal[ii] = -1.1e20;
182 10 : psWOptions->padfSrcNoDataImag[ii] = 0.0;
183 : }
184 : }
185 :
186 10 : psWOptions->padfSrcNoDataReal[iBand] = dfNoDataValue;
187 : }
188 :
189 62 : hBand = GDALGetRasterBand( hDstDS, iBand+1 );
190 62 : if (hBand && GDALGetRasterColorInterpretation(hBand) == GCI_AlphaBand)
191 : {
192 4 : psWOptions->nDstAlphaBand = iBand + 1;
193 : }
194 : }
195 :
196 : /* -------------------------------------------------------------------- */
197 : /* Set the progress function. */
198 : /* -------------------------------------------------------------------- */
199 50 : if( pfnProgress != NULL )
200 : {
201 2 : psWOptions->pfnProgress = pfnProgress;
202 2 : psWOptions->pProgressArg = pProgressArg;
203 : }
204 :
205 : /* -------------------------------------------------------------------- */
206 : /* Create a warp options based on the options. */
207 : /* -------------------------------------------------------------------- */
208 50 : GDALWarpOperation oWarper;
209 : CPLErr eErr;
210 :
211 50 : eErr = oWarper.Initialize( psWOptions );
212 :
213 50 : if( eErr == CE_None )
214 : eErr = oWarper.ChunkAndWarpImage( 0, 0,
215 : GDALGetRasterXSize(hDstDS),
216 50 : GDALGetRasterYSize(hDstDS) );
217 :
218 : /* -------------------------------------------------------------------- */
219 : /* Cleanup. */
220 : /* -------------------------------------------------------------------- */
221 50 : GDALDestroyGenImgProjTransformer( hTransformArg );
222 :
223 50 : if( dfMaxError > 0.0 )
224 2 : GDALDestroyApproxTransformer( psWOptions->pTransformerArg );
225 :
226 50 : GDALDestroyWarpOptions( psWOptions );
227 :
228 50 : return eErr;
229 : }
230 :
231 : /************************************************************************/
232 : /* GDALCreateAndReprojectImage() */
233 : /* */
234 : /* This is a "quicky" reprojection API. */
235 : /************************************************************************/
236 :
237 0 : CPLErr CPL_STDCALL GDALCreateAndReprojectImage(
238 : GDALDatasetH hSrcDS, const char *pszSrcWKT,
239 : const char *pszDstFilename, const char *pszDstWKT,
240 : GDALDriverH hDstDriver, char **papszCreateOptions,
241 : GDALResampleAlg eResampleAlg, double dfWarpMemoryLimit, double dfMaxError,
242 : GDALProgressFunc pfnProgress, void *pProgressArg,
243 : GDALWarpOptions *psOptions )
244 :
245 : {
246 0 : VALIDATE_POINTER1( hSrcDS, "GDALCreateAndReprojectImage", CE_Failure );
247 :
248 : /* -------------------------------------------------------------------- */
249 : /* Default a few parameters. */
250 : /* -------------------------------------------------------------------- */
251 0 : if( hDstDriver == NULL )
252 : {
253 0 : hDstDriver = GDALGetDriverByName( "GTiff" );
254 0 : if (hDstDriver == NULL)
255 : {
256 : CPLError(CE_Failure, CPLE_AppDefined,
257 0 : "GDALCreateAndReprojectImage needs GTiff driver");
258 0 : return CE_Failure;
259 : }
260 : }
261 :
262 0 : if( pszSrcWKT == NULL )
263 0 : pszSrcWKT = GDALGetProjectionRef( hSrcDS );
264 :
265 0 : if( pszDstWKT == NULL )
266 0 : pszDstWKT = pszSrcWKT;
267 :
268 : /* -------------------------------------------------------------------- */
269 : /* Create a transformation object from the source to */
270 : /* destination coordinate system. */
271 : /* -------------------------------------------------------------------- */
272 : void *hTransformArg;
273 :
274 : hTransformArg =
275 : GDALCreateGenImgProjTransformer( hSrcDS, pszSrcWKT, NULL, pszDstWKT,
276 0 : TRUE, 1000.0, 0 );
277 :
278 0 : if( hTransformArg == NULL )
279 0 : return CE_Failure;
280 :
281 : /* -------------------------------------------------------------------- */
282 : /* Get approximate output definition. */
283 : /* -------------------------------------------------------------------- */
284 : double adfDstGeoTransform[6];
285 : int nPixels, nLines;
286 :
287 0 : if( GDALSuggestedWarpOutput( hSrcDS,
288 : GDALGenImgProjTransform, hTransformArg,
289 : adfDstGeoTransform, &nPixels, &nLines )
290 : != CE_None )
291 0 : return CE_Failure;
292 :
293 0 : GDALDestroyGenImgProjTransformer( hTransformArg );
294 :
295 : /* -------------------------------------------------------------------- */
296 : /* Create the output file. */
297 : /* -------------------------------------------------------------------- */
298 : GDALDatasetH hDstDS;
299 :
300 : hDstDS = GDALCreate( hDstDriver, pszDstFilename, nPixels, nLines,
301 : GDALGetRasterCount(hSrcDS),
302 : GDALGetRasterDataType(GDALGetRasterBand(hSrcDS,1)),
303 0 : papszCreateOptions );
304 :
305 0 : if( hDstDS == NULL )
306 0 : return CE_Failure;
307 :
308 : /* -------------------------------------------------------------------- */
309 : /* Write out the projection definition. */
310 : /* -------------------------------------------------------------------- */
311 0 : GDALSetProjection( hDstDS, pszDstWKT );
312 0 : GDALSetGeoTransform( hDstDS, adfDstGeoTransform );
313 :
314 : /* -------------------------------------------------------------------- */
315 : /* Perform the reprojection. */
316 : /* -------------------------------------------------------------------- */
317 : CPLErr eErr ;
318 :
319 : eErr =
320 : GDALReprojectImage( hSrcDS, pszSrcWKT, hDstDS, pszDstWKT,
321 : eResampleAlg, dfWarpMemoryLimit, dfMaxError,
322 0 : pfnProgress, pProgressArg, psOptions );
323 :
324 0 : GDALClose( hDstDS );
325 :
326 0 : return eErr;
327 : }
328 :
329 : /************************************************************************/
330 : /* GDALWarpNoDataMasker() */
331 : /* */
332 : /* GDALMaskFunc for establishing a validity mask for a source */
333 : /* band based on a provided NODATA value. */
334 : /************************************************************************/
335 :
336 : CPLErr
337 60 : GDALWarpNoDataMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
338 : int /* nXOff */, int /* nYOff */, int nXSize, int nYSize,
339 : GByte **ppImageData,
340 : int bMaskIsFloat, void *pValidityMask )
341 :
342 : {
343 60 : double *padfNoData = (double *) pMaskFuncArg;
344 60 : GUInt32 *panValidityMask = (GUInt32 *) pValidityMask;
345 :
346 60 : if( nBandCount != 1 || bMaskIsFloat )
347 : {
348 : CPLError( CE_Failure, CPLE_AppDefined,
349 0 : "Invalid nBandCount or bMaskIsFloat argument in SourceNoDataMask" );
350 0 : return CE_Failure;
351 : }
352 :
353 60 : switch( eType )
354 : {
355 : case GDT_Byte:
356 : {
357 18 : int nNoData = (int) padfNoData[0];
358 18 : GByte *pabyData = (GByte *) *ppImageData;
359 : int iOffset;
360 :
361 : // nothing to do if value is out of range.
362 36 : if( padfNoData[0] < 0.0 || padfNoData[0] > 255.000001
363 18 : || padfNoData[1] != 0.0 )
364 0 : return CE_None;
365 :
366 162772 : for( iOffset = nXSize*nYSize-1; iOffset >= 0; iOffset-- )
367 : {
368 162754 : if( pabyData[iOffset] == nNoData )
369 : {
370 136044 : panValidityMask[iOffset>>5] &= ~(0x01 << (iOffset & 0x1f));
371 : }
372 : }
373 : }
374 18 : break;
375 :
376 : case GDT_Int16:
377 : {
378 10 : int nNoData = (int) padfNoData[0];
379 10 : GInt16 *panData = (GInt16 *) *ppImageData;
380 : int iOffset;
381 :
382 : // nothing to do if value is out of range.
383 20 : if( padfNoData[0] < -32768 || padfNoData[0] > 32767
384 10 : || padfNoData[1] != 0.0 )
385 0 : return CE_None;
386 :
387 91658 : for( iOffset = nXSize*nYSize-1; iOffset >= 0; iOffset-- )
388 : {
389 91648 : if( panData[iOffset] == nNoData )
390 : {
391 1430 : panValidityMask[iOffset>>5] &= ~(0x01 << (iOffset & 0x1f));
392 : }
393 : }
394 : }
395 10 : break;
396 :
397 : case GDT_UInt16:
398 : {
399 0 : int nNoData = (int) padfNoData[0];
400 0 : GUInt16 *panData = (GUInt16 *) *ppImageData;
401 : int iOffset;
402 :
403 : // nothing to do if value is out of range.
404 0 : if( padfNoData[0] < 0 || padfNoData[0] > 65535
405 0 : || padfNoData[1] != 0.0 )
406 0 : return CE_None;
407 :
408 0 : for( iOffset = nXSize*nYSize-1; iOffset >= 0; iOffset-- )
409 : {
410 0 : if( panData[iOffset] == nNoData )
411 : {
412 0 : panValidityMask[iOffset>>5] &= ~(0x01 << (iOffset & 0x1f));
413 : }
414 : }
415 : }
416 0 : break;
417 :
418 : case GDT_Float32:
419 : {
420 16 : float fNoData = (float) padfNoData[0];
421 16 : float *pafData = (float *) *ppImageData;
422 : int iOffset;
423 16 : int bIsNoDataNan = CPLIsNan(fNoData);
424 :
425 : // nothing to do if value is out of range.
426 16 : if( padfNoData[1] != 0.0 )
427 0 : return CE_None;
428 :
429 525104 : for( iOffset = nXSize*nYSize-1; iOffset >= 0; iOffset-- )
430 : {
431 525088 : float fVal = pafData[iOffset];
432 525088 : if( (bIsNoDataNan && CPLIsNan(fVal)) || (!bIsNoDataNan && ARE_REAL_EQUAL(fVal, fNoData)) )
433 : {
434 524368 : panValidityMask[iOffset>>5] &= ~(0x01 << (iOffset & 0x1f));
435 : }
436 : }
437 : }
438 16 : break;
439 :
440 : case GDT_Float64:
441 : {
442 0 : double dfNoData = padfNoData[0];
443 0 : double *padfData = (double *) *ppImageData;
444 : int iOffset;
445 0 : int bIsNoDataNan = CPLIsNan(dfNoData);
446 :
447 : // nothing to do if value is out of range.
448 0 : if( padfNoData[1] != 0.0 )
449 0 : return CE_None;
450 :
451 0 : for( iOffset = nXSize*nYSize-1; iOffset >= 0; iOffset-- )
452 : {
453 0 : double dfVal = padfData[iOffset];
454 0 : if( (bIsNoDataNan && CPLIsNan(dfVal)) || (!bIsNoDataNan && ARE_REAL_EQUAL(dfVal, dfNoData)) )
455 : {
456 0 : panValidityMask[iOffset>>5] &= ~(0x01 << (iOffset & 0x1f));
457 : }
458 : }
459 : }
460 0 : break;
461 :
462 : default:
463 : {
464 : double *padfWrk;
465 : int iLine, iPixel;
466 16 : int nWordSize = GDALGetDataTypeSize(eType)/8;
467 :
468 16 : int bIsNoDataRealNan = CPLIsNan(padfNoData[0]);
469 16 : int bIsNoDataImagNan = CPLIsNan(padfNoData[1]);
470 :
471 16 : padfWrk = (double *) CPLMalloc(nXSize * sizeof(double) * 2);
472 176 : for( iLine = 0; iLine < nYSize; iLine++ )
473 : {
474 : GDALCopyWords( ((GByte *) *ppImageData)+nWordSize*iLine*nXSize,
475 : eType, nWordSize,
476 160 : padfWrk, GDT_CFloat64, 16, nXSize );
477 :
478 1760 : for( iPixel = 0; iPixel < nXSize; iPixel++ )
479 : {
480 8000 : if( ((bIsNoDataRealNan && CPLIsNan(padfWrk[iPixel*2])) ||
481 6400 : (!bIsNoDataRealNan && ARE_REAL_EQUAL(padfWrk[iPixel*2], padfNoData[0])))
482 : && ((bIsNoDataImagNan && CPLIsNan(padfWrk[iPixel*2+1])) ||
483 0 : (!bIsNoDataImagNan && ARE_REAL_EQUAL(padfWrk[iPixel*2+1], padfNoData[1]))) )
484 : {
485 0 : int iOffset = iPixel + iLine * nXSize;
486 :
487 : panValidityMask[iOffset>>5] &=
488 0 : ~(0x01 << (iOffset & 0x1f));
489 : }
490 : }
491 :
492 : }
493 :
494 16 : CPLFree( padfWrk );
495 : }
496 : break;
497 : }
498 :
499 60 : return CE_None;
500 : }
501 :
502 : /************************************************************************/
503 : /* GDALWarpSrcAlphaMasker() */
504 : /* */
505 : /* GDALMaskFunc for reading source simple 8bit alpha mask */
506 : /* information and building a floating point density mask from */
507 : /* it. */
508 : /************************************************************************/
509 :
510 : CPLErr
511 18 : GDALWarpSrcAlphaMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
512 : int nXOff, int nYOff, int nXSize, int nYSize,
513 : GByte ** /*ppImageData */,
514 : int bMaskIsFloat, void *pValidityMask )
515 :
516 : {
517 18 : GDALWarpOptions *psWO = (GDALWarpOptions *) pMaskFuncArg;
518 18 : float *pafMask = (float *) pValidityMask;
519 :
520 : /* -------------------------------------------------------------------- */
521 : /* Do some minimal checking. */
522 : /* -------------------------------------------------------------------- */
523 18 : if( !bMaskIsFloat )
524 : {
525 0 : CPLAssert( FALSE );
526 0 : return CE_Failure;
527 : }
528 :
529 18 : if( psWO == NULL || psWO->nSrcAlphaBand < 1 )
530 : {
531 0 : CPLAssert( FALSE );
532 0 : return CE_Failure;
533 : }
534 :
535 : /* -------------------------------------------------------------------- */
536 : /* Read the alpha band. */
537 : /* -------------------------------------------------------------------- */
538 : CPLErr eErr;
539 : GDALRasterBandH hAlphaBand = GDALGetRasterBand( psWO->hSrcDS,
540 18 : psWO->nSrcAlphaBand );
541 18 : if (hAlphaBand == NULL)
542 0 : return CE_Failure;
543 :
544 : eErr = GDALRasterIO( hAlphaBand, GF_Read, nXOff, nYOff, nXSize, nYSize,
545 18 : pafMask, nXSize, nYSize, GDT_Float32, 0, 0 );
546 :
547 18 : if( eErr != CE_None )
548 0 : return eErr;
549 :
550 : /* -------------------------------------------------------------------- */
551 : /* Rescale from 0-255 to 0.0-1.0. */
552 : /* -------------------------------------------------------------------- */
553 6618 : for( int iPixel = nXSize * nYSize - 1; iPixel >= 0; iPixel-- )
554 : { // (1/255)
555 6600 : pafMask[iPixel] = (float)( pafMask[iPixel] * 0.00392157 );
556 6600 : pafMask[iPixel] = MIN( 1.0F, pafMask[iPixel] );
557 : }
558 :
559 18 : return CE_None;
560 : }
561 :
562 : /************************************************************************/
563 : /* GDALWarpSrcMaskMasker() */
564 : /* */
565 : /* GDALMaskFunc for reading source simple 8bit validity mask */
566 : /* information and building a one bit validity mask. */
567 : /************************************************************************/
568 :
569 : CPLErr
570 2 : GDALWarpSrcMaskMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
571 : int nXOff, int nYOff, int nXSize, int nYSize,
572 : GByte ** /*ppImageData */,
573 : int bMaskIsFloat, void *pValidityMask )
574 :
575 : {
576 2 : GDALWarpOptions *psWO = (GDALWarpOptions *) pMaskFuncArg;
577 2 : GUInt32 *panMask = (GUInt32 *) pValidityMask;
578 :
579 : /* -------------------------------------------------------------------- */
580 : /* Do some minimal checking. */
581 : /* -------------------------------------------------------------------- */
582 2 : if( bMaskIsFloat )
583 : {
584 0 : CPLAssert( FALSE );
585 0 : return CE_Failure;
586 : }
587 :
588 2 : if( psWO == NULL )
589 : {
590 0 : CPLAssert( FALSE );
591 0 : return CE_Failure;
592 : }
593 :
594 : /* -------------------------------------------------------------------- */
595 : /* Allocate a temporary buffer to read mask byte data into. */
596 : /* -------------------------------------------------------------------- */
597 : GByte *pabySrcMask;
598 :
599 2 : pabySrcMask = (GByte *) VSIMalloc2(nXSize,nYSize);
600 2 : if( pabySrcMask == NULL )
601 : {
602 : CPLError( CE_Failure, CPLE_OutOfMemory,
603 : "Failed to allocate pabySrcMask (%dx%d) in GDALWarpSrcMaskMasker()",
604 0 : nXSize, nYSize );
605 0 : return CE_Failure;
606 : }
607 :
608 : /* -------------------------------------------------------------------- */
609 : /* Fetch our mask band. */
610 : /* -------------------------------------------------------------------- */
611 2 : GDALRasterBandH hSrcBand, hMaskBand = NULL;
612 :
613 2 : hSrcBand = GDALGetRasterBand( psWO->hSrcDS, psWO->panSrcBands[0] );
614 2 : if( hSrcBand != NULL )
615 2 : hMaskBand = GDALGetMaskBand( hSrcBand );
616 :
617 2 : if( hMaskBand == NULL )
618 : {
619 0 : CPLAssert( FALSE );
620 0 : return CE_Failure;
621 : }
622 :
623 : /* -------------------------------------------------------------------- */
624 : /* Read the mask band. */
625 : /* -------------------------------------------------------------------- */
626 : CPLErr eErr;
627 :
628 : eErr = GDALRasterIO( hMaskBand, GF_Read, nXOff, nYOff, nXSize, nYSize,
629 2 : pabySrcMask, nXSize, nYSize, GDT_Byte, 0, 0 );
630 :
631 2 : if( eErr != CE_None )
632 : {
633 0 : CPLFree( pabySrcMask );
634 0 : return eErr;
635 : }
636 :
637 : /* -------------------------------------------------------------------- */
638 : /* Pack into 1 bit per pixel for validity. */
639 : /* -------------------------------------------------------------------- */
640 309156 : for( int iPixel = nXSize * nYSize - 1; iPixel >= 0; iPixel-- )
641 : {
642 309154 : if( pabySrcMask[iPixel] == 0 )
643 63318 : panMask[iPixel>>5] &= ~(0x01 << (iPixel & 0x1f));
644 : }
645 :
646 2 : CPLFree( pabySrcMask );
647 :
648 2 : return CE_None;
649 : }
650 :
651 : /************************************************************************/
652 : /* GDALWarpDstAlphaMasker() */
653 : /* */
654 : /* GDALMaskFunc for reading or writing the destination simple */
655 : /* 8bit alpha mask information and building a floating point */
656 : /* density mask from it. Note, writing is distinguished */
657 : /* negative bandcount. */
658 : /************************************************************************/
659 :
660 : CPLErr
661 104 : GDALWarpDstAlphaMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
662 : int nXOff, int nYOff, int nXSize, int nYSize,
663 : GByte ** /*ppImageData */,
664 : int bMaskIsFloat, void *pValidityMask )
665 :
666 : {
667 104 : GDALWarpOptions *psWO = (GDALWarpOptions *) pMaskFuncArg;
668 104 : float *pafMask = (float *) pValidityMask;
669 : int iPixel;
670 : CPLErr eErr;
671 :
672 : /* -------------------------------------------------------------------- */
673 : /* Do some minimal checking. */
674 : /* -------------------------------------------------------------------- */
675 104 : if( !bMaskIsFloat )
676 : {
677 0 : CPLAssert( FALSE );
678 0 : return CE_Failure;
679 : }
680 :
681 104 : if( psWO == NULL || psWO->nDstAlphaBand < 1 )
682 : {
683 0 : CPLAssert( FALSE );
684 0 : return CE_Failure;
685 : }
686 :
687 : GDALRasterBandH hAlphaBand =
688 104 : GDALGetRasterBand( psWO->hDstDS, psWO->nDstAlphaBand );
689 104 : if (hAlphaBand == NULL)
690 0 : return CE_Failure;
691 :
692 : /* -------------------------------------------------------------------- */
693 : /* Read alpha case. */
694 : /* -------------------------------------------------------------------- */
695 104 : if( nBandCount >= 0 )
696 : {
697 : const char *pszInitDest =
698 52 : CSLFetchNameValue( psWO->papszWarpOptions, "INIT_DEST" );
699 :
700 : // Special logic for destinations being initialized on the fly.
701 52 : if( pszInitDest != NULL )
702 : {
703 3109800 : for( iPixel = nXSize * nYSize - 1; iPixel >= 0; iPixel-- )
704 3109752 : pafMask[iPixel] = 0.0;
705 48 : return CE_None;
706 : }
707 :
708 : // Read data.
709 : eErr = GDALRasterIO( hAlphaBand, GF_Read, nXOff, nYOff, nXSize, nYSize,
710 4 : pafMask, nXSize, nYSize, GDT_Float32, 0, 0 );
711 :
712 4 : if( eErr != CE_None )
713 0 : return eErr;
714 :
715 : // rescale.
716 254 : for( iPixel = nXSize * nYSize - 1; iPixel >= 0; iPixel-- )
717 : {
718 250 : pafMask[iPixel] = (float) (pafMask[iPixel] * 0.00392157);
719 250 : pafMask[iPixel] = MIN( 1.0F, pafMask[iPixel] );
720 : }
721 :
722 4 : return CE_None;
723 : }
724 :
725 : /* -------------------------------------------------------------------- */
726 : /* Write alpha case. */
727 : /* -------------------------------------------------------------------- */
728 : else
729 : {
730 3110054 : for( iPixel = nXSize * nYSize - 1; iPixel >= 0; iPixel-- )
731 3110002 : pafMask[iPixel] = (float)(int) ( pafMask[iPixel] * 255.1 );
732 :
733 : // Write data.
734 :
735 : /* The VRT warper will pass destination sizes that may exceed */
736 : /* the size of the raster for the partial blocks at the right */
737 : /* and bottom of the band. So let's adjust the size */
738 52 : int nDstXSize = nXSize;
739 52 : if (nXOff + nXSize > GDALGetRasterBandXSize(hAlphaBand))
740 32 : nDstXSize = GDALGetRasterBandXSize(hAlphaBand) - nXOff;
741 52 : int nDstYSize = nYSize;
742 52 : if (nYOff + nYSize > GDALGetRasterBandYSize(hAlphaBand))
743 24 : nDstYSize = GDALGetRasterBandYSize(hAlphaBand) - nYOff;
744 :
745 : eErr = GDALRasterIO( hAlphaBand, GF_Write,
746 : nXOff, nYOff, nDstXSize, nDstYSize,
747 : pafMask, nDstXSize, nDstYSize, GDT_Float32,
748 52 : 0, sizeof(float) * nXSize );
749 52 : return eErr;
750 : }
751 : }
752 :
753 : /************************************************************************/
754 : /* ==================================================================== */
755 : /* GDALWarpOptions */
756 : /* ==================================================================== */
757 : /************************************************************************/
758 :
759 : /**
760 : * \var char **GDALWarpOptions::papszWarpOptions;
761 : *
762 : * A string list of additional options controlling the warp operation in
763 : * name=value format. A suitable string list can be prepared with
764 : * CSLSetNameValue().
765 : *
766 : * The following values are currently supported:
767 : *
768 : * - INIT_DEST=[value] or INIT_DEST=NO_DATA: This option forces the
769 : * destination image to be initialized to the indicated value (for all bands)
770 : * or indicates that it should be initialized to the NO_DATA value in
771 : * padfDstNoDataReal/padfDstNoDataImag. If this value isn't set the
772 : * destination image will be read and overlayed.
773 : *
774 : * - WRITE_FLUSH=YES/NO: This option forces a flush to disk of data after
775 : * each chunk is processed. In some cases this helps ensure a serial
776 : * writing of the output data otherwise a block of data may be written to disk
777 : * each time a block of data is read for the input buffer resulting in alot
778 : * of extra seeking around the disk, and reduced IO throughput. The default
779 : * at this time is NO.
780 : *
781 : * - SKIP_NOSOURCE=YES/NO: Skip all processing for chunks for which there
782 : * is no corresponding input data. This will disable initializing the
783 : * destination (INIT_DEST) and all other processing, and so should be used
784 : * careful. Mostly useful to short circuit a lot of extra work in mosaicing
785 : * situations.
786 : *
787 : * - UNIFIED_SRC_NODATA=YES/[NO]: By default nodata masking values considered
788 : * independently for each band. However, sometimes it is desired to treat all
789 : * bands as nodata if and only if, all bands match the corresponding nodata
790 : * values. To get this behavior set this option to YES.
791 : *
792 : * Normally when computing the source raster data to
793 : * load to generate a particular output area, the warper samples transforms
794 : * 21 points along each edge of the destination region back onto the source
795 : * file, and uses this to compute a bounding window on the source image that
796 : * is sufficient. Depending on the transformation in effect, the source
797 : * window may be a bit too small, or even missing large areas. Problem
798 : * situations are those where the transformation is very non-linear or
799 : * "inside out". Examples are transforming from WGS84 to Polar Steregraphic
800 : * for areas around the pole, or transformations where some of the image is
801 : * untransformable. The following options provide some additional control
802 : * to deal with errors in computing the source window:
803 : *
804 : * - SAMPLE_GRID=YES/NO: Setting this option to YES will force the sampling to
805 : * include internal points as well as edge points which can be important if
806 : * the transformation is esoteric inside out, or if large sections of the
807 : * destination image are not transformable into the source coordinate system.
808 : *
809 : * - SAMPLE_STEPS: Modifies the density of the sampling grid. The default
810 : * number of steps is 21. Increasing this can increase the computational
811 : * cost, but improves the accuracy with which the source region is computed.
812 : *
813 : * - SOURCE_EXTRA: This is a number of extra pixels added around the source
814 : * window for a given request, and by default it is 1 to take care of rounding
815 : * error. Setting this larger will incease the amount of data that needs to
816 : * be read, but can avoid missing source data.
817 : *
818 : * - CUTLINE: This may contain the WKT geometry for a cutline. It will
819 : * be converted into a geometry by GDALWarpOperation::Initialize() and assigned
820 : * to the GDALWarpOptions hCutline field. The coordinates must be expressed
821 : * in source pixel/line coordinates. Note: this is different from the assumptions
822 : * made for the -cutline option of the gdalwarp utility !
823 : *
824 : * - CUTLINE_BLEND_DIST: This may be set with a distance in pixels which
825 : * will be assigned to the dfCutlineBlendDist field in the GDALWarpOptions.
826 : *
827 : * - CUTLINE_ALL_TOUCHED: This defaults to FALSE, but may be set to TRUE
828 : * to enable ALL_TOUCHEd mode when rasterizing cutline polygons. This is
829 : * useful to ensure that that all pixels overlapping the cutline polygon
830 : * will be selected, not just those whose center point falls within the
831 : * polygon.
832 : *
833 : * - OPTIMIZE_SIZE: This defaults to FALSE, but may be set to TRUE when
834 : * outputing typically to a compressed dataset (GeoTIFF with COMPRESSED creation
835 : * option set for example) for achieving a smaller file size. This is achieved
836 : * by writing at once data aligned on full blocks of the target dataset, which
837 : * avoids partial writes of compressed blocks and lost space when they are rewritten
838 : * at the end of the file. However sticking to target block size may cause major
839 : * processing slowdown for some particular reprojections.
840 : */
841 :
842 : /************************************************************************/
843 : /* GDALCreateWarpOptions() */
844 : /************************************************************************/
845 :
846 1442 : GDALWarpOptions * CPL_STDCALL GDALCreateWarpOptions()
847 :
848 : {
849 : GDALWarpOptions *psOptions;
850 :
851 1442 : psOptions = (GDALWarpOptions *) CPLCalloc(sizeof(GDALWarpOptions),1);
852 :
853 1442 : psOptions->eResampleAlg = GRA_NearestNeighbour;
854 1442 : psOptions->pfnProgress = GDALDummyProgress;
855 1442 : psOptions->eWorkingDataType = GDT_Unknown;
856 :
857 1442 : return psOptions;
858 : }
859 :
860 : /************************************************************************/
861 : /* GDALDestroyWarpOptions() */
862 : /************************************************************************/
863 :
864 1442 : void CPL_STDCALL GDALDestroyWarpOptions( GDALWarpOptions *psOptions )
865 :
866 : {
867 1442 : VALIDATE_POINTER0( psOptions, "GDALDestroyWarpOptions" );
868 :
869 1442 : CSLDestroy( psOptions->papszWarpOptions );
870 1442 : CPLFree( psOptions->panSrcBands );
871 1442 : CPLFree( psOptions->panDstBands );
872 1442 : CPLFree( psOptions->padfSrcNoDataReal );
873 1442 : CPLFree( psOptions->padfSrcNoDataImag );
874 1442 : CPLFree( psOptions->padfDstNoDataReal );
875 1442 : CPLFree( psOptions->padfDstNoDataImag );
876 1442 : CPLFree( psOptions->papfnSrcPerBandValidityMaskFunc );
877 1442 : CPLFree( psOptions->papSrcPerBandValidityMaskFuncArg );
878 :
879 1442 : if( psOptions->hCutline != NULL )
880 18 : OGR_G_DestroyGeometry( (OGRGeometryH) psOptions->hCutline );
881 :
882 1442 : CPLFree( psOptions );
883 : }
884 :
885 :
886 : #define COPY_MEM(target,type,count) \
887 : do { if( (psSrcOptions->target) != NULL && (count) != 0 ) \
888 : { \
889 : (psDstOptions->target) = (type *) CPLMalloc(sizeof(type)*(count)); \
890 : memcpy( (psDstOptions->target), (psSrcOptions->target), \
891 : sizeof(type) * (count) ); \
892 : } \
893 : else \
894 : (psDstOptions->target) = NULL; } while(0)
895 :
896 : /************************************************************************/
897 : /* GDALCloneWarpOptions() */
898 : /************************************************************************/
899 :
900 : GDALWarpOptions * CPL_STDCALL
901 742 : GDALCloneWarpOptions( const GDALWarpOptions *psSrcOptions )
902 :
903 : {
904 742 : GDALWarpOptions *psDstOptions = GDALCreateWarpOptions();
905 :
906 742 : memcpy( psDstOptions, psSrcOptions, sizeof(GDALWarpOptions) );
907 :
908 742 : if( psSrcOptions->papszWarpOptions != NULL )
909 : psDstOptions->papszWarpOptions =
910 662 : CSLDuplicate( psSrcOptions->papszWarpOptions );
911 :
912 742 : COPY_MEM( panSrcBands, int, psSrcOptions->nBandCount );
913 742 : COPY_MEM( panDstBands, int, psSrcOptions->nBandCount );
914 742 : COPY_MEM( padfSrcNoDataReal, double, psSrcOptions->nBandCount );
915 742 : COPY_MEM( padfSrcNoDataImag, double, psSrcOptions->nBandCount );
916 742 : COPY_MEM( padfDstNoDataReal, double, psSrcOptions->nBandCount );
917 742 : COPY_MEM( padfDstNoDataImag, double, psSrcOptions->nBandCount );
918 742 : COPY_MEM( papfnSrcPerBandValidityMaskFunc, GDALMaskFunc,
919 : psSrcOptions->nBandCount );
920 742 : psDstOptions->papSrcPerBandValidityMaskFuncArg = NULL;
921 :
922 742 : if( psSrcOptions->hCutline != NULL )
923 : psDstOptions->hCutline =
924 6 : OGR_G_Clone( (OGRGeometryH) psSrcOptions->hCutline );
925 742 : psDstOptions->dfCutlineBlendDist = psSrcOptions->dfCutlineBlendDist;
926 :
927 742 : return psDstOptions;
928 : }
929 :
930 : /************************************************************************/
931 : /* GDALSerializeWarpOptions() */
932 : /************************************************************************/
933 :
934 : CPLXMLNode * CPL_STDCALL
935 12 : GDALSerializeWarpOptions( const GDALWarpOptions *psWO )
936 :
937 : {
938 : CPLXMLNode *psTree;
939 :
940 : /* -------------------------------------------------------------------- */
941 : /* Create root. */
942 : /* -------------------------------------------------------------------- */
943 12 : psTree = CPLCreateXMLNode( NULL, CXT_Element, "GDALWarpOptions" );
944 :
945 : /* -------------------------------------------------------------------- */
946 : /* WarpMemoryLimit */
947 : /* -------------------------------------------------------------------- */
948 : CPLCreateXMLElementAndValue(
949 : psTree, "WarpMemoryLimit",
950 12 : CPLString().Printf("%g", psWO->dfWarpMemoryLimit ) );
951 :
952 : /* -------------------------------------------------------------------- */
953 : /* ResampleAlg */
954 : /* -------------------------------------------------------------------- */
955 : const char *pszAlgName;
956 :
957 12 : if( psWO->eResampleAlg == GRA_NearestNeighbour )
958 12 : pszAlgName = "NearestNeighbour";
959 0 : else if( psWO->eResampleAlg == GRA_Bilinear )
960 0 : pszAlgName = "Bilinear";
961 0 : else if( psWO->eResampleAlg == GRA_Cubic )
962 0 : pszAlgName = "Cubic";
963 0 : else if( psWO->eResampleAlg == GRA_CubicSpline )
964 0 : pszAlgName = "CubicSpline";
965 0 : else if( psWO->eResampleAlg == GRA_Lanczos )
966 0 : pszAlgName = "Lanczos";
967 : else
968 0 : pszAlgName = "Unknown";
969 :
970 : CPLCreateXMLElementAndValue(
971 12 : psTree, "ResampleAlg", pszAlgName );
972 :
973 : /* -------------------------------------------------------------------- */
974 : /* Working Data Type */
975 : /* -------------------------------------------------------------------- */
976 :
977 : CPLCreateXMLElementAndValue(
978 : psTree, "WorkingDataType",
979 12 : GDALGetDataTypeName( psWO->eWorkingDataType ) );
980 :
981 : /* -------------------------------------------------------------------- */
982 : /* Name/value warp options. */
983 : /* -------------------------------------------------------------------- */
984 : int iWO;
985 :
986 48 : for( iWO = 0; psWO->papszWarpOptions != NULL
987 24 : && psWO->papszWarpOptions[iWO] != NULL; iWO++ )
988 : {
989 12 : char *pszName = NULL;
990 : const char *pszValue =
991 12 : CPLParseNameValue( psWO->papszWarpOptions[iWO], &pszName );
992 :
993 : CPLXMLNode *psOption =
994 : CPLCreateXMLElementAndValue(
995 12 : psTree, "Option", pszValue );
996 :
997 : CPLCreateXMLNode(
998 : CPLCreateXMLNode( psOption, CXT_Attribute, "name" ),
999 12 : CXT_Text, pszName );
1000 :
1001 12 : CPLFree(pszName);
1002 : }
1003 :
1004 : /* -------------------------------------------------------------------- */
1005 : /* Source and Destination Data Source */
1006 : /* -------------------------------------------------------------------- */
1007 12 : if( psWO->hSrcDS != NULL )
1008 : {
1009 : CPLCreateXMLElementAndValue(
1010 : psTree, "SourceDataset",
1011 12 : GDALGetDescription( psWO->hSrcDS ) );
1012 : }
1013 :
1014 12 : if( psWO->hDstDS != NULL && strlen(GDALGetDescription(psWO->hDstDS)) != 0 )
1015 : {
1016 : CPLCreateXMLElementAndValue(
1017 : psTree, "DestinationDataset",
1018 0 : GDALGetDescription( psWO->hDstDS ) );
1019 : }
1020 :
1021 : /* -------------------------------------------------------------------- */
1022 : /* Serialize transformer. */
1023 : /* -------------------------------------------------------------------- */
1024 12 : if( psWO->pfnTransformer != NULL )
1025 : {
1026 : CPLXMLNode *psTransformerContainer;
1027 : CPLXMLNode *psTransformerTree;
1028 :
1029 : psTransformerContainer =
1030 12 : CPLCreateXMLNode( psTree, CXT_Element, "Transformer" );
1031 :
1032 : psTransformerTree =
1033 : GDALSerializeTransformer( psWO->pfnTransformer,
1034 12 : psWO->pTransformerArg );
1035 :
1036 12 : if( psTransformerTree != NULL )
1037 12 : CPLAddXMLChild( psTransformerContainer, psTransformerTree );
1038 : }
1039 :
1040 : /* -------------------------------------------------------------------- */
1041 : /* Band count and lists. */
1042 : /* -------------------------------------------------------------------- */
1043 12 : CPLXMLNode *psBandList = NULL;
1044 : int i;
1045 :
1046 12 : if( psWO->nBandCount != 0 )
1047 12 : psBandList = CPLCreateXMLNode( psTree, CXT_Element, "BandList" );
1048 :
1049 42 : for( i = 0; i < psWO->nBandCount; i++ )
1050 : {
1051 : CPLXMLNode *psBand;
1052 :
1053 30 : psBand = CPLCreateXMLNode( psBandList, CXT_Element, "BandMapping" );
1054 30 : if( psWO->panSrcBands != NULL )
1055 : CPLCreateXMLNode(
1056 : CPLCreateXMLNode( psBand, CXT_Attribute, "src" ),
1057 30 : CXT_Text, CPLString().Printf( "%d", psWO->panSrcBands[i] ) );
1058 30 : if( psWO->panDstBands != NULL )
1059 : CPLCreateXMLNode(
1060 : CPLCreateXMLNode( psBand, CXT_Attribute, "dst" ),
1061 30 : CXT_Text, CPLString().Printf( "%d", psWO->panDstBands[i] ) );
1062 :
1063 30 : if( psWO->padfSrcNoDataReal != NULL )
1064 : {
1065 16 : if (CPLIsNan(psWO->padfSrcNoDataReal[i]))
1066 0 : CPLCreateXMLElementAndValue(psBand, "SrcNoDataReal", "nan");
1067 : else
1068 : CPLCreateXMLElementAndValue(
1069 : psBand, "SrcNoDataReal",
1070 16 : CPLString().Printf( "%.16g", psWO->padfSrcNoDataReal[i] ) );
1071 : }
1072 :
1073 30 : if( psWO->padfSrcNoDataImag != NULL )
1074 : {
1075 16 : if (CPLIsNan(psWO->padfSrcNoDataImag[i]))
1076 0 : CPLCreateXMLElementAndValue(psBand, "SrcNoDataImag", "nan");
1077 : else
1078 : CPLCreateXMLElementAndValue(
1079 : psBand, "SrcNoDataImag",
1080 16 : CPLString().Printf( "%.16g", psWO->padfSrcNoDataImag[i] ) );
1081 : }
1082 :
1083 30 : if( psWO->padfDstNoDataReal != NULL )
1084 : {
1085 0 : if (CPLIsNan(psWO->padfDstNoDataReal[i]))
1086 0 : CPLCreateXMLElementAndValue(psBand, "DstNoDataReal", "nan");
1087 : else
1088 : CPLCreateXMLElementAndValue(
1089 : psBand, "DstNoDataReal",
1090 0 : CPLString().Printf( "%.16g", psWO->padfDstNoDataReal[i] ) );
1091 : }
1092 :
1093 30 : if( psWO->padfDstNoDataImag != NULL )
1094 : {
1095 0 : if (CPLIsNan(psWO->padfDstNoDataImag[i]))
1096 0 : CPLCreateXMLElementAndValue(psBand, "DstNoDataImag", "nan");
1097 : else
1098 : CPLCreateXMLElementAndValue(
1099 : psBand, "DstNoDataImag",
1100 0 : CPLString().Printf( "%.16g", psWO->padfDstNoDataImag[i] ) );
1101 : }
1102 : }
1103 :
1104 : /* -------------------------------------------------------------------- */
1105 : /* Alpha bands. */
1106 : /* -------------------------------------------------------------------- */
1107 12 : if( psWO->nSrcAlphaBand > 0 )
1108 : CPLCreateXMLElementAndValue(
1109 : psTree, "SrcAlphaBand",
1110 0 : CPLString().Printf( "%d", psWO->nSrcAlphaBand ) );
1111 :
1112 12 : if( psWO->nDstAlphaBand > 0 )
1113 : CPLCreateXMLElementAndValue(
1114 : psTree, "DstAlphaBand",
1115 0 : CPLString().Printf( "%d", psWO->nDstAlphaBand ) );
1116 :
1117 : /* -------------------------------------------------------------------- */
1118 : /* Cutline. */
1119 : /* -------------------------------------------------------------------- */
1120 12 : if( psWO->hCutline != NULL )
1121 : {
1122 0 : char *pszWKT = NULL;
1123 0 : if( OGR_G_ExportToWkt( (OGRGeometryH) psWO->hCutline, &pszWKT )
1124 : == OGRERR_NONE )
1125 : {
1126 0 : CPLCreateXMLElementAndValue( psTree, "Cutline", pszWKT );
1127 0 : CPLFree( pszWKT );
1128 : }
1129 : }
1130 :
1131 12 : if( psWO->dfCutlineBlendDist != 0.0 )
1132 : CPLCreateXMLElementAndValue(
1133 : psTree, "CutlineBlendDist",
1134 0 : CPLString().Printf( "%.5g", psWO->dfCutlineBlendDist ) );
1135 :
1136 12 : return psTree;
1137 : }
1138 :
1139 : /************************************************************************/
1140 : /* GDALDeserializeWarpOptions() */
1141 : /************************************************************************/
1142 :
1143 84 : GDALWarpOptions * CPL_STDCALL GDALDeserializeWarpOptions( CPLXMLNode *psTree )
1144 :
1145 : {
1146 84 : CPLErrorReset();
1147 :
1148 : /* -------------------------------------------------------------------- */
1149 : /* Verify this is the right kind of object. */
1150 : /* -------------------------------------------------------------------- */
1151 84 : if( psTree == NULL || psTree->eType != CXT_Element
1152 : || !EQUAL(psTree->pszValue,"GDALWarpOptions") )
1153 : {
1154 : CPLError( CE_Failure, CPLE_AppDefined,
1155 0 : "Wrong node, unable to deserialize GDALWarpOptions." );
1156 0 : return NULL;
1157 : }
1158 :
1159 : /* -------------------------------------------------------------------- */
1160 : /* Create pre-initialized warp options. */
1161 : /* -------------------------------------------------------------------- */
1162 84 : GDALWarpOptions *psWO = GDALCreateWarpOptions();
1163 :
1164 : /* -------------------------------------------------------------------- */
1165 : /* Warp memory limit. */
1166 : /* -------------------------------------------------------------------- */
1167 : psWO->dfWarpMemoryLimit =
1168 84 : atof(CPLGetXMLValue(psTree,"WarpMemoryLimit","0.0"));
1169 :
1170 : /* -------------------------------------------------------------------- */
1171 : /* resample algorithm */
1172 : /* -------------------------------------------------------------------- */
1173 : const char *pszValue =
1174 84 : CPLGetXMLValue(psTree,"ResampleAlg","Default");
1175 :
1176 84 : if( EQUAL(pszValue,"NearestNeighbour") )
1177 56 : psWO->eResampleAlg = GRA_NearestNeighbour;
1178 28 : else if( EQUAL(pszValue,"Bilinear") )
1179 8 : psWO->eResampleAlg = GRA_Bilinear;
1180 20 : else if( EQUAL(pszValue,"Cubic") )
1181 8 : psWO->eResampleAlg = GRA_Cubic;
1182 12 : else if( EQUAL(pszValue,"CubicSpline") )
1183 8 : psWO->eResampleAlg = GRA_CubicSpline;
1184 4 : else if( EQUAL(pszValue,"Lanczos") )
1185 4 : psWO->eResampleAlg = GRA_Lanczos;
1186 0 : else if( EQUAL(pszValue,"Default") )
1187 : /* leave as is */;
1188 : else
1189 : {
1190 : CPLError( CE_Failure, CPLE_AppDefined,
1191 : "Unrecognise ResampleAlg value '%s'.",
1192 0 : pszValue );
1193 : }
1194 :
1195 : /* -------------------------------------------------------------------- */
1196 : /* Working data type. */
1197 : /* -------------------------------------------------------------------- */
1198 : psWO->eWorkingDataType =
1199 : GDALGetDataTypeByName(
1200 84 : CPLGetXMLValue(psTree,"WorkingDataType","Unknown"));
1201 :
1202 : /* -------------------------------------------------------------------- */
1203 : /* Name/value warp options. */
1204 : /* -------------------------------------------------------------------- */
1205 : CPLXMLNode *psItem;
1206 :
1207 678 : for( psItem = psTree->psChild; psItem != NULL; psItem = psItem->psNext )
1208 : {
1209 594 : if( psItem->eType == CXT_Element
1210 : && EQUAL(psItem->pszValue,"Option") )
1211 : {
1212 50 : const char *pszName = CPLGetXMLValue(psItem, "Name", NULL );
1213 50 : const char *pszValue = CPLGetXMLValue(psItem, "", NULL );
1214 :
1215 50 : if( pszName != NULL && pszValue != NULL )
1216 : {
1217 : psWO->papszWarpOptions =
1218 : CSLSetNameValue( psWO->papszWarpOptions,
1219 50 : pszName, pszValue );
1220 : }
1221 : }
1222 : }
1223 :
1224 : /* -------------------------------------------------------------------- */
1225 : /* Source Dataset. */
1226 : /* -------------------------------------------------------------------- */
1227 84 : pszValue = CPLGetXMLValue(psTree,"SourceDataset",NULL);
1228 :
1229 84 : if( pszValue != NULL )
1230 84 : psWO->hSrcDS = GDALOpenShared( pszValue, GA_ReadOnly );
1231 :
1232 : /* -------------------------------------------------------------------- */
1233 : /* Destination Dataset. */
1234 : /* -------------------------------------------------------------------- */
1235 84 : pszValue = CPLGetXMLValue(psTree,"DestinationDataset",NULL);
1236 :
1237 84 : if( pszValue != NULL )
1238 0 : psWO->hDstDS = GDALOpenShared( pszValue, GA_Update );
1239 :
1240 : /* -------------------------------------------------------------------- */
1241 : /* First, count band mappings so we can establish the bandcount. */
1242 : /* -------------------------------------------------------------------- */
1243 84 : CPLXMLNode *psBandTree = CPLGetXMLNode( psTree, "BandList" );
1244 84 : CPLXMLNode *psBand = NULL;
1245 :
1246 84 : psWO->nBandCount = 0;
1247 :
1248 84 : if (psBandTree)
1249 84 : psBand = psBandTree->psChild;
1250 : else
1251 0 : psBand = NULL;
1252 :
1253 222 : for( ; psBand != NULL; psBand = psBand->psNext )
1254 : {
1255 138 : if( psBand->eType != CXT_Element
1256 : || !EQUAL(psBand->pszValue,"BandMapping") )
1257 0 : continue;
1258 :
1259 138 : psWO->nBandCount++;
1260 : }
1261 :
1262 : /* ==================================================================== */
1263 : /* Now actually process each bandmapping. */
1264 : /* ==================================================================== */
1265 84 : int iBand = 0;
1266 :
1267 84 : if (psBandTree)
1268 84 : psBand = psBandTree->psChild;
1269 : else
1270 0 : psBand = NULL;
1271 :
1272 222 : for( ; psBand != NULL; psBand = psBand->psNext )
1273 : {
1274 138 : if( psBand->eType != CXT_Element
1275 : || !EQUAL(psBand->pszValue,"BandMapping") )
1276 0 : continue;
1277 :
1278 : /* -------------------------------------------------------------------- */
1279 : /* Source band */
1280 : /* -------------------------------------------------------------------- */
1281 138 : if( psWO->panSrcBands == NULL )
1282 84 : psWO->panSrcBands = (int *)CPLMalloc(sizeof(int)*psWO->nBandCount);
1283 :
1284 138 : pszValue = CPLGetXMLValue(psBand,"src",NULL);
1285 138 : if( pszValue == NULL )
1286 0 : psWO->panSrcBands[iBand] = iBand+1;
1287 : else
1288 138 : psWO->panSrcBands[iBand] = atoi(pszValue);
1289 :
1290 : /* -------------------------------------------------------------------- */
1291 : /* Destination band. */
1292 : /* -------------------------------------------------------------------- */
1293 138 : pszValue = CPLGetXMLValue(psBand,"dst",NULL);
1294 138 : if( pszValue != NULL )
1295 : {
1296 138 : if( psWO->panDstBands == NULL )
1297 : psWO->panDstBands =
1298 84 : (int *) CPLMalloc(sizeof(int)*psWO->nBandCount);
1299 :
1300 138 : psWO->panDstBands[iBand] = atoi(pszValue);
1301 : }
1302 :
1303 : /* -------------------------------------------------------------------- */
1304 : /* Source nodata. */
1305 : /* -------------------------------------------------------------------- */
1306 138 : pszValue = CPLGetXMLValue(psBand,"SrcNoDataReal",NULL);
1307 138 : if( pszValue != NULL )
1308 : {
1309 26 : if( psWO->padfSrcNoDataReal == NULL )
1310 : psWO->padfSrcNoDataReal =
1311 12 : (double *) CPLCalloc(sizeof(double),psWO->nBandCount);
1312 :
1313 26 : psWO->padfSrcNoDataReal[iBand] = CPLAtofM(pszValue);
1314 : }
1315 :
1316 138 : pszValue = CPLGetXMLValue(psBand,"SrcNoDataImag",NULL);
1317 138 : if( pszValue != NULL )
1318 : {
1319 26 : if( psWO->padfSrcNoDataImag == NULL )
1320 : psWO->padfSrcNoDataImag =
1321 12 : (double *) CPLCalloc(sizeof(double),psWO->nBandCount);
1322 :
1323 26 : psWO->padfSrcNoDataImag[iBand] = CPLAtofM(pszValue);
1324 : }
1325 :
1326 : /* -------------------------------------------------------------------- */
1327 : /* Destination nodata. */
1328 : /* -------------------------------------------------------------------- */
1329 138 : pszValue = CPLGetXMLValue(psBand,"DstNoDataReal",NULL);
1330 138 : if( pszValue != NULL )
1331 : {
1332 10 : if( psWO->padfDstNoDataReal == NULL )
1333 : psWO->padfDstNoDataReal =
1334 10 : (double *) CPLCalloc(sizeof(double),psWO->nBandCount);
1335 :
1336 10 : psWO->padfDstNoDataReal[iBand] = CPLAtofM(pszValue);
1337 : }
1338 :
1339 138 : pszValue = CPLGetXMLValue(psBand,"DstNoDataImag",NULL);
1340 138 : if( pszValue != NULL )
1341 : {
1342 10 : if( psWO->padfDstNoDataImag == NULL )
1343 : psWO->padfDstNoDataImag =
1344 10 : (double *) CPLCalloc(sizeof(double),psWO->nBandCount);
1345 :
1346 10 : psWO->padfDstNoDataImag[iBand] = CPLAtofM(pszValue);
1347 : }
1348 :
1349 138 : iBand++;
1350 : }
1351 :
1352 : /* -------------------------------------------------------------------- */
1353 : /* Alpha bands. */
1354 : /* -------------------------------------------------------------------- */
1355 : psWO->nSrcAlphaBand =
1356 84 : atoi( CPLGetXMLValue( psTree, "SrcAlphaBand", "0" ) );
1357 : psWO->nDstAlphaBand =
1358 84 : atoi( CPLGetXMLValue( psTree, "DstAlphaBand", "0" ) );
1359 :
1360 : /* -------------------------------------------------------------------- */
1361 : /* Cutline. */
1362 : /* -------------------------------------------------------------------- */
1363 84 : const char *pszWKT = CPLGetXMLValue( psTree, "Cutline", NULL );
1364 84 : if( pszWKT )
1365 : {
1366 : OGR_G_CreateFromWkt( (char **) &pszWKT, NULL,
1367 6 : (OGRGeometryH *) (&psWO->hCutline) );
1368 : }
1369 :
1370 : psWO->dfCutlineBlendDist =
1371 84 : atof( CPLGetXMLValue( psTree, "CutlineBlendDist", "0" ) );
1372 :
1373 : /* -------------------------------------------------------------------- */
1374 : /* Transformation. */
1375 : /* -------------------------------------------------------------------- */
1376 84 : CPLXMLNode *psTransformer = CPLGetXMLNode( psTree, "Transformer" );
1377 :
1378 84 : if( psTransformer != NULL && psTransformer->psChild != NULL )
1379 : {
1380 : GDALDeserializeTransformer( psTransformer->psChild,
1381 : &(psWO->pfnTransformer),
1382 84 : &(psWO->pTransformerArg) );
1383 : }
1384 :
1385 : /* -------------------------------------------------------------------- */
1386 : /* If any error has occured, cleanup else return success. */
1387 : /* -------------------------------------------------------------------- */
1388 84 : if( CPLGetLastErrorNo() != CE_None )
1389 : {
1390 0 : if ( psWO->pTransformerArg )
1391 : {
1392 0 : GDALDestroyTransformer( psWO->pTransformerArg );
1393 0 : psWO->pTransformerArg = NULL;
1394 : }
1395 0 : if( psWO->hSrcDS != NULL )
1396 : {
1397 0 : GDALClose( psWO->hSrcDS );
1398 0 : psWO->hSrcDS = NULL;
1399 : }
1400 0 : if( psWO->hDstDS != NULL )
1401 : {
1402 0 : GDALClose( psWO->hDstDS );
1403 0 : psWO->hDstDS = NULL;
1404 : }
1405 0 : GDALDestroyWarpOptions( psWO );
1406 0 : return NULL;
1407 : }
1408 : else
1409 84 : return psWO;
1410 : }
|