1 : /******************************************************************************
2 : * $Id: gdal_translate.cpp 22783 2011-07-23 19:28:16Z rouault $
3 : *
4 : * Project: GDAL Utilities
5 : * Purpose: GDAL Image Translator Program
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1998, 2002, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_vsi.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include "gdal_priv.h"
34 : #include "ogr_spatialref.h"
35 : #include "vrt/vrtdataset.h"
36 : #include "commonutils.h"
37 :
38 : CPL_CVSID("$Id: gdal_translate.cpp 22783 2011-07-23 19:28:16Z rouault $");
39 :
40 : static int ArgIsNumeric( const char * );
41 : static void AttachMetadata( GDALDatasetH, char ** );
42 : static void CopyBandInfo( GDALRasterBand * poSrcBand, GDALRasterBand * poDstBand,
43 : int bCanCopyStatsMetadata, int bCopyScale, int bCopyNoData );
44 : static int bSubCall = FALSE;
45 :
46 : /* ******************************************************************* */
47 : /* Usage() */
48 : /* ******************************************************************** */
49 :
50 0 : static void Usage()
51 :
52 : {
53 : int iDr;
54 :
55 : printf( "Usage: gdal_translate [--help-general]\n"
56 : " [-ot {Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/\n"
57 : " CInt16/CInt32/CFloat32/CFloat64}] [-strict]\n"
58 : " [-of format] [-b band] [-mask band] [-expand {gray|rgb|rgba}]\n"
59 : " [-outsize xsize[%%] ysize[%%]]\n"
60 : " [-unscale] [-scale [src_min src_max [dst_min dst_max]]]\n"
61 : " [-srcwin xoff yoff xsize ysize] [-projwin ulx uly lrx lry]\n"
62 : " [-a_srs srs_def] [-a_ullr ulx uly lrx lry] [-a_nodata value]\n"
63 : " [-gcp pixel line easting northing [elevation]]*\n"
64 : " [-mo \"META-TAG=VALUE\"]* [-q] [-sds]\n"
65 : " [-co \"NAME=VALUE\"]* [-stats]\n"
66 0 : " src_dataset dst_dataset\n\n" );
67 :
68 0 : printf( "%s\n\n", GDALVersionInfo( "--version" ) );
69 0 : printf( "The following format drivers are configured and support output:\n" );
70 0 : for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
71 : {
72 0 : GDALDriverH hDriver = GDALGetDriver(iDr);
73 :
74 0 : if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
75 : || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY,
76 : NULL ) != NULL )
77 : {
78 : printf( " %s: %s\n",
79 : GDALGetDriverShortName( hDriver ),
80 0 : GDALGetDriverLongName( hDriver ) );
81 : }
82 : }
83 0 : }
84 :
85 : /************************************************************************/
86 : /* ProxyMain() */
87 : /************************************************************************/
88 :
89 : enum
90 : {
91 : MASK_DISABLED,
92 : MASK_AUTO,
93 : MASK_USER
94 : };
95 :
96 125 : static int ProxyMain( int argc, char ** argv )
97 :
98 : {
99 : GDALDatasetH hDataset, hOutDS;
100 : int i;
101 : int nRasterXSize, nRasterYSize;
102 125 : const char *pszSource=NULL, *pszDest=NULL, *pszFormat = "GTiff";
103 125 : int bFormatExplicitelySet = FALSE;
104 : GDALDriverH hDriver;
105 125 : int *panBandList = NULL; /* negative value of panBandList[i] means mask band of ABS(panBandList[i]) */
106 125 : int nBandCount = 0, bDefBands = TRUE;
107 : double adfGeoTransform[6];
108 125 : GDALDataType eOutputType = GDT_Unknown;
109 125 : int nOXSize = 0, nOYSize = 0;
110 125 : char *pszOXSize=NULL, *pszOYSize=NULL;
111 125 : char **papszCreateOptions = NULL;
112 125 : int anSrcWin[4], bStrict = FALSE;
113 : const char *pszProjection;
114 125 : int bScale = FALSE, bHaveScaleSrc = FALSE, bUnscale=FALSE;
115 125 : double dfScaleSrcMin=0.0, dfScaleSrcMax=255.0;
116 125 : double dfScaleDstMin=0.0, dfScaleDstMax=255.0;
117 : double dfULX, dfULY, dfLRX, dfLRY;
118 125 : char **papszMetadataOptions = NULL;
119 125 : char *pszOutputSRS = NULL;
120 125 : int bQuiet = FALSE, bGotBounds = FALSE;
121 125 : GDALProgressFunc pfnProgress = GDALTermProgress;
122 125 : int nGCPCount = 0;
123 125 : GDAL_GCP *pasGCPs = NULL;
124 125 : int iSrcFileArg = -1, iDstFileArg = -1;
125 125 : int bCopySubDatasets = FALSE;
126 125 : double adfULLR[4] = { 0,0,0,0 };
127 125 : int bSetNoData = FALSE;
128 125 : int bUnsetNoData = FALSE;
129 125 : double dfNoDataReal = 0.0;
130 125 : int nRGBExpand = 0;
131 125 : int bParsedMaskArgument = FALSE;
132 125 : int eMaskMode = MASK_AUTO;
133 125 : int nMaskBand = 0; /* negative value means mask band of ABS(nMaskBand) */
134 125 : int bStats = FALSE, bApproxStats = FALSE;
135 :
136 :
137 125 : anSrcWin[0] = 0;
138 125 : anSrcWin[1] = 0;
139 125 : anSrcWin[2] = 0;
140 125 : anSrcWin[3] = 0;
141 :
142 125 : dfULX = dfULY = dfLRX = dfLRY = 0.0;
143 :
144 : /* Check strict compilation and runtime library version as we use C++ API */
145 125 : if (! GDAL_CHECK_VERSION(argv[0]))
146 0 : exit(1);
147 :
148 : /* Must process GDAL_SKIP before GDALAllRegister(), but we can't call */
149 : /* GDALGeneralCmdLineProcessor before it needs the drivers to be registered */
150 : /* for the --format or --formats options */
151 741 : for( i = 1; i < argc; i++ )
152 : {
153 616 : if( EQUAL(argv[i],"--config") && i + 2 < argc && EQUAL(argv[i + 1], "GDAL_SKIP") )
154 : {
155 0 : CPLSetConfigOption( argv[i+1], argv[i+2] );
156 :
157 0 : i += 2;
158 : }
159 : }
160 :
161 : /* -------------------------------------------------------------------- */
162 : /* Register standard GDAL drivers, and process generic GDAL */
163 : /* command options. */
164 : /* -------------------------------------------------------------------- */
165 125 : GDALAllRegister();
166 125 : argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
167 125 : if( argc < 1 )
168 0 : exit( -argc );
169 :
170 : /* -------------------------------------------------------------------- */
171 : /* Handle command line arguments. */
172 : /* -------------------------------------------------------------------- */
173 528 : for( i = 1; i < argc; i++ )
174 : {
175 404 : if( EQUAL(argv[i], "--utility_version") )
176 : {
177 : printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
178 1 : argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
179 1 : return 0;
180 : }
181 477 : else if( EQUAL(argv[i],"-of") && i < argc-1 )
182 : {
183 74 : pszFormat = argv[++i];
184 74 : bFormatExplicitelySet = TRUE;
185 : }
186 :
187 329 : else if( EQUAL(argv[i],"-q") || EQUAL(argv[i],"-quiet") )
188 : {
189 0 : bQuiet = TRUE;
190 0 : pfnProgress = GDALDummyProgress;
191 : }
192 :
193 353 : else if( EQUAL(argv[i],"-ot") && i < argc-1 )
194 : {
195 : int iType;
196 :
197 288 : for( iType = 1; iType < GDT_TypeCount; iType++ )
198 : {
199 528 : if( GDALGetDataTypeName((GDALDataType)iType) != NULL
200 264 : && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
201 : argv[i+1]) )
202 : {
203 24 : eOutputType = (GDALDataType) iType;
204 : }
205 : }
206 :
207 24 : if( eOutputType == GDT_Unknown )
208 : {
209 0 : printf( "Unknown output pixel type: %s\n", argv[i+1] );
210 0 : Usage();
211 0 : GDALDestroyDriverManager();
212 0 : exit( 2 );
213 : }
214 24 : i++;
215 : }
216 321 : else if( EQUAL(argv[i],"-b") && i < argc-1 )
217 : {
218 16 : const char* pszBand = argv[i+1];
219 16 : int bMask = FALSE;
220 16 : if (EQUAL(pszBand, "mask"))
221 1 : pszBand = "mask,1";
222 16 : if (EQUALN(pszBand, "mask,", 5))
223 : {
224 1 : bMask = TRUE;
225 1 : pszBand += 5;
226 : /* If we use tha source mask band as a regular band */
227 : /* don't create a target mask band by default */
228 1 : if( !bParsedMaskArgument )
229 1 : eMaskMode = MASK_DISABLED;
230 : }
231 16 : int nBand = atoi(pszBand);
232 16 : if( nBand < 1 )
233 : {
234 0 : printf( "Unrecognizable band number (%s).\n", argv[i+1] );
235 0 : Usage();
236 0 : GDALDestroyDriverManager();
237 0 : exit( 2 );
238 : }
239 16 : i++;
240 :
241 16 : nBandCount++;
242 : panBandList = (int *)
243 16 : CPLRealloc(panBandList, sizeof(int) * nBandCount);
244 16 : panBandList[nBandCount-1] = nBand;
245 16 : if (bMask)
246 1 : panBandList[nBandCount-1] *= -1;
247 :
248 16 : if( panBandList[nBandCount-1] != nBandCount )
249 3 : bDefBands = FALSE;
250 : }
251 292 : else if( EQUAL(argv[i],"-mask") && i < argc-1 )
252 : {
253 3 : bParsedMaskArgument = TRUE;
254 3 : const char* pszBand = argv[i+1];
255 3 : if (EQUAL(pszBand, "none"))
256 : {
257 1 : eMaskMode = MASK_DISABLED;
258 : }
259 2 : else if (EQUAL(pszBand, "auto"))
260 : {
261 0 : eMaskMode = MASK_AUTO;
262 : }
263 : else
264 : {
265 2 : int bMask = FALSE;
266 2 : if (EQUAL(pszBand, "mask"))
267 0 : pszBand = "mask,1";
268 2 : if (EQUALN(pszBand, "mask,", 5))
269 : {
270 1 : bMask = TRUE;
271 1 : pszBand += 5;
272 : }
273 2 : int nBand = atoi(pszBand);
274 2 : if( nBand < 1 )
275 : {
276 0 : printf( "Unrecognizable band number (%s).\n", argv[i+1] );
277 0 : Usage();
278 0 : GDALDestroyDriverManager();
279 0 : exit( 2 );
280 : }
281 :
282 2 : eMaskMode = MASK_USER;
283 2 : nMaskBand = nBand;
284 2 : if (bMask)
285 1 : nMaskBand *= -1;
286 : }
287 3 : i ++;
288 : }
289 286 : else if( EQUAL(argv[i],"-not_strict") )
290 0 : bStrict = FALSE;
291 :
292 286 : else if( EQUAL(argv[i],"-strict") )
293 0 : bStrict = TRUE;
294 :
295 286 : else if( EQUAL(argv[i],"-sds") )
296 2 : bCopySubDatasets = TRUE;
297 :
298 296 : else if( EQUAL(argv[i],"-gcp") && i < argc - 4 )
299 : {
300 12 : char* endptr = NULL;
301 : /* -gcp pixel line easting northing [elev] */
302 :
303 12 : nGCPCount++;
304 : pasGCPs = (GDAL_GCP *)
305 12 : CPLRealloc( pasGCPs, sizeof(GDAL_GCP) * nGCPCount );
306 12 : GDALInitGCPs( 1, pasGCPs + nGCPCount - 1 );
307 :
308 12 : pasGCPs[nGCPCount-1].dfGCPPixel = CPLAtofM(argv[++i]);
309 12 : pasGCPs[nGCPCount-1].dfGCPLine = CPLAtofM(argv[++i]);
310 12 : pasGCPs[nGCPCount-1].dfGCPX = CPLAtofM(argv[++i]);
311 12 : pasGCPs[nGCPCount-1].dfGCPY = CPLAtofM(argv[++i]);
312 34 : if( argv[i+1] != NULL
313 22 : && (CPLStrtod(argv[i+1], &endptr) != 0.0 || argv[i+1][0] == '0') )
314 : {
315 : /* Check that last argument is really a number and not a filename */
316 : /* looking like a number (see ticket #863) */
317 2 : if (endptr && *endptr == 0)
318 2 : pasGCPs[nGCPCount-1].dfGCPZ = CPLAtofM(argv[++i]);
319 : }
320 :
321 : /* should set id and info? */
322 : }
323 :
324 275 : else if( EQUAL(argv[i],"-a_nodata") && i < argc - 1 )
325 : {
326 3 : if (EQUAL(argv[i+1], "none"))
327 : {
328 1 : bUnsetNoData = TRUE;
329 : }
330 : else
331 : {
332 2 : bSetNoData = TRUE;
333 2 : dfNoDataReal = CPLAtofM(argv[i+1]);
334 : }
335 3 : i += 1;
336 : }
337 :
338 270 : else if( EQUAL(argv[i],"-a_ullr") && i < argc - 4 )
339 : {
340 1 : adfULLR[0] = CPLAtofM(argv[i+1]);
341 1 : adfULLR[1] = CPLAtofM(argv[i+2]);
342 1 : adfULLR[2] = CPLAtofM(argv[i+3]);
343 1 : adfULLR[3] = CPLAtofM(argv[i+4]);
344 :
345 1 : bGotBounds = TRUE;
346 :
347 1 : i += 4;
348 : }
349 :
350 270 : else if( EQUAL(argv[i],"-co") && i < argc-1 )
351 : {
352 2 : papszCreateOptions = CSLAddString( papszCreateOptions, argv[++i] );
353 : }
354 :
355 266 : else if( EQUAL(argv[i],"-scale") )
356 : {
357 1 : bScale = TRUE;
358 1 : if( i < argc-2 && ArgIsNumeric(argv[i+1]) )
359 : {
360 1 : bHaveScaleSrc = TRUE;
361 1 : dfScaleSrcMin = CPLAtofM(argv[i+1]);
362 1 : dfScaleSrcMax = CPLAtofM(argv[i+2]);
363 1 : i += 2;
364 : }
365 1 : if( i < argc-2 && bHaveScaleSrc && ArgIsNumeric(argv[i+1]) )
366 : {
367 1 : dfScaleDstMin = CPLAtofM(argv[i+1]);
368 1 : dfScaleDstMax = CPLAtofM(argv[i+2]);
369 1 : i += 2;
370 : }
371 : else
372 : {
373 0 : dfScaleDstMin = 0.0;
374 0 : dfScaleDstMax = 255.999;
375 : }
376 : }
377 :
378 265 : else if( EQUAL(argv[i], "-unscale") )
379 : {
380 0 : bUnscale = TRUE;
381 : }
382 :
383 266 : else if( EQUAL(argv[i],"-mo") && i < argc-1 )
384 : {
385 : papszMetadataOptions = CSLAddString( papszMetadataOptions,
386 1 : argv[++i] );
387 : }
388 :
389 268 : else if( EQUAL(argv[i],"-outsize") && i < argc-2 )
390 : {
391 4 : pszOXSize = argv[++i];
392 4 : pszOYSize = argv[++i];
393 : }
394 :
395 263 : else if( EQUAL(argv[i],"-srcwin") && i < argc-4 )
396 : {
397 3 : anSrcWin[0] = atoi(argv[++i]);
398 3 : anSrcWin[1] = atoi(argv[++i]);
399 3 : anSrcWin[2] = atoi(argv[++i]);
400 3 : anSrcWin[3] = atoi(argv[++i]);
401 : }
402 :
403 258 : else if( EQUAL(argv[i],"-projwin") && i < argc-4 )
404 : {
405 1 : dfULX = CPLAtofM(argv[++i]);
406 1 : dfULY = CPLAtofM(argv[++i]);
407 1 : dfLRX = CPLAtofM(argv[++i]);
408 1 : dfLRY = CPLAtofM(argv[++i]);
409 : }
410 :
411 258 : else if( EQUAL(argv[i],"-a_srs") && i < argc-1 )
412 : {
413 2 : OGRSpatialReference oOutputSRS;
414 :
415 2 : if( oOutputSRS.SetFromUserInput( argv[i+1] ) != OGRERR_NONE )
416 : {
417 : fprintf( stderr, "Failed to process SRS definition: %s\n",
418 0 : argv[i+1] );
419 0 : GDALDestroyDriverManager();
420 0 : exit( 1 );
421 : }
422 :
423 2 : oOutputSRS.exportToWkt( &pszOutputSRS );
424 2 : i++;
425 : }
426 :
427 259 : else if( EQUAL(argv[i],"-expand") && i < argc-1 )
428 : {
429 5 : if (EQUAL(argv[i+1], "gray"))
430 1 : nRGBExpand = 1;
431 4 : else if (EQUAL(argv[i+1], "rgb"))
432 2 : nRGBExpand = 3;
433 2 : else if (EQUAL(argv[i+1], "rgba"))
434 2 : nRGBExpand = 4;
435 : else
436 : {
437 : printf( "Value %s unsupported. Only gray, rgb or rgba are supported.\n\n",
438 0 : argv[i] );
439 0 : Usage();
440 0 : GDALDestroyDriverManager();
441 0 : exit( 2 );
442 : }
443 5 : i++;
444 : }
445 :
446 249 : else if( EQUAL(argv[i], "-stats") )
447 : {
448 1 : bStats = TRUE;
449 1 : bApproxStats = FALSE;
450 : }
451 248 : else if( EQUAL(argv[i], "-approx_stats") )
452 : {
453 0 : bStats = TRUE;
454 0 : bApproxStats = TRUE;
455 : }
456 :
457 248 : else if( argv[i][0] == '-' )
458 : {
459 : printf( "Option %s incomplete, or not recognised.\n\n",
460 0 : argv[i] );
461 0 : Usage();
462 0 : GDALDestroyDriverManager();
463 0 : exit( 2 );
464 : }
465 248 : else if( pszSource == NULL )
466 : {
467 124 : iSrcFileArg = i;
468 124 : pszSource = argv[i];
469 : }
470 124 : else if( pszDest == NULL )
471 : {
472 124 : pszDest = argv[i];
473 124 : iDstFileArg = i;
474 : }
475 :
476 : else
477 : {
478 0 : printf( "Too many command options.\n\n" );
479 0 : Usage();
480 0 : GDALDestroyDriverManager();
481 0 : exit( 2 );
482 : }
483 : }
484 :
485 124 : if( pszDest == NULL )
486 : {
487 0 : Usage();
488 0 : GDALDestroyDriverManager();
489 0 : exit( 10 );
490 : }
491 :
492 124 : if ( strcmp(pszSource, pszDest) == 0)
493 : {
494 0 : fprintf(stderr, "Source and destination datasets must be different.\n");
495 0 : GDALDestroyDriverManager();
496 0 : exit( 1 );
497 : }
498 :
499 124 : if( strcmp(pszDest, "/vsistdout/") == 0)
500 : {
501 0 : bQuiet = TRUE;
502 0 : pfnProgress = GDALDummyProgress;
503 : }
504 :
505 124 : if (!bQuiet && !bFormatExplicitelySet)
506 51 : CheckExtensionConsistency(pszDest, pszFormat);
507 :
508 : /* -------------------------------------------------------------------- */
509 : /* Attempt to open source file. */
510 : /* -------------------------------------------------------------------- */
511 :
512 124 : hDataset = GDALOpenShared( pszSource, GA_ReadOnly );
513 :
514 124 : if( hDataset == NULL )
515 : {
516 : fprintf( stderr,
517 : "GDALOpen failed - %d\n%s\n",
518 0 : CPLGetLastErrorNo(), CPLGetLastErrorMsg() );
519 0 : GDALDestroyDriverManager();
520 0 : exit( 1 );
521 : }
522 :
523 : /* -------------------------------------------------------------------- */
524 : /* Handle subdatasets. */
525 : /* -------------------------------------------------------------------- */
526 124 : if( !bCopySubDatasets
527 : && CSLCount(GDALGetMetadata( hDataset, "SUBDATASETS" )) > 0
528 : && GDALGetRasterCount(hDataset) == 0 )
529 : {
530 : fprintf( stderr,
531 0 : "Input file contains subdatasets. Please, select one of them for reading.\n" );
532 0 : GDALClose( hDataset );
533 0 : GDALDestroyDriverManager();
534 0 : exit( 1 );
535 : }
536 :
537 124 : if( CSLCount(GDALGetMetadata( hDataset, "SUBDATASETS" )) > 0
538 : && bCopySubDatasets )
539 : {
540 1 : char **papszSubdatasets = GDALGetMetadata(hDataset,"SUBDATASETS");
541 1 : char *pszSubDest = (char *) CPLMalloc(strlen(pszDest)+32);
542 : int i;
543 1 : int bOldSubCall = bSubCall;
544 1 : char** papszDupArgv = CSLDuplicate(argv);
545 1 : int nRet = 0;
546 :
547 1 : CPLFree(papszDupArgv[iDstFileArg]);
548 1 : papszDupArgv[iDstFileArg] = pszSubDest;
549 1 : bSubCall = TRUE;
550 2 : for( i = 0; papszSubdatasets[i] != NULL; i += 2 )
551 : {
552 1 : CPLFree(papszDupArgv[iSrcFileArg]);
553 1 : papszDupArgv[iSrcFileArg] = CPLStrdup(strstr(papszSubdatasets[i],"=")+1);
554 1 : sprintf( pszSubDest, "%s%d", pszDest, i/2 + 1 );
555 1 : nRet = ProxyMain( argc, papszDupArgv );
556 1 : if (nRet != 0)
557 0 : break;
558 : }
559 1 : CSLDestroy(papszDupArgv);
560 :
561 1 : bSubCall = bOldSubCall;
562 1 : CSLDestroy(argv);
563 :
564 1 : GDALClose( hDataset );
565 :
566 1 : if( !bSubCall )
567 : {
568 1 : GDALDumpOpenDatasets( stderr );
569 1 : GDALDestroyDriverManager();
570 : }
571 1 : return nRet;
572 : }
573 :
574 : /* -------------------------------------------------------------------- */
575 : /* Collect some information from the source file. */
576 : /* -------------------------------------------------------------------- */
577 123 : nRasterXSize = GDALGetRasterXSize( hDataset );
578 123 : nRasterYSize = GDALGetRasterYSize( hDataset );
579 :
580 123 : if( !bQuiet )
581 123 : printf( "Input file size is %d, %d\n", nRasterXSize, nRasterYSize );
582 :
583 123 : if( anSrcWin[2] == 0 && anSrcWin[3] == 0 )
584 : {
585 120 : anSrcWin[2] = nRasterXSize;
586 120 : anSrcWin[3] = nRasterYSize;
587 : }
588 :
589 : /* -------------------------------------------------------------------- */
590 : /* Build band list to translate */
591 : /* -------------------------------------------------------------------- */
592 123 : if( nBandCount == 0 )
593 : {
594 118 : nBandCount = GDALGetRasterCount( hDataset );
595 118 : if( nBandCount == 0 )
596 : {
597 0 : fprintf( stderr, "Input file has no bands, and so cannot be translated.\n" );
598 0 : GDALDestroyDriverManager();
599 0 : exit(1 );
600 : }
601 :
602 118 : panBandList = (int *) CPLMalloc(sizeof(int)*nBandCount);
603 251 : for( i = 0; i < nBandCount; i++ )
604 133 : panBandList[i] = i+1;
605 : }
606 : else
607 : {
608 21 : for( i = 0; i < nBandCount; i++ )
609 : {
610 16 : if( ABS(panBandList[i]) > GDALGetRasterCount(hDataset) )
611 : {
612 : fprintf( stderr,
613 : "Band %d requested, but only bands 1 to %d available.\n",
614 0 : ABS(panBandList[i]), GDALGetRasterCount(hDataset) );
615 0 : GDALDestroyDriverManager();
616 0 : exit( 2 );
617 : }
618 : }
619 :
620 5 : if( nBandCount != GDALGetRasterCount( hDataset ) )
621 3 : bDefBands = FALSE;
622 : }
623 :
624 : /* -------------------------------------------------------------------- */
625 : /* Compute the source window from the projected source window */
626 : /* if the projected coordinates were provided. Note that the */
627 : /* projected coordinates are in ulx, uly, lrx, lry format, */
628 : /* while the anSrcWin is xoff, yoff, xsize, ysize with the */
629 : /* xoff,yoff being the ulx, uly in pixel/line. */
630 : /* -------------------------------------------------------------------- */
631 123 : if( dfULX != 0.0 || dfULY != 0.0
632 : || dfLRX != 0.0 || dfLRY != 0.0 )
633 : {
634 : double adfGeoTransform[6];
635 :
636 1 : GDALGetGeoTransform( hDataset, adfGeoTransform );
637 :
638 1 : if( adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0 )
639 : {
640 : fprintf( stderr,
641 : "The -projwin option was used, but the geotransform is\n"
642 0 : "rotated. This configuration is not supported.\n" );
643 0 : GDALClose( hDataset );
644 0 : CPLFree( panBandList );
645 0 : GDALDestroyDriverManager();
646 0 : exit( 1 );
647 : }
648 :
649 : anSrcWin[0] = (int)
650 1 : ((dfULX - adfGeoTransform[0]) / adfGeoTransform[1] + 0.001);
651 : anSrcWin[1] = (int)
652 1 : ((dfULY - adfGeoTransform[3]) / adfGeoTransform[5] + 0.001);
653 :
654 1 : anSrcWin[2] = (int) ((dfLRX - dfULX) / adfGeoTransform[1] + 0.5);
655 1 : anSrcWin[3] = (int) ((dfLRY - dfULY) / adfGeoTransform[5] + 0.5);
656 :
657 1 : if( !bQuiet )
658 : fprintf( stdout,
659 : "Computed -srcwin %d %d %d %d from projected window.\n",
660 : anSrcWin[0],
661 : anSrcWin[1],
662 : anSrcWin[2],
663 1 : anSrcWin[3] );
664 :
665 3 : if( anSrcWin[0] < 0 || anSrcWin[1] < 0
666 1 : || anSrcWin[0] + anSrcWin[2] > GDALGetRasterXSize(hDataset)
667 1 : || anSrcWin[1] + anSrcWin[3] > GDALGetRasterYSize(hDataset) )
668 : {
669 : fprintf( stderr,
670 : "Computed -srcwin falls outside raster size of %dx%d.\n",
671 : GDALGetRasterXSize(hDataset),
672 0 : GDALGetRasterYSize(hDataset) );
673 0 : exit( 1 );
674 : }
675 : }
676 :
677 : /* -------------------------------------------------------------------- */
678 : /* Verify source window. */
679 : /* -------------------------------------------------------------------- */
680 615 : if( anSrcWin[0] < 0 || anSrcWin[1] < 0
681 246 : || anSrcWin[2] <= 0 || anSrcWin[3] <= 0
682 123 : || anSrcWin[0] + anSrcWin[2] > GDALGetRasterXSize(hDataset)
683 123 : || anSrcWin[1] + anSrcWin[3] > GDALGetRasterYSize(hDataset) )
684 : {
685 : fprintf( stderr,
686 : "-srcwin %d %d %d %d falls outside raster size of %dx%d\n"
687 : "or is otherwise illegal.\n",
688 : anSrcWin[0],
689 : anSrcWin[1],
690 : anSrcWin[2],
691 : anSrcWin[3],
692 : GDALGetRasterXSize(hDataset),
693 0 : GDALGetRasterYSize(hDataset) );
694 0 : exit( 1 );
695 : }
696 :
697 : /* -------------------------------------------------------------------- */
698 : /* Find the output driver. */
699 : /* -------------------------------------------------------------------- */
700 123 : hDriver = GDALGetDriverByName( pszFormat );
701 123 : if( hDriver == NULL )
702 : {
703 : int iDr;
704 :
705 0 : printf( "Output driver `%s' not recognised.\n", pszFormat );
706 0 : printf( "The following format drivers are configured and support output:\n" );
707 0 : for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
708 : {
709 0 : GDALDriverH hDriver = GDALGetDriver(iDr);
710 :
711 0 : if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
712 : || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY,
713 : NULL ) != NULL )
714 : {
715 : printf( " %s: %s\n",
716 : GDALGetDriverShortName( hDriver ),
717 0 : GDALGetDriverLongName( hDriver ) );
718 : }
719 : }
720 0 : printf( "\n" );
721 0 : Usage();
722 :
723 0 : GDALClose( hDataset );
724 0 : CPLFree( panBandList );
725 0 : GDALDestroyDriverManager();
726 0 : CSLDestroy( argv );
727 0 : CSLDestroy( papszCreateOptions );
728 0 : exit( 1 );
729 : }
730 :
731 : /* -------------------------------------------------------------------- */
732 : /* The short form is to CreateCopy(). We use this if the input */
733 : /* matches the whole dataset. Eventually we should rewrite */
734 : /* this entire program to use virtual datasets to construct a */
735 : /* virtual input source to copy from. */
736 : /* -------------------------------------------------------------------- */
737 :
738 :
739 : int bSpatialArrangementPreserved = (
740 245 : anSrcWin[0] == 0 && anSrcWin[1] == 0
741 122 : && anSrcWin[2] == GDALGetRasterXSize(hDataset)
742 120 : && anSrcWin[3] == GDALGetRasterYSize(hDataset)
743 487 : && pszOXSize == NULL && pszOYSize == NULL );
744 :
745 123 : if( eOutputType == GDT_Unknown
746 : && !bScale && !bUnscale
747 : && CSLCount(papszMetadataOptions) == 0 && bDefBands
748 : && eMaskMode == MASK_AUTO
749 : && bSpatialArrangementPreserved
750 : && nGCPCount == 0 && !bGotBounds
751 : && pszOutputSRS == NULL && !bSetNoData && !bUnsetNoData
752 : && nRGBExpand == 0 && !bStats )
753 : {
754 :
755 : hOutDS = GDALCreateCopy( hDriver, pszDest, hDataset,
756 : bStrict, papszCreateOptions,
757 71 : pfnProgress, NULL );
758 :
759 71 : if( hOutDS != NULL )
760 10 : GDALClose( hOutDS );
761 :
762 71 : GDALClose( hDataset );
763 :
764 71 : CPLFree( panBandList );
765 :
766 71 : if( !bSubCall )
767 : {
768 70 : GDALDumpOpenDatasets( stderr );
769 70 : GDALDestroyDriverManager();
770 : }
771 :
772 71 : CSLDestroy( argv );
773 71 : CSLDestroy( papszCreateOptions );
774 :
775 71 : return hOutDS == NULL;
776 : }
777 :
778 : /* -------------------------------------------------------------------- */
779 : /* Establish some parameters. */
780 : /* -------------------------------------------------------------------- */
781 52 : if( pszOXSize == NULL )
782 : {
783 48 : nOXSize = anSrcWin[2];
784 48 : nOYSize = anSrcWin[3];
785 : }
786 : else
787 : {
788 4 : nOXSize = (int) ((pszOXSize[strlen(pszOXSize)-1]=='%'
789 8 : ? CPLAtofM(pszOXSize)/100*anSrcWin[2] : atoi(pszOXSize)));
790 4 : nOYSize = (int) ((pszOYSize[strlen(pszOYSize)-1]=='%'
791 8 : ? CPLAtofM(pszOYSize)/100*anSrcWin[3] : atoi(pszOYSize)));
792 : }
793 :
794 : /* ==================================================================== */
795 : /* Create a virtual dataset. */
796 : /* ==================================================================== */
797 : VRTDataset *poVDS;
798 :
799 : /* -------------------------------------------------------------------- */
800 : /* Make a virtual clone. */
801 : /* -------------------------------------------------------------------- */
802 52 : poVDS = (VRTDataset *) VRTCreate( nOXSize, nOYSize );
803 :
804 52 : if( nGCPCount == 0 )
805 : {
806 49 : if( pszOutputSRS != NULL )
807 : {
808 0 : poVDS->SetProjection( pszOutputSRS );
809 : }
810 : else
811 : {
812 49 : pszProjection = GDALGetProjectionRef( hDataset );
813 49 : if( pszProjection != NULL && strlen(pszProjection) > 0 )
814 43 : poVDS->SetProjection( pszProjection );
815 : }
816 : }
817 :
818 52 : if( bGotBounds )
819 : {
820 1 : adfGeoTransform[0] = adfULLR[0];
821 1 : adfGeoTransform[1] = (adfULLR[2] - adfULLR[0]) / nOXSize;
822 1 : adfGeoTransform[2] = 0.0;
823 1 : adfGeoTransform[3] = adfULLR[1];
824 1 : adfGeoTransform[4] = 0.0;
825 1 : adfGeoTransform[5] = (adfULLR[3] - adfULLR[1]) / nOYSize;
826 :
827 1 : poVDS->SetGeoTransform( adfGeoTransform );
828 : }
829 :
830 51 : else if( GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None
831 : && nGCPCount == 0 )
832 : {
833 86 : adfGeoTransform[0] += anSrcWin[0] * adfGeoTransform[1]
834 129 : + anSrcWin[1] * adfGeoTransform[2];
835 86 : adfGeoTransform[3] += anSrcWin[0] * adfGeoTransform[4]
836 129 : + anSrcWin[1] * adfGeoTransform[5];
837 :
838 43 : adfGeoTransform[1] *= anSrcWin[2] / (double) nOXSize;
839 43 : adfGeoTransform[2] *= anSrcWin[3] / (double) nOYSize;
840 43 : adfGeoTransform[4] *= anSrcWin[2] / (double) nOXSize;
841 43 : adfGeoTransform[5] *= anSrcWin[3] / (double) nOYSize;
842 :
843 43 : poVDS->SetGeoTransform( adfGeoTransform );
844 : }
845 :
846 52 : if( nGCPCount != 0 )
847 : {
848 3 : const char *pszGCPProjection = pszOutputSRS;
849 :
850 3 : if( pszGCPProjection == NULL )
851 1 : pszGCPProjection = GDALGetGCPProjection( hDataset );
852 3 : if( pszGCPProjection == NULL )
853 0 : pszGCPProjection = "";
854 :
855 3 : poVDS->SetGCPs( nGCPCount, pasGCPs, pszGCPProjection );
856 :
857 3 : GDALDeinitGCPs( nGCPCount, pasGCPs );
858 3 : CPLFree( pasGCPs );
859 : }
860 :
861 49 : else if( GDALGetGCPCount( hDataset ) > 0 )
862 : {
863 : GDAL_GCP *pasGCPs;
864 0 : int nGCPs = GDALGetGCPCount( hDataset );
865 :
866 0 : pasGCPs = GDALDuplicateGCPs( nGCPs, GDALGetGCPs( hDataset ) );
867 :
868 0 : for( i = 0; i < nGCPs; i++ )
869 : {
870 0 : pasGCPs[i].dfGCPPixel -= anSrcWin[0];
871 0 : pasGCPs[i].dfGCPLine -= anSrcWin[1];
872 0 : pasGCPs[i].dfGCPPixel *= (nOXSize / (double) anSrcWin[2] );
873 0 : pasGCPs[i].dfGCPLine *= (nOYSize / (double) anSrcWin[3] );
874 : }
875 :
876 : poVDS->SetGCPs( nGCPs, pasGCPs,
877 0 : GDALGetGCPProjection( hDataset ) );
878 :
879 0 : GDALDeinitGCPs( nGCPs, pasGCPs );
880 0 : CPLFree( pasGCPs );
881 : }
882 :
883 : /* -------------------------------------------------------------------- */
884 : /* Transfer generally applicable metadata. */
885 : /* -------------------------------------------------------------------- */
886 52 : char** papszMetadata = CSLDuplicate(((GDALDataset*)hDataset)->GetMetadata());
887 52 : if ( bScale || bUnscale || eOutputType != GDT_Unknown )
888 : {
889 : /* Remove TIFFTAG_MINSAMPLEVALUE and TIFFTAG_MAXSAMPLEVALUE */
890 : /* if the data range may change because of options */
891 25 : char** papszIter = papszMetadata;
892 96 : while(papszIter && *papszIter)
893 : {
894 46 : if (EQUALN(*papszIter, "TIFFTAG_MINSAMPLEVALUE=", 23) ||
895 : EQUALN(*papszIter, "TIFFTAG_MAXSAMPLEVALUE=", 23))
896 : {
897 0 : CPLFree(*papszIter);
898 0 : memmove(papszIter, papszIter+1, sizeof(char*) * (CSLCount(papszIter+1)+1));
899 : }
900 : else
901 46 : papszIter++;
902 : }
903 : }
904 52 : poVDS->SetMetadata( papszMetadata );
905 52 : CSLDestroy( papszMetadata );
906 52 : AttachMetadata( (GDALDatasetH) poVDS, papszMetadataOptions );
907 :
908 52 : const char* pszInterleave = GDALGetMetadataItem(hDataset, "INTERLEAVE", "IMAGE_STRUCTURE");
909 52 : if (pszInterleave)
910 47 : poVDS->SetMetadataItem("INTERLEAVE", pszInterleave, "IMAGE_STRUCTURE");
911 :
912 : /* -------------------------------------------------------------------- */
913 : /* Transfer metadata that remains valid if the spatial */
914 : /* arrangement of the data is unaltered. */
915 : /* -------------------------------------------------------------------- */
916 52 : if( bSpatialArrangementPreserved )
917 : {
918 : char **papszMD;
919 :
920 45 : papszMD = ((GDALDataset*)hDataset)->GetMetadata("RPC");
921 45 : if( papszMD != NULL )
922 0 : poVDS->SetMetadata( papszMD, "RPC" );
923 :
924 45 : papszMD = ((GDALDataset*)hDataset)->GetMetadata("GEOLOCATION");
925 45 : if( papszMD != NULL )
926 0 : poVDS->SetMetadata( papszMD, "GEOLOCATION" );
927 : }
928 :
929 52 : int nSrcBandCount = nBandCount;
930 :
931 52 : if (nRGBExpand != 0)
932 : {
933 : GDALRasterBand *poSrcBand;
934 : poSrcBand = ((GDALDataset *)
935 5 : hDataset)->GetRasterBand(ABS(panBandList[0]));
936 5 : if (panBandList[0] < 0)
937 0 : poSrcBand = poSrcBand->GetMaskBand();
938 5 : GDALColorTable* poColorTable = poSrcBand->GetColorTable();
939 5 : if (poColorTable == NULL)
940 : {
941 0 : fprintf(stderr, "Error : band %d has no color table\n", ABS(panBandList[0]));
942 0 : GDALClose( hDataset );
943 0 : CPLFree( panBandList );
944 0 : GDALDestroyDriverManager();
945 0 : CSLDestroy( argv );
946 0 : CSLDestroy( papszCreateOptions );
947 0 : exit( 1 );
948 : }
949 :
950 : /* Check that the color table only contains gray levels */
951 : /* when using -expand gray */
952 5 : if (nRGBExpand == 1)
953 : {
954 1 : int nColorCount = poColorTable->GetColorEntryCount();
955 : int nColor;
956 3 : for( nColor = 0; nColor < nColorCount; nColor++ )
957 : {
958 2 : const GDALColorEntry* poEntry = poColorTable->GetColorEntry(nColor);
959 2 : if (poEntry->c1 != poEntry->c2 || poEntry->c1 != poEntry->c2)
960 : {
961 0 : fprintf(stderr, "Warning : color table contains non gray levels colors\n");
962 0 : break;
963 : }
964 : }
965 : }
966 :
967 5 : if (nBandCount == 1)
968 4 : nBandCount = nRGBExpand;
969 2 : else if (nBandCount == 2 && (nRGBExpand == 3 || nRGBExpand == 4))
970 1 : nBandCount = nRGBExpand;
971 : else
972 : {
973 0 : fprintf(stderr, "Error : invalid use of -expand option.\n");
974 0 : exit( 1 );
975 : }
976 : }
977 :
978 : int bFilterOutStatsMetadata =
979 52 : (bScale || bUnscale || !bSpatialArrangementPreserved || nRGBExpand != 0);
980 :
981 : /* ==================================================================== */
982 : /* Process all bands. */
983 : /* ==================================================================== */
984 131 : for( i = 0; i < nBandCount; i++ )
985 : {
986 : VRTSourcedRasterBand *poVRTBand;
987 : GDALRasterBand *poSrcBand;
988 : GDALDataType eBandType;
989 79 : int nComponent = 0;
990 :
991 : int nSrcBand;
992 79 : if (nRGBExpand != 0)
993 : {
994 16 : if (nSrcBandCount == 2 && nRGBExpand == 4 && i == 3)
995 1 : nSrcBand = panBandList[1];
996 : else
997 : {
998 14 : nSrcBand = panBandList[0];
999 14 : nComponent = i + 1;
1000 : }
1001 : }
1002 : else
1003 64 : nSrcBand = panBandList[i];
1004 :
1005 79 : poSrcBand = ((GDALDataset *) hDataset)->GetRasterBand(ABS(nSrcBand));
1006 :
1007 : /* -------------------------------------------------------------------- */
1008 : /* Select output data type to match source. */
1009 : /* -------------------------------------------------------------------- */
1010 79 : if( eOutputType == GDT_Unknown )
1011 55 : eBandType = poSrcBand->GetRasterDataType();
1012 : else
1013 24 : eBandType = eOutputType;
1014 :
1015 : /* -------------------------------------------------------------------- */
1016 : /* Create this band. */
1017 : /* -------------------------------------------------------------------- */
1018 79 : poVDS->AddBand( eBandType, NULL );
1019 79 : poVRTBand = (VRTSourcedRasterBand *) poVDS->GetRasterBand( i+1 );
1020 79 : if (nSrcBand < 0)
1021 : {
1022 1 : poVRTBand->AddMaskBandSource(poSrcBand);
1023 1 : continue;
1024 : }
1025 :
1026 : /* -------------------------------------------------------------------- */
1027 : /* Do we need to collect scaling information? */
1028 : /* -------------------------------------------------------------------- */
1029 78 : double dfScale=1.0, dfOffset=0.0;
1030 :
1031 78 : if( bScale && !bHaveScaleSrc )
1032 : {
1033 : double adfCMinMax[2];
1034 0 : GDALComputeRasterMinMax( poSrcBand, TRUE, adfCMinMax );
1035 0 : dfScaleSrcMin = adfCMinMax[0];
1036 0 : dfScaleSrcMax = adfCMinMax[1];
1037 : }
1038 :
1039 78 : if( bScale )
1040 : {
1041 1 : if( dfScaleSrcMax == dfScaleSrcMin )
1042 0 : dfScaleSrcMax += 0.1;
1043 1 : if( dfScaleDstMax == dfScaleDstMin )
1044 0 : dfScaleDstMax += 0.1;
1045 :
1046 : dfScale = (dfScaleDstMax - dfScaleDstMin)
1047 1 : / (dfScaleSrcMax - dfScaleSrcMin);
1048 1 : dfOffset = -1 * dfScaleSrcMin * dfScale + dfScaleDstMin;
1049 : }
1050 :
1051 78 : if( bUnscale )
1052 : {
1053 0 : dfScale = poSrcBand->GetScale();
1054 0 : dfOffset = poSrcBand->GetOffset();
1055 : }
1056 :
1057 : /* -------------------------------------------------------------------- */
1058 : /* Create a simple or complex data source depending on the */
1059 : /* translation type required. */
1060 : /* -------------------------------------------------------------------- */
1061 94 : if( bUnscale || bScale || (nRGBExpand != 0 && i < nRGBExpand) )
1062 : {
1063 : poVRTBand->AddComplexSource( poSrcBand,
1064 : anSrcWin[0], anSrcWin[1],
1065 : anSrcWin[2], anSrcWin[3],
1066 : 0, 0, nOXSize, nOYSize,
1067 : dfOffset, dfScale,
1068 : VRT_NODATA_UNSET,
1069 16 : nComponent );
1070 : }
1071 : else
1072 : poVRTBand->AddSimpleSource( poSrcBand,
1073 : anSrcWin[0], anSrcWin[1],
1074 : anSrcWin[2], anSrcWin[3],
1075 62 : 0, 0, nOXSize, nOYSize );
1076 :
1077 : /* -------------------------------------------------------------------- */
1078 : /* In case of color table translate, we only set the color */
1079 : /* interpretation other info copied by CopyBandInfo are */
1080 : /* not relevant in RGB expansion. */
1081 : /* -------------------------------------------------------------------- */
1082 78 : if (nRGBExpand == 1)
1083 : {
1084 1 : poVRTBand->SetColorInterpretation( GCI_GrayIndex );
1085 : }
1086 91 : else if (nRGBExpand != 0 && i < nRGBExpand)
1087 : {
1088 14 : poVRTBand->SetColorInterpretation( (GDALColorInterp) (GCI_RedBand + i) );
1089 : }
1090 :
1091 : /* -------------------------------------------------------------------- */
1092 : /* copy over some other information of interest. */
1093 : /* -------------------------------------------------------------------- */
1094 : else
1095 : {
1096 : CopyBandInfo( poSrcBand, poVRTBand,
1097 : !bStats && !bFilterOutStatsMetadata,
1098 : !bUnscale,
1099 63 : !bSetNoData && !bUnsetNoData );
1100 : }
1101 :
1102 : /* -------------------------------------------------------------------- */
1103 : /* Set a forcable nodata value? */
1104 : /* -------------------------------------------------------------------- */
1105 78 : if( bSetNoData )
1106 : {
1107 2 : double dfVal = dfNoDataReal;
1108 2 : int bClamped = FALSE, bRounded = FALSE;
1109 :
1110 : #define CLAMP(val,type,minval,maxval) \
1111 : do { if (val < minval) { bClamped = TRUE; val = minval; } \
1112 : else if (val > maxval) { bClamped = TRUE; val = maxval; } \
1113 : else if (val != (type)val) { bRounded = TRUE; val = (type)(val + 0.5); } } \
1114 : while(0)
1115 :
1116 2 : switch(eBandType)
1117 : {
1118 : case GDT_Byte:
1119 2 : CLAMP(dfVal, GByte, 0.0, 255.0);
1120 2 : break;
1121 : case GDT_Int16:
1122 0 : CLAMP(dfVal, GInt16, -32768.0, 32767.0);
1123 0 : break;
1124 : case GDT_UInt16:
1125 0 : CLAMP(dfVal, GUInt16, 0.0, 65535.0);
1126 0 : break;
1127 : case GDT_Int32:
1128 0 : CLAMP(dfVal, GInt32, -2147483648.0, 2147483647.0);
1129 0 : break;
1130 : case GDT_UInt32:
1131 0 : CLAMP(dfVal, GUInt32, 0.0, 4294967295.0);
1132 : break;
1133 : default:
1134 : break;
1135 : }
1136 :
1137 2 : if (bClamped)
1138 : {
1139 : printf( "for band %d, nodata value has been clamped "
1140 : "to %.0f, the original value being out of range.\n",
1141 0 : i + 1, dfVal);
1142 : }
1143 2 : else if(bRounded)
1144 : {
1145 : printf("for band %d, nodata value has been rounded "
1146 : "to %.0f, %s being an integer datatype.\n",
1147 : i + 1, dfVal,
1148 0 : GDALGetDataTypeName(eBandType));
1149 : }
1150 :
1151 2 : poVRTBand->SetNoDataValue( dfVal );
1152 : }
1153 :
1154 138 : if (eMaskMode == MASK_AUTO &&
1155 : (GDALGetMaskFlags(GDALGetRasterBand(hDataset, 1)) & GMF_PER_DATASET) == 0 &&
1156 60 : (poSrcBand->GetMaskFlags() & (GMF_ALL_VALID | GMF_NODATA)) == 0)
1157 : {
1158 0 : if (poVRTBand->CreateMaskBand(poSrcBand->GetMaskFlags()) == CE_None)
1159 : {
1160 : VRTSourcedRasterBand* hMaskVRTBand =
1161 0 : (VRTSourcedRasterBand*)poVRTBand->GetMaskBand();
1162 : hMaskVRTBand->AddMaskBandSource(poSrcBand,
1163 : anSrcWin[0], anSrcWin[1],
1164 : anSrcWin[2], anSrcWin[3],
1165 0 : 0, 0, nOXSize, nOYSize );
1166 : }
1167 : }
1168 : }
1169 :
1170 52 : if (eMaskMode == MASK_USER)
1171 : {
1172 : GDALRasterBand *poSrcBand =
1173 2 : (GDALRasterBand*)GDALGetRasterBand(hDataset, ABS(nMaskBand));
1174 2 : if (poSrcBand && poVDS->CreateMaskBand(GMF_PER_DATASET) == CE_None)
1175 : {
1176 : VRTSourcedRasterBand* hMaskVRTBand = (VRTSourcedRasterBand*)
1177 2 : GDALGetMaskBand(GDALGetRasterBand((GDALDatasetH)poVDS, 1));
1178 2 : if (nMaskBand > 0)
1179 : hMaskVRTBand->AddSimpleSource(poSrcBand,
1180 : anSrcWin[0], anSrcWin[1],
1181 : anSrcWin[2], anSrcWin[3],
1182 1 : 0, 0, nOXSize, nOYSize );
1183 : else
1184 : hMaskVRTBand->AddMaskBandSource(poSrcBand,
1185 : anSrcWin[0], anSrcWin[1],
1186 : anSrcWin[2], anSrcWin[3],
1187 1 : 0, 0, nOXSize, nOYSize );
1188 : }
1189 : }
1190 : else
1191 50 : if (eMaskMode == MASK_AUTO && nSrcBandCount > 0 &&
1192 : GDALGetMaskFlags(GDALGetRasterBand(hDataset, 1)) == GMF_PER_DATASET)
1193 : {
1194 1 : if (poVDS->CreateMaskBand(GMF_PER_DATASET) == CE_None)
1195 : {
1196 : VRTSourcedRasterBand* hMaskVRTBand = (VRTSourcedRasterBand*)
1197 1 : GDALGetMaskBand(GDALGetRasterBand((GDALDatasetH)poVDS, 1));
1198 : hMaskVRTBand->AddMaskBandSource((GDALRasterBand*)GDALGetRasterBand(hDataset, 1),
1199 : anSrcWin[0], anSrcWin[1],
1200 : anSrcWin[2], anSrcWin[3],
1201 1 : 0, 0, nOXSize, nOYSize );
1202 : }
1203 : }
1204 :
1205 : /* -------------------------------------------------------------------- */
1206 : /* Compute stats if required. */
1207 : /* -------------------------------------------------------------------- */
1208 52 : if (bStats)
1209 : {
1210 2 : for( i = 0; i < poVDS->GetRasterCount(); i++ )
1211 : {
1212 : double dfMin, dfMax, dfMean, dfStdDev;
1213 : poVDS->GetRasterBand(i+1)->ComputeStatistics( bApproxStats,
1214 1 : &dfMin, &dfMax, &dfMean, &dfStdDev, GDALDummyProgress, NULL );
1215 : }
1216 : }
1217 :
1218 : /* -------------------------------------------------------------------- */
1219 : /* Write to the output file using CopyCreate(). */
1220 : /* -------------------------------------------------------------------- */
1221 : hOutDS = GDALCreateCopy( hDriver, pszDest, (GDALDatasetH) poVDS,
1222 : bStrict, papszCreateOptions,
1223 52 : pfnProgress, NULL );
1224 52 : if( hOutDS != NULL )
1225 : {
1226 52 : int bHasGotErr = FALSE;
1227 52 : CPLErrorReset();
1228 52 : GDALFlushCache( hOutDS );
1229 52 : if (CPLGetLastErrorType() != CE_None)
1230 0 : bHasGotErr = TRUE;
1231 52 : GDALClose( hOutDS );
1232 52 : if (bHasGotErr)
1233 0 : hOutDS = NULL;
1234 : }
1235 :
1236 52 : GDALClose( (GDALDatasetH) poVDS );
1237 :
1238 52 : GDALClose( hDataset );
1239 :
1240 52 : CPLFree( panBandList );
1241 :
1242 52 : CPLFree( pszOutputSRS );
1243 :
1244 52 : if( !bSubCall )
1245 : {
1246 52 : GDALDumpOpenDatasets( stderr );
1247 52 : GDALDestroyDriverManager();
1248 : }
1249 :
1250 52 : CSLDestroy( argv );
1251 52 : CSLDestroy( papszCreateOptions );
1252 :
1253 52 : return hOutDS == NULL;
1254 : }
1255 :
1256 :
1257 : /************************************************************************/
1258 : /* ArgIsNumeric() */
1259 : /************************************************************************/
1260 :
1261 2 : int ArgIsNumeric( const char *pszArg )
1262 :
1263 : {
1264 2 : if( pszArg[0] == '-' )
1265 0 : pszArg++;
1266 :
1267 2 : if( *pszArg == '\0' )
1268 0 : return FALSE;
1269 :
1270 6 : while( *pszArg != '\0' )
1271 : {
1272 2 : if( (*pszArg < '0' || *pszArg > '9') && *pszArg != '.' )
1273 0 : return FALSE;
1274 2 : pszArg++;
1275 : }
1276 :
1277 2 : return TRUE;
1278 : }
1279 :
1280 : /************************************************************************/
1281 : /* AttachMetadata() */
1282 : /************************************************************************/
1283 :
1284 52 : static void AttachMetadata( GDALDatasetH hDS, char **papszMetadataOptions )
1285 :
1286 : {
1287 52 : int nCount = CSLCount(papszMetadataOptions);
1288 : int i;
1289 :
1290 53 : for( i = 0; i < nCount; i++ )
1291 : {
1292 1 : char *pszKey = NULL;
1293 : const char *pszValue;
1294 :
1295 1 : pszValue = CPLParseNameValue( papszMetadataOptions[i], &pszKey );
1296 1 : GDALSetMetadataItem(hDS,pszKey,pszValue,NULL);
1297 1 : CPLFree( pszKey );
1298 : }
1299 :
1300 52 : CSLDestroy( papszMetadataOptions );
1301 52 : }
1302 :
1303 : /************************************************************************/
1304 : /* CopyBandInfo() */
1305 : /************************************************************************/
1306 :
1307 : /* A bit of a clone of VRTRasterBand::CopyCommonInfoFrom(), but we need */
1308 : /* more and more custom behaviour in the context of gdal_translate ... */
1309 :
1310 63 : static void CopyBandInfo( GDALRasterBand * poSrcBand, GDALRasterBand * poDstBand,
1311 : int bCanCopyStatsMetadata, int bCopyScale, int bCopyNoData )
1312 :
1313 : {
1314 : int bSuccess;
1315 : double dfNoData;
1316 :
1317 63 : if (bCanCopyStatsMetadata)
1318 : {
1319 50 : poDstBand->SetMetadata( poSrcBand->GetMetadata() );
1320 : }
1321 : else
1322 : {
1323 13 : char** papszMetadata = poSrcBand->GetMetadata();
1324 13 : char** papszMetadataNew = NULL;
1325 27 : for( int i = 0; papszMetadata != NULL && papszMetadata[i] != NULL; i++ )
1326 : {
1327 14 : if (strncmp(papszMetadata[i], "STATISTICS_", 11) != 0)
1328 1 : papszMetadataNew = CSLAddString(papszMetadataNew, papszMetadata[i]);
1329 : }
1330 13 : poDstBand->SetMetadata( papszMetadataNew );
1331 13 : CSLDestroy(papszMetadataNew);
1332 : }
1333 :
1334 63 : poDstBand->SetColorTable( poSrcBand->GetColorTable() );
1335 63 : poDstBand->SetColorInterpretation(poSrcBand->GetColorInterpretation());
1336 63 : if( strlen(poSrcBand->GetDescription()) > 0 )
1337 1 : poDstBand->SetDescription( poSrcBand->GetDescription() );
1338 :
1339 63 : if (bCopyNoData)
1340 : {
1341 60 : dfNoData = poSrcBand->GetNoDataValue( &bSuccess );
1342 60 : if( bSuccess )
1343 1 : poDstBand->SetNoDataValue( dfNoData );
1344 : }
1345 :
1346 63 : if (bCopyScale)
1347 : {
1348 63 : poDstBand->SetOffset( poSrcBand->GetOffset() );
1349 63 : poDstBand->SetScale( poSrcBand->GetScale() );
1350 : }
1351 :
1352 63 : poDstBand->SetCategoryNames( poSrcBand->GetCategoryNames() );
1353 63 : if( !EQUAL(poSrcBand->GetUnitType(),"") )
1354 1 : poDstBand->SetUnitType( poSrcBand->GetUnitType() );
1355 63 : }
1356 :
1357 : /************************************************************************/
1358 : /* main() */
1359 : /************************************************************************/
1360 :
1361 124 : int main( int argc, char ** argv )
1362 :
1363 : {
1364 124 : return ProxyMain( argc, argv );
1365 : }
1366 :
1367 :
|