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