1 : /******************************************************************************
2 : * $Id: gdalwarper.cpp 25229 2012-11-16 19:06:58Z 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 25229 2012-11-16 19:06:58Z 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 27 : 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 27 : TRUE, 1000.0, 0 );
95 :
96 27 : 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 27 : if( psOptions == NULL )
104 27 : psWOptions = GDALCreateWarpOptions();
105 : else
106 0 : psWOptions = GDALCloneWarpOptions( psOptions );
107 :
108 27 : psWOptions->eResampleAlg = eResampleAlg;
109 :
110 : /* -------------------------------------------------------------------- */
111 : /* Set transform. */
112 : /* -------------------------------------------------------------------- */
113 27 : if( dfMaxError > 0.0 )
114 : {
115 : psWOptions->pTransformerArg =
116 : GDALCreateApproxTransformer( GDALGenImgProjTransform,
117 3 : hTransformArg, dfMaxError );
118 :
119 3 : psWOptions->pfnTransformer = GDALApproxTransform;
120 : }
121 : else
122 : {
123 24 : psWOptions->pfnTransformer = GDALGenImgProjTransform;
124 24 : psWOptions->pTransformerArg = hTransformArg;
125 : }
126 :
127 : /* -------------------------------------------------------------------- */
128 : /* Set file and band mapping. */
129 : /* -------------------------------------------------------------------- */
130 : int iBand;
131 :
132 27 : psWOptions->hSrcDS = hSrcDS;
133 27 : psWOptions->hDstDS = hDstDS;
134 :
135 27 : if( psWOptions->nBandCount == 0 )
136 : {
137 : psWOptions->nBandCount = MIN(GDALGetRasterCount(hSrcDS),
138 27 : GDALGetRasterCount(hDstDS));
139 :
140 : psWOptions->panSrcBands = (int *)
141 27 : CPLMalloc(sizeof(int) * psWOptions->nBandCount);
142 : psWOptions->panDstBands = (int *)
143 27 : CPLMalloc(sizeof(int) * psWOptions->nBandCount);
144 :
145 60 : for( iBand = 0; iBand < psWOptions->nBandCount; iBand++ )
146 : {
147 33 : psWOptions->panSrcBands[iBand] = iBand+1;
148 33 : 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 60 : for( iBand = 0; iBand < psWOptions->nBandCount; iBand++ )
157 : {
158 33 : GDALRasterBandH hBand = GDALGetRasterBand( hSrcDS, iBand+1 );
159 33 : int bGotNoData = FALSE;
160 : double dfNoDataValue;
161 :
162 33 : if (GDALGetRasterColorInterpretation(hBand) == GCI_AlphaBand)
163 : {
164 2 : psWOptions->nSrcAlphaBand = iBand + 1;
165 : }
166 :
167 33 : dfNoDataValue = GDALGetRasterNoDataValue( hBand, &bGotNoData );
168 33 : if( bGotNoData )
169 : {
170 5 : if( psWOptions->padfSrcNoDataReal == NULL )
171 : {
172 : int ii;
173 :
174 : psWOptions->padfSrcNoDataReal = (double *)
175 5 : CPLMalloc(sizeof(double) * psWOptions->nBandCount);
176 : psWOptions->padfSrcNoDataImag = (double *)
177 5 : CPLMalloc(sizeof(double) * psWOptions->nBandCount);
178 :
179 10 : for( ii = 0; ii < psWOptions->nBandCount; ii++ )
180 : {
181 5 : psWOptions->padfSrcNoDataReal[ii] = -1.1e20;
182 5 : psWOptions->padfSrcNoDataImag[ii] = 0.0;
183 : }
184 : }
185 :
186 5 : psWOptions->padfSrcNoDataReal[iBand] = dfNoDataValue;
187 : }
188 :
189 33 : hBand = GDALGetRasterBand( hDstDS, iBand+1 );
190 33 : if (hBand && GDALGetRasterColorInterpretation(hBand) == GCI_AlphaBand)
191 : {
192 2 : psWOptions->nDstAlphaBand = iBand + 1;
193 : }
194 : }
195 :
196 : /* -------------------------------------------------------------------- */
197 : /* Set the progress function. */
198 : /* -------------------------------------------------------------------- */
199 27 : if( pfnProgress != NULL )
200 : {
201 3 : psWOptions->pfnProgress = pfnProgress;
202 3 : psWOptions->pProgressArg = pProgressArg;
203 : }
204 :
205 : /* -------------------------------------------------------------------- */
206 : /* Create a warp options based on the options. */
207 : /* -------------------------------------------------------------------- */
208 27 : GDALWarpOperation oWarper;
209 : CPLErr eErr;
210 :
211 27 : eErr = oWarper.Initialize( psWOptions );
212 :
213 27 : if( eErr == CE_None )
214 : eErr = oWarper.ChunkAndWarpImage( 0, 0,
215 : GDALGetRasterXSize(hDstDS),
216 27 : GDALGetRasterYSize(hDstDS) );
217 :
218 : /* -------------------------------------------------------------------- */
219 : /* Cleanup. */
220 : /* -------------------------------------------------------------------- */
221 27 : GDALDestroyGenImgProjTransformer( hTransformArg );
222 :
223 27 : if( dfMaxError > 0.0 )
224 3 : GDALDestroyApproxTransformer( psWOptions->pTransformerArg );
225 :
226 27 : GDALDestroyWarpOptions( psWOptions );
227 :
228 27 : 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 36 : 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 36 : double *padfNoData = (double *) pMaskFuncArg;
344 36 : GUInt32 *panValidityMask = (GUInt32 *) pValidityMask;
345 :
346 36 : 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 36 : switch( eType )
354 : {
355 : case GDT_Byte:
356 : {
357 15 : int nNoData = (int) padfNoData[0];
358 15 : GByte *pabyData = (GByte *) *ppImageData;
359 : int iOffset;
360 :
361 : // nothing to do if value is out of range.
362 30 : if( padfNoData[0] < 0.0 || padfNoData[0] > 255.000001
363 15 : || padfNoData[1] != 0.0 )
364 0 : return CE_None;
365 :
366 279200 : for( iOffset = nXSize*nYSize-1; iOffset >= 0; iOffset-- )
367 : {
368 279185 : if( pabyData[iOffset] == nNoData )
369 : {
370 264930 : panValidityMask[iOffset>>5] &= ~(0x01 << (iOffset & 0x1f));
371 : }
372 : }
373 : }
374 15 : break;
375 :
376 : case GDT_Int16:
377 : {
378 5 : int nNoData = (int) padfNoData[0];
379 5 : GInt16 *panData = (GInt16 *) *ppImageData;
380 : int iOffset;
381 :
382 : // nothing to do if value is out of range.
383 10 : if( padfNoData[0] < -32768 || padfNoData[0] > 32767
384 5 : || padfNoData[1] != 0.0 )
385 0 : return CE_None;
386 :
387 45829 : for( iOffset = nXSize*nYSize-1; iOffset >= 0; iOffset-- )
388 : {
389 45824 : if( panData[iOffset] == nNoData )
390 : {
391 715 : panValidityMask[iOffset>>5] &= ~(0x01 << (iOffset & 0x1f));
392 : }
393 : }
394 : }
395 5 : 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 8 : float fNoData = (float) padfNoData[0];
421 8 : float *pafData = (float *) *ppImageData;
422 : int iOffset;
423 8 : int bIsNoDataNan = CPLIsNan(fNoData);
424 :
425 : // nothing to do if value is out of range.
426 8 : if( padfNoData[1] != 0.0 )
427 0 : return CE_None;
428 :
429 262552 : for( iOffset = nXSize*nYSize-1; iOffset >= 0; iOffset-- )
430 : {
431 262544 : float fVal = pafData[iOffset];
432 262544 : if( (bIsNoDataNan && CPLIsNan(fVal)) || (!bIsNoDataNan && ARE_REAL_EQUAL(fVal, fNoData)) )
433 : {
434 262184 : panValidityMask[iOffset>>5] &= ~(0x01 << (iOffset & 0x1f));
435 : }
436 : }
437 : }
438 8 : 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 8 : int nWordSize = GDALGetDataTypeSize(eType)/8;
467 :
468 8 : int bIsNoDataRealNan = CPLIsNan(padfNoData[0]);
469 8 : int bIsNoDataImagNan = CPLIsNan(padfNoData[1]);
470 :
471 8 : padfWrk = (double *) CPLMalloc(nXSize * sizeof(double) * 2);
472 88 : for( iLine = 0; iLine < nYSize; iLine++ )
473 : {
474 : GDALCopyWords( ((GByte *) *ppImageData)+nWordSize*iLine*nXSize,
475 : eType, nWordSize,
476 80 : padfWrk, GDT_CFloat64, 16, nXSize );
477 :
478 880 : for( iPixel = 0; iPixel < nXSize; iPixel++ )
479 : {
480 4000 : if( ((bIsNoDataRealNan && CPLIsNan(padfWrk[iPixel*2])) ||
481 3200 : (!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 8 : CPLFree( padfWrk );
495 : }
496 : break;
497 : }
498 :
499 36 : 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 9 : 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 9 : GDALWarpOptions *psWO = (GDALWarpOptions *) pMaskFuncArg;
518 9 : float *pafMask = (float *) pValidityMask;
519 :
520 : /* -------------------------------------------------------------------- */
521 : /* Do some minimal checking. */
522 : /* -------------------------------------------------------------------- */
523 9 : if( !bMaskIsFloat )
524 : {
525 0 : CPLAssert( FALSE );
526 0 : return CE_Failure;
527 : }
528 :
529 9 : 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 9 : psWO->nSrcAlphaBand );
541 9 : if (hAlphaBand == NULL)
542 0 : return CE_Failure;
543 :
544 : eErr = GDALRasterIO( hAlphaBand, GF_Read, nXOff, nYOff, nXSize, nYSize,
545 9 : pafMask, nXSize, nYSize, GDT_Float32, 0, 0 );
546 :
547 9 : if( eErr != CE_None )
548 0 : return eErr;
549 :
550 : /* -------------------------------------------------------------------- */
551 : /* Rescale from 0-255 to 0.0-1.0. */
552 : /* -------------------------------------------------------------------- */
553 3309 : for( int iPixel = nXSize * nYSize - 1; iPixel >= 0; iPixel-- )
554 : { // (1/255)
555 3300 : pafMask[iPixel] = (float)( pafMask[iPixel] * 0.00392157 );
556 3300 : pafMask[iPixel] = MIN( 1.0F, pafMask[iPixel] );
557 : }
558 :
559 9 : 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 1 : 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 1 : GDALWarpOptions *psWO = (GDALWarpOptions *) pMaskFuncArg;
577 1 : GUInt32 *panMask = (GUInt32 *) pValidityMask;
578 :
579 : /* -------------------------------------------------------------------- */
580 : /* Do some minimal checking. */
581 : /* -------------------------------------------------------------------- */
582 1 : if( bMaskIsFloat )
583 : {
584 0 : CPLAssert( FALSE );
585 0 : return CE_Failure;
586 : }
587 :
588 1 : 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 1 : pabySrcMask = (GByte *) VSIMalloc2(nXSize,nYSize);
600 1 : 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 1 : GDALRasterBandH hSrcBand, hMaskBand = NULL;
612 :
613 1 : hSrcBand = GDALGetRasterBand( psWO->hSrcDS, psWO->panSrcBands[0] );
614 1 : if( hSrcBand != NULL )
615 1 : hMaskBand = GDALGetMaskBand( hSrcBand );
616 :
617 1 : 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 1 : pabySrcMask, nXSize, nYSize, GDT_Byte, 0, 0 );
630 :
631 1 : 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 154578 : for( int iPixel = nXSize * nYSize - 1; iPixel >= 0; iPixel-- )
641 : {
642 154577 : if( pabySrcMask[iPixel] == 0 )
643 31659 : panMask[iPixel>>5] &= ~(0x01 << (iPixel & 0x1f));
644 : }
645 :
646 1 : CPLFree( pabySrcMask );
647 :
648 1 : 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 52 : 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 52 : GDALWarpOptions *psWO = (GDALWarpOptions *) pMaskFuncArg;
668 52 : float *pafMask = (float *) pValidityMask;
669 : int iPixel;
670 : CPLErr eErr;
671 :
672 : /* -------------------------------------------------------------------- */
673 : /* Do some minimal checking. */
674 : /* -------------------------------------------------------------------- */
675 52 : if( !bMaskIsFloat )
676 : {
677 0 : CPLAssert( FALSE );
678 0 : return CE_Failure;
679 : }
680 :
681 52 : if( psWO == NULL || psWO->nDstAlphaBand < 1 )
682 : {
683 0 : CPLAssert( FALSE );
684 0 : return CE_Failure;
685 : }
686 :
687 : GDALRasterBandH hAlphaBand =
688 52 : GDALGetRasterBand( psWO->hDstDS, psWO->nDstAlphaBand );
689 52 : if (hAlphaBand == NULL)
690 0 : return CE_Failure;
691 :
692 : /* -------------------------------------------------------------------- */
693 : /* Read alpha case. */
694 : /* -------------------------------------------------------------------- */
695 52 : if( nBandCount >= 0 )
696 : {
697 : const char *pszInitDest =
698 26 : CSLFetchNameValue( psWO->papszWarpOptions, "INIT_DEST" );
699 :
700 : // Special logic for destinations being initialized on the fly.
701 26 : if( pszInitDest != NULL )
702 : {
703 1554900 : for( iPixel = nXSize * nYSize - 1; iPixel >= 0; iPixel-- )
704 1554876 : pafMask[iPixel] = 0.0;
705 24 : return CE_None;
706 : }
707 :
708 : // Read data.
709 : eErr = GDALRasterIO( hAlphaBand, GF_Read, nXOff, nYOff, nXSize, nYSize,
710 2 : pafMask, nXSize, nYSize, GDT_Float32, 0, 0 );
711 :
712 2 : if( eErr != CE_None )
713 0 : return eErr;
714 :
715 : // rescale.
716 127 : for( iPixel = nXSize * nYSize - 1; iPixel >= 0; iPixel-- )
717 : {
718 125 : pafMask[iPixel] = (float) (pafMask[iPixel] * 0.00392157);
719 125 : pafMask[iPixel] = MIN( 1.0F, pafMask[iPixel] );
720 : }
721 :
722 2 : return CE_None;
723 : }
724 :
725 : /* -------------------------------------------------------------------- */
726 : /* Write alpha case. */
727 : /* -------------------------------------------------------------------- */
728 : else
729 : {
730 1555027 : for( iPixel = nXSize * nYSize - 1; iPixel >= 0; iPixel-- )
731 1555001 : 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 26 : int nDstXSize = nXSize;
739 26 : if (nXOff + nXSize > GDALGetRasterBandXSize(hAlphaBand))
740 16 : nDstXSize = GDALGetRasterBandXSize(hAlphaBand) - nXOff;
741 26 : int nDstYSize = nYSize;
742 26 : if (nYOff + nYSize > GDALGetRasterBandYSize(hAlphaBand))
743 12 : nDstYSize = GDALGetRasterBandYSize(hAlphaBand) - nYOff;
744 :
745 : eErr = GDALRasterIO( hAlphaBand, GF_Write,
746 : nXOff, nYOff, nDstXSize, nDstYSize,
747 : pafMask, nDstXSize, nDstYSize, GDT_Float32,
748 26 : 0, sizeof(float) * nXSize );
749 26 : 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 : * - NUM_THREADS: (GDAL >= 1.10) Can be set to a numeric value or ALL_CPUS to
842 : * set the number of threads to use to parallelize the computation part of the
843 : * warping. If not set, computation will be done in a single thread.
844 : */
845 :
846 : /************************************************************************/
847 : /* GDALCreateWarpOptions() */
848 : /************************************************************************/
849 :
850 738 : GDALWarpOptions * CPL_STDCALL GDALCreateWarpOptions()
851 :
852 : {
853 : GDALWarpOptions *psOptions;
854 :
855 738 : psOptions = (GDALWarpOptions *) CPLCalloc(sizeof(GDALWarpOptions),1);
856 :
857 738 : psOptions->eResampleAlg = GRA_NearestNeighbour;
858 738 : psOptions->pfnProgress = GDALDummyProgress;
859 738 : psOptions->eWorkingDataType = GDT_Unknown;
860 :
861 738 : return psOptions;
862 : }
863 :
864 : /************************************************************************/
865 : /* GDALDestroyWarpOptions() */
866 : /************************************************************************/
867 :
868 738 : void CPL_STDCALL GDALDestroyWarpOptions( GDALWarpOptions *psOptions )
869 :
870 : {
871 738 : VALIDATE_POINTER0( psOptions, "GDALDestroyWarpOptions" );
872 :
873 738 : CSLDestroy( psOptions->papszWarpOptions );
874 738 : CPLFree( psOptions->panSrcBands );
875 738 : CPLFree( psOptions->panDstBands );
876 738 : CPLFree( psOptions->padfSrcNoDataReal );
877 738 : CPLFree( psOptions->padfSrcNoDataImag );
878 738 : CPLFree( psOptions->padfDstNoDataReal );
879 738 : CPLFree( psOptions->padfDstNoDataImag );
880 738 : CPLFree( psOptions->papfnSrcPerBandValidityMaskFunc );
881 738 : CPLFree( psOptions->papSrcPerBandValidityMaskFuncArg );
882 :
883 738 : if( psOptions->hCutline != NULL )
884 9 : OGR_G_DestroyGeometry( (OGRGeometryH) psOptions->hCutline );
885 :
886 738 : CPLFree( psOptions );
887 : }
888 :
889 :
890 : #define COPY_MEM(target,type,count) \
891 : do { if( (psSrcOptions->target) != NULL && (count) != 0 ) \
892 : { \
893 : (psDstOptions->target) = (type *) CPLMalloc(sizeof(type)*(count)); \
894 : memcpy( (psDstOptions->target), (psSrcOptions->target), \
895 : sizeof(type) * (count) ); \
896 : } \
897 : else \
898 : (psDstOptions->target) = NULL; } while(0)
899 :
900 : /************************************************************************/
901 : /* GDALCloneWarpOptions() */
902 : /************************************************************************/
903 :
904 : GDALWarpOptions * CPL_STDCALL
905 380 : GDALCloneWarpOptions( const GDALWarpOptions *psSrcOptions )
906 :
907 : {
908 380 : GDALWarpOptions *psDstOptions = GDALCreateWarpOptions();
909 :
910 380 : memcpy( psDstOptions, psSrcOptions, sizeof(GDALWarpOptions) );
911 :
912 380 : if( psSrcOptions->papszWarpOptions != NULL )
913 : psDstOptions->papszWarpOptions =
914 337 : CSLDuplicate( psSrcOptions->papszWarpOptions );
915 :
916 380 : COPY_MEM( panSrcBands, int, psSrcOptions->nBandCount );
917 380 : COPY_MEM( panDstBands, int, psSrcOptions->nBandCount );
918 380 : COPY_MEM( padfSrcNoDataReal, double, psSrcOptions->nBandCount );
919 380 : COPY_MEM( padfSrcNoDataImag, double, psSrcOptions->nBandCount );
920 380 : COPY_MEM( padfDstNoDataReal, double, psSrcOptions->nBandCount );
921 380 : COPY_MEM( padfDstNoDataImag, double, psSrcOptions->nBandCount );
922 380 : COPY_MEM( papfnSrcPerBandValidityMaskFunc, GDALMaskFunc,
923 : psSrcOptions->nBandCount );
924 380 : psDstOptions->papSrcPerBandValidityMaskFuncArg = NULL;
925 :
926 380 : if( psSrcOptions->hCutline != NULL )
927 : psDstOptions->hCutline =
928 3 : OGR_G_Clone( (OGRGeometryH) psSrcOptions->hCutline );
929 380 : psDstOptions->dfCutlineBlendDist = psSrcOptions->dfCutlineBlendDist;
930 :
931 380 : return psDstOptions;
932 : }
933 :
934 : /************************************************************************/
935 : /* GDALSerializeWarpOptions() */
936 : /************************************************************************/
937 :
938 : CPLXMLNode * CPL_STDCALL
939 6 : GDALSerializeWarpOptions( const GDALWarpOptions *psWO )
940 :
941 : {
942 : CPLXMLNode *psTree;
943 :
944 : /* -------------------------------------------------------------------- */
945 : /* Create root. */
946 : /* -------------------------------------------------------------------- */
947 6 : psTree = CPLCreateXMLNode( NULL, CXT_Element, "GDALWarpOptions" );
948 :
949 : /* -------------------------------------------------------------------- */
950 : /* WarpMemoryLimit */
951 : /* -------------------------------------------------------------------- */
952 : CPLCreateXMLElementAndValue(
953 : psTree, "WarpMemoryLimit",
954 6 : CPLString().Printf("%g", psWO->dfWarpMemoryLimit ) );
955 :
956 : /* -------------------------------------------------------------------- */
957 : /* ResampleAlg */
958 : /* -------------------------------------------------------------------- */
959 : const char *pszAlgName;
960 :
961 6 : if( psWO->eResampleAlg == GRA_NearestNeighbour )
962 6 : pszAlgName = "NearestNeighbour";
963 0 : else if( psWO->eResampleAlg == GRA_Bilinear )
964 0 : pszAlgName = "Bilinear";
965 0 : else if( psWO->eResampleAlg == GRA_Cubic )
966 0 : pszAlgName = "Cubic";
967 0 : else if( psWO->eResampleAlg == GRA_CubicSpline )
968 0 : pszAlgName = "CubicSpline";
969 0 : else if( psWO->eResampleAlg == GRA_Lanczos )
970 0 : pszAlgName = "Lanczos";
971 : else
972 0 : pszAlgName = "Unknown";
973 :
974 : CPLCreateXMLElementAndValue(
975 6 : psTree, "ResampleAlg", pszAlgName );
976 :
977 : /* -------------------------------------------------------------------- */
978 : /* Working Data Type */
979 : /* -------------------------------------------------------------------- */
980 :
981 : CPLCreateXMLElementAndValue(
982 : psTree, "WorkingDataType",
983 6 : GDALGetDataTypeName( psWO->eWorkingDataType ) );
984 :
985 : /* -------------------------------------------------------------------- */
986 : /* Name/value warp options. */
987 : /* -------------------------------------------------------------------- */
988 : int iWO;
989 :
990 36 : for( iWO = 0; psWO->papszWarpOptions != NULL
991 18 : && psWO->papszWarpOptions[iWO] != NULL; iWO++ )
992 : {
993 12 : char *pszName = NULL;
994 : const char *pszValue =
995 12 : CPLParseNameValue( psWO->papszWarpOptions[iWO], &pszName );
996 :
997 : CPLXMLNode *psOption =
998 : CPLCreateXMLElementAndValue(
999 12 : psTree, "Option", pszValue );
1000 :
1001 : CPLCreateXMLNode(
1002 : CPLCreateXMLNode( psOption, CXT_Attribute, "name" ),
1003 12 : CXT_Text, pszName );
1004 :
1005 12 : CPLFree(pszName);
1006 : }
1007 :
1008 : /* -------------------------------------------------------------------- */
1009 : /* Source and Destination Data Source */
1010 : /* -------------------------------------------------------------------- */
1011 6 : if( psWO->hSrcDS != NULL )
1012 : {
1013 : CPLCreateXMLElementAndValue(
1014 : psTree, "SourceDataset",
1015 6 : GDALGetDescription( psWO->hSrcDS ) );
1016 : }
1017 :
1018 6 : if( psWO->hDstDS != NULL && strlen(GDALGetDescription(psWO->hDstDS)) != 0 )
1019 : {
1020 : CPLCreateXMLElementAndValue(
1021 : psTree, "DestinationDataset",
1022 0 : GDALGetDescription( psWO->hDstDS ) );
1023 : }
1024 :
1025 : /* -------------------------------------------------------------------- */
1026 : /* Serialize transformer. */
1027 : /* -------------------------------------------------------------------- */
1028 6 : if( psWO->pfnTransformer != NULL )
1029 : {
1030 : CPLXMLNode *psTransformerContainer;
1031 : CPLXMLNode *psTransformerTree;
1032 :
1033 : psTransformerContainer =
1034 6 : CPLCreateXMLNode( psTree, CXT_Element, "Transformer" );
1035 :
1036 : psTransformerTree =
1037 : GDALSerializeTransformer( psWO->pfnTransformer,
1038 6 : psWO->pTransformerArg );
1039 :
1040 6 : if( psTransformerTree != NULL )
1041 6 : CPLAddXMLChild( psTransformerContainer, psTransformerTree );
1042 : }
1043 :
1044 : /* -------------------------------------------------------------------- */
1045 : /* Band count and lists. */
1046 : /* -------------------------------------------------------------------- */
1047 6 : CPLXMLNode *psBandList = NULL;
1048 : int i;
1049 :
1050 6 : if( psWO->nBandCount != 0 )
1051 6 : psBandList = CPLCreateXMLNode( psTree, CXT_Element, "BandList" );
1052 :
1053 21 : for( i = 0; i < psWO->nBandCount; i++ )
1054 : {
1055 : CPLXMLNode *psBand;
1056 :
1057 15 : psBand = CPLCreateXMLNode( psBandList, CXT_Element, "BandMapping" );
1058 15 : if( psWO->panSrcBands != NULL )
1059 : CPLCreateXMLNode(
1060 : CPLCreateXMLNode( psBand, CXT_Attribute, "src" ),
1061 15 : CXT_Text, CPLString().Printf( "%d", psWO->panSrcBands[i] ) );
1062 15 : if( psWO->panDstBands != NULL )
1063 : CPLCreateXMLNode(
1064 : CPLCreateXMLNode( psBand, CXT_Attribute, "dst" ),
1065 15 : CXT_Text, CPLString().Printf( "%d", psWO->panDstBands[i] ) );
1066 :
1067 15 : if( psWO->padfSrcNoDataReal != NULL )
1068 : {
1069 8 : if (CPLIsNan(psWO->padfSrcNoDataReal[i]))
1070 0 : CPLCreateXMLElementAndValue(psBand, "SrcNoDataReal", "nan");
1071 : else
1072 : CPLCreateXMLElementAndValue(
1073 : psBand, "SrcNoDataReal",
1074 8 : CPLString().Printf( "%.16g", psWO->padfSrcNoDataReal[i] ) );
1075 : }
1076 :
1077 15 : if( psWO->padfSrcNoDataImag != NULL )
1078 : {
1079 8 : if (CPLIsNan(psWO->padfSrcNoDataImag[i]))
1080 0 : CPLCreateXMLElementAndValue(psBand, "SrcNoDataImag", "nan");
1081 : else
1082 : CPLCreateXMLElementAndValue(
1083 : psBand, "SrcNoDataImag",
1084 8 : CPLString().Printf( "%.16g", psWO->padfSrcNoDataImag[i] ) );
1085 : }
1086 :
1087 15 : if( psWO->padfDstNoDataReal != NULL )
1088 : {
1089 0 : if (CPLIsNan(psWO->padfDstNoDataReal[i]))
1090 0 : CPLCreateXMLElementAndValue(psBand, "DstNoDataReal", "nan");
1091 : else
1092 : CPLCreateXMLElementAndValue(
1093 : psBand, "DstNoDataReal",
1094 0 : CPLString().Printf( "%.16g", psWO->padfDstNoDataReal[i] ) );
1095 : }
1096 :
1097 15 : if( psWO->padfDstNoDataImag != NULL )
1098 : {
1099 0 : if (CPLIsNan(psWO->padfDstNoDataImag[i]))
1100 0 : CPLCreateXMLElementAndValue(psBand, "DstNoDataImag", "nan");
1101 : else
1102 : CPLCreateXMLElementAndValue(
1103 : psBand, "DstNoDataImag",
1104 0 : CPLString().Printf( "%.16g", psWO->padfDstNoDataImag[i] ) );
1105 : }
1106 : }
1107 :
1108 : /* -------------------------------------------------------------------- */
1109 : /* Alpha bands. */
1110 : /* -------------------------------------------------------------------- */
1111 6 : if( psWO->nSrcAlphaBand > 0 )
1112 : CPLCreateXMLElementAndValue(
1113 : psTree, "SrcAlphaBand",
1114 0 : CPLString().Printf( "%d", psWO->nSrcAlphaBand ) );
1115 :
1116 6 : if( psWO->nDstAlphaBand > 0 )
1117 : CPLCreateXMLElementAndValue(
1118 : psTree, "DstAlphaBand",
1119 0 : CPLString().Printf( "%d", psWO->nDstAlphaBand ) );
1120 :
1121 : /* -------------------------------------------------------------------- */
1122 : /* Cutline. */
1123 : /* -------------------------------------------------------------------- */
1124 6 : if( psWO->hCutline != NULL )
1125 : {
1126 0 : char *pszWKT = NULL;
1127 0 : if( OGR_G_ExportToWkt( (OGRGeometryH) psWO->hCutline, &pszWKT )
1128 : == OGRERR_NONE )
1129 : {
1130 0 : CPLCreateXMLElementAndValue( psTree, "Cutline", pszWKT );
1131 0 : CPLFree( pszWKT );
1132 : }
1133 : }
1134 :
1135 6 : if( psWO->dfCutlineBlendDist != 0.0 )
1136 : CPLCreateXMLElementAndValue(
1137 : psTree, "CutlineBlendDist",
1138 0 : CPLString().Printf( "%.5g", psWO->dfCutlineBlendDist ) );
1139 :
1140 6 : return psTree;
1141 : }
1142 :
1143 : /************************************************************************/
1144 : /* GDALDeserializeWarpOptions() */
1145 : /************************************************************************/
1146 :
1147 45 : GDALWarpOptions * CPL_STDCALL GDALDeserializeWarpOptions( CPLXMLNode *psTree )
1148 :
1149 : {
1150 45 : CPLErrorReset();
1151 :
1152 : /* -------------------------------------------------------------------- */
1153 : /* Verify this is the right kind of object. */
1154 : /* -------------------------------------------------------------------- */
1155 45 : if( psTree == NULL || psTree->eType != CXT_Element
1156 : || !EQUAL(psTree->pszValue,"GDALWarpOptions") )
1157 : {
1158 : CPLError( CE_Failure, CPLE_AppDefined,
1159 0 : "Wrong node, unable to deserialize GDALWarpOptions." );
1160 0 : return NULL;
1161 : }
1162 :
1163 : /* -------------------------------------------------------------------- */
1164 : /* Create pre-initialized warp options. */
1165 : /* -------------------------------------------------------------------- */
1166 45 : GDALWarpOptions *psWO = GDALCreateWarpOptions();
1167 :
1168 : /* -------------------------------------------------------------------- */
1169 : /* Warp memory limit. */
1170 : /* -------------------------------------------------------------------- */
1171 : psWO->dfWarpMemoryLimit =
1172 45 : atof(CPLGetXMLValue(psTree,"WarpMemoryLimit","0.0"));
1173 :
1174 : /* -------------------------------------------------------------------- */
1175 : /* resample algorithm */
1176 : /* -------------------------------------------------------------------- */
1177 : const char *pszValue =
1178 45 : CPLGetXMLValue(psTree,"ResampleAlg","Default");
1179 :
1180 45 : if( EQUAL(pszValue,"NearestNeighbour") )
1181 31 : psWO->eResampleAlg = GRA_NearestNeighbour;
1182 14 : else if( EQUAL(pszValue,"Bilinear") )
1183 4 : psWO->eResampleAlg = GRA_Bilinear;
1184 10 : else if( EQUAL(pszValue,"Cubic") )
1185 4 : psWO->eResampleAlg = GRA_Cubic;
1186 6 : else if( EQUAL(pszValue,"CubicSpline") )
1187 4 : psWO->eResampleAlg = GRA_CubicSpline;
1188 2 : else if( EQUAL(pszValue,"Lanczos") )
1189 2 : psWO->eResampleAlg = GRA_Lanczos;
1190 0 : else if( EQUAL(pszValue,"Default") )
1191 : /* leave as is */;
1192 : else
1193 : {
1194 : CPLError( CE_Failure, CPLE_AppDefined,
1195 : "Unrecognise ResampleAlg value '%s'.",
1196 0 : pszValue );
1197 : }
1198 :
1199 : /* -------------------------------------------------------------------- */
1200 : /* Working data type. */
1201 : /* -------------------------------------------------------------------- */
1202 : psWO->eWorkingDataType =
1203 : GDALGetDataTypeByName(
1204 45 : CPLGetXMLValue(psTree,"WorkingDataType","Unknown"));
1205 :
1206 : /* -------------------------------------------------------------------- */
1207 : /* Name/value warp options. */
1208 : /* -------------------------------------------------------------------- */
1209 : CPLXMLNode *psItem;
1210 :
1211 372 : for( psItem = psTree->psChild; psItem != NULL; psItem = psItem->psNext )
1212 : {
1213 327 : if( psItem->eType == CXT_Element
1214 : && EQUAL(psItem->pszValue,"Option") )
1215 : {
1216 37 : const char *pszName = CPLGetXMLValue(psItem, "Name", NULL );
1217 37 : const char *pszValue = CPLGetXMLValue(psItem, "", NULL );
1218 :
1219 37 : if( pszName != NULL && pszValue != NULL )
1220 : {
1221 : psWO->papszWarpOptions =
1222 : CSLSetNameValue( psWO->papszWarpOptions,
1223 37 : pszName, pszValue );
1224 : }
1225 : }
1226 : }
1227 :
1228 : /* -------------------------------------------------------------------- */
1229 : /* Source Dataset. */
1230 : /* -------------------------------------------------------------------- */
1231 45 : pszValue = CPLGetXMLValue(psTree,"SourceDataset",NULL);
1232 :
1233 45 : if( pszValue != NULL )
1234 45 : psWO->hSrcDS = GDALOpenShared( pszValue, GA_ReadOnly );
1235 :
1236 : /* -------------------------------------------------------------------- */
1237 : /* Destination Dataset. */
1238 : /* -------------------------------------------------------------------- */
1239 45 : pszValue = CPLGetXMLValue(psTree,"DestinationDataset",NULL);
1240 :
1241 45 : if( pszValue != NULL )
1242 0 : psWO->hDstDS = GDALOpenShared( pszValue, GA_Update );
1243 :
1244 : /* -------------------------------------------------------------------- */
1245 : /* First, count band mappings so we can establish the bandcount. */
1246 : /* -------------------------------------------------------------------- */
1247 45 : CPLXMLNode *psBandTree = CPLGetXMLNode( psTree, "BandList" );
1248 45 : CPLXMLNode *psBand = NULL;
1249 :
1250 45 : psWO->nBandCount = 0;
1251 :
1252 45 : if (psBandTree)
1253 45 : psBand = psBandTree->psChild;
1254 : else
1255 0 : psBand = NULL;
1256 :
1257 117 : for( ; psBand != NULL; psBand = psBand->psNext )
1258 : {
1259 72 : if( psBand->eType != CXT_Element
1260 : || !EQUAL(psBand->pszValue,"BandMapping") )
1261 0 : continue;
1262 :
1263 72 : psWO->nBandCount++;
1264 : }
1265 :
1266 : /* ==================================================================== */
1267 : /* Now actually process each bandmapping. */
1268 : /* ==================================================================== */
1269 45 : int iBand = 0;
1270 :
1271 45 : if (psBandTree)
1272 45 : psBand = psBandTree->psChild;
1273 : else
1274 0 : psBand = NULL;
1275 :
1276 117 : for( ; psBand != NULL; psBand = psBand->psNext )
1277 : {
1278 72 : if( psBand->eType != CXT_Element
1279 : || !EQUAL(psBand->pszValue,"BandMapping") )
1280 0 : continue;
1281 :
1282 : /* -------------------------------------------------------------------- */
1283 : /* Source band */
1284 : /* -------------------------------------------------------------------- */
1285 72 : if( psWO->panSrcBands == NULL )
1286 45 : psWO->panSrcBands = (int *)CPLMalloc(sizeof(int)*psWO->nBandCount);
1287 :
1288 72 : pszValue = CPLGetXMLValue(psBand,"src",NULL);
1289 72 : if( pszValue == NULL )
1290 0 : psWO->panSrcBands[iBand] = iBand+1;
1291 : else
1292 72 : psWO->panSrcBands[iBand] = atoi(pszValue);
1293 :
1294 : /* -------------------------------------------------------------------- */
1295 : /* Destination band. */
1296 : /* -------------------------------------------------------------------- */
1297 72 : pszValue = CPLGetXMLValue(psBand,"dst",NULL);
1298 72 : if( pszValue != NULL )
1299 : {
1300 72 : if( psWO->panDstBands == NULL )
1301 : psWO->panDstBands =
1302 45 : (int *) CPLMalloc(sizeof(int)*psWO->nBandCount);
1303 :
1304 72 : psWO->panDstBands[iBand] = atoi(pszValue);
1305 : }
1306 :
1307 : /* -------------------------------------------------------------------- */
1308 : /* Source nodata. */
1309 : /* -------------------------------------------------------------------- */
1310 72 : pszValue = CPLGetXMLValue(psBand,"SrcNoDataReal",NULL);
1311 72 : if( pszValue != NULL )
1312 : {
1313 16 : if( psWO->padfSrcNoDataReal == NULL )
1314 : psWO->padfSrcNoDataReal =
1315 9 : (double *) CPLCalloc(sizeof(double),psWO->nBandCount);
1316 :
1317 16 : psWO->padfSrcNoDataReal[iBand] = CPLAtofM(pszValue);
1318 : }
1319 :
1320 72 : pszValue = CPLGetXMLValue(psBand,"SrcNoDataImag",NULL);
1321 72 : if( pszValue != NULL )
1322 : {
1323 16 : if( psWO->padfSrcNoDataImag == NULL )
1324 : psWO->padfSrcNoDataImag =
1325 9 : (double *) CPLCalloc(sizeof(double),psWO->nBandCount);
1326 :
1327 16 : psWO->padfSrcNoDataImag[iBand] = CPLAtofM(pszValue);
1328 : }
1329 :
1330 : /* -------------------------------------------------------------------- */
1331 : /* Destination nodata. */
1332 : /* -------------------------------------------------------------------- */
1333 72 : pszValue = CPLGetXMLValue(psBand,"DstNoDataReal",NULL);
1334 72 : if( pszValue != NULL )
1335 : {
1336 8 : if( psWO->padfDstNoDataReal == NULL )
1337 : psWO->padfDstNoDataReal =
1338 8 : (double *) CPLCalloc(sizeof(double),psWO->nBandCount);
1339 :
1340 8 : psWO->padfDstNoDataReal[iBand] = CPLAtofM(pszValue);
1341 : }
1342 :
1343 72 : pszValue = CPLGetXMLValue(psBand,"DstNoDataImag",NULL);
1344 72 : if( pszValue != NULL )
1345 : {
1346 8 : if( psWO->padfDstNoDataImag == NULL )
1347 : psWO->padfDstNoDataImag =
1348 8 : (double *) CPLCalloc(sizeof(double),psWO->nBandCount);
1349 :
1350 8 : psWO->padfDstNoDataImag[iBand] = CPLAtofM(pszValue);
1351 : }
1352 :
1353 72 : iBand++;
1354 : }
1355 :
1356 : /* -------------------------------------------------------------------- */
1357 : /* Alpha bands. */
1358 : /* -------------------------------------------------------------------- */
1359 : psWO->nSrcAlphaBand =
1360 45 : atoi( CPLGetXMLValue( psTree, "SrcAlphaBand", "0" ) );
1361 : psWO->nDstAlphaBand =
1362 45 : atoi( CPLGetXMLValue( psTree, "DstAlphaBand", "0" ) );
1363 :
1364 : /* -------------------------------------------------------------------- */
1365 : /* Cutline. */
1366 : /* -------------------------------------------------------------------- */
1367 45 : const char *pszWKT = CPLGetXMLValue( psTree, "Cutline", NULL );
1368 45 : if( pszWKT )
1369 : {
1370 : OGR_G_CreateFromWkt( (char **) &pszWKT, NULL,
1371 3 : (OGRGeometryH *) (&psWO->hCutline) );
1372 : }
1373 :
1374 : psWO->dfCutlineBlendDist =
1375 45 : atof( CPLGetXMLValue( psTree, "CutlineBlendDist", "0" ) );
1376 :
1377 : /* -------------------------------------------------------------------- */
1378 : /* Transformation. */
1379 : /* -------------------------------------------------------------------- */
1380 45 : CPLXMLNode *psTransformer = CPLGetXMLNode( psTree, "Transformer" );
1381 :
1382 45 : if( psTransformer != NULL && psTransformer->psChild != NULL )
1383 : {
1384 : GDALDeserializeTransformer( psTransformer->psChild,
1385 : &(psWO->pfnTransformer),
1386 45 : &(psWO->pTransformerArg) );
1387 : }
1388 :
1389 : /* -------------------------------------------------------------------- */
1390 : /* If any error has occured, cleanup else return success. */
1391 : /* -------------------------------------------------------------------- */
1392 45 : if( CPLGetLastErrorNo() != CE_None )
1393 : {
1394 0 : if ( psWO->pTransformerArg )
1395 : {
1396 0 : GDALDestroyTransformer( psWO->pTransformerArg );
1397 0 : psWO->pTransformerArg = NULL;
1398 : }
1399 0 : if( psWO->hSrcDS != NULL )
1400 : {
1401 0 : GDALClose( psWO->hSrcDS );
1402 0 : psWO->hSrcDS = NULL;
1403 : }
1404 0 : if( psWO->hDstDS != NULL )
1405 : {
1406 0 : GDALClose( psWO->hDstDS );
1407 0 : psWO->hDstDS = NULL;
1408 : }
1409 0 : GDALDestroyWarpOptions( psWO );
1410 0 : return NULL;
1411 : }
1412 : else
1413 45 : return psWO;
1414 : }
|