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 258 : static int ProxyMain( int argc, char ** argv )
97 :
98 : {
99 : GDALDatasetH hDataset, hOutDS;
100 : int i;
101 : int nRasterXSize, nRasterYSize;
102 258 : const char *pszSource=NULL, *pszDest=NULL, *pszFormat = "GTiff";
103 258 : int bFormatExplicitelySet = FALSE;
104 : GDALDriverH hDriver;
105 258 : int *panBandList = NULL; /* negative value of panBandList[i] means mask band of ABS(panBandList[i]) */
106 258 : int nBandCount = 0, bDefBands = TRUE;
107 : double adfGeoTransform[6];
108 258 : GDALDataType eOutputType = GDT_Unknown;
109 258 : int nOXSize = 0, nOYSize = 0;
110 258 : char *pszOXSize=NULL, *pszOYSize=NULL;
111 258 : char **papszCreateOptions = NULL;
112 258 : int anSrcWin[4], bStrict = FALSE;
113 : const char *pszProjection;
114 258 : int bScale = FALSE, bHaveScaleSrc = FALSE, bUnscale=FALSE;
115 258 : double dfScaleSrcMin=0.0, dfScaleSrcMax=255.0;
116 258 : double dfScaleDstMin=0.0, dfScaleDstMax=255.0;
117 : double dfULX, dfULY, dfLRX, dfLRY;
118 258 : char **papszMetadataOptions = NULL;
119 258 : char *pszOutputSRS = NULL;
120 258 : int bQuiet = FALSE, bGotBounds = FALSE;
121 258 : GDALProgressFunc pfnProgress = GDALTermProgress;
122 258 : int nGCPCount = 0;
123 258 : GDAL_GCP *pasGCPs = NULL;
124 258 : int iSrcFileArg = -1, iDstFileArg = -1;
125 258 : int bCopySubDatasets = FALSE;
126 258 : double adfULLR[4] = { 0,0,0,0 };
127 258 : int bSetNoData = FALSE;
128 258 : int bUnsetNoData = FALSE;
129 258 : double dfNoDataReal = 0.0;
130 258 : int nRGBExpand = 0;
131 258 : int bParsedMaskArgument = FALSE;
132 258 : int eMaskMode = MASK_AUTO;
133 258 : int nMaskBand = 0; /* negative value means mask band of ABS(nMaskBand) */
134 258 : int bStats = FALSE, bApproxStats = FALSE;
135 :
136 :
137 258 : anSrcWin[0] = 0;
138 258 : anSrcWin[1] = 0;
139 258 : anSrcWin[2] = 0;
140 258 : anSrcWin[3] = 0;
141 :
142 258 : dfULX = dfULY = dfLRX = dfLRY = 0.0;
143 :
144 : /* Check strict compilation and runtime library version as we use C++ API */
145 258 : 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 1522 : for( i = 1; i < argc; i++ )
152 : {
153 1264 : 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 258 : GDALAllRegister();
166 258 : argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
167 258 : if( argc < 1 )
168 0 : exit( -argc );
169 :
170 : /* -------------------------------------------------------------------- */
171 : /* Handle command line arguments. */
172 : /* -------------------------------------------------------------------- */
173 1088 : for( i = 1; i < argc; i++ )
174 : {
175 832 : if( EQUAL(argv[i], "--utility_version") )
176 : {
177 : printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
178 2 : argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
179 2 : return 0;
180 : }
181 986 : else if( EQUAL(argv[i],"-of") && i < argc-1 )
182 : {
183 156 : pszFormat = argv[++i];
184 156 : bFormatExplicitelySet = TRUE;
185 : }
186 :
187 674 : else if( EQUAL(argv[i],"-q") || EQUAL(argv[i],"-quiet") )
188 : {
189 0 : bQuiet = TRUE;
190 0 : pfnProgress = GDALDummyProgress;
191 : }
192 :
193 722 : else if( EQUAL(argv[i],"-ot") && i < argc-1 )
194 : {
195 : int iType;
196 :
197 576 : for( iType = 1; iType < GDT_TypeCount; iType++ )
198 : {
199 1056 : if( GDALGetDataTypeName((GDALDataType)iType) != NULL
200 528 : && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
201 : argv[i+1]) )
202 : {
203 48 : eOutputType = (GDALDataType) iType;
204 : }
205 : }
206 :
207 48 : 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 48 : i++;
215 : }
216 658 : else if( EQUAL(argv[i],"-b") && i < argc-1 )
217 : {
218 32 : const char* pszBand = argv[i+1];
219 32 : int bMask = FALSE;
220 32 : if (EQUAL(pszBand, "mask"))
221 2 : pszBand = "mask,1";
222 32 : if (EQUALN(pszBand, "mask,", 5))
223 : {
224 2 : bMask = TRUE;
225 2 : 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 2 : if( !bParsedMaskArgument )
229 2 : eMaskMode = MASK_DISABLED;
230 : }
231 32 : int nBand = atoi(pszBand);
232 32 : 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 32 : i++;
240 :
241 32 : nBandCount++;
242 : panBandList = (int *)
243 32 : CPLRealloc(panBandList, sizeof(int) * nBandCount);
244 32 : panBandList[nBandCount-1] = nBand;
245 32 : if (bMask)
246 2 : panBandList[nBandCount-1] *= -1;
247 :
248 32 : if( panBandList[nBandCount-1] != nBandCount )
249 6 : bDefBands = FALSE;
250 : }
251 600 : else if( EQUAL(argv[i],"-mask") && i < argc-1 )
252 : {
253 6 : bParsedMaskArgument = TRUE;
254 6 : const char* pszBand = argv[i+1];
255 6 : if (EQUAL(pszBand, "none"))
256 : {
257 2 : eMaskMode = MASK_DISABLED;
258 : }
259 4 : else if (EQUAL(pszBand, "auto"))
260 : {
261 0 : eMaskMode = MASK_AUTO;
262 : }
263 : else
264 : {
265 4 : int bMask = FALSE;
266 4 : if (EQUAL(pszBand, "mask"))
267 0 : pszBand = "mask,1";
268 4 : if (EQUALN(pszBand, "mask,", 5))
269 : {
270 2 : bMask = TRUE;
271 2 : pszBand += 5;
272 : }
273 4 : int nBand = atoi(pszBand);
274 4 : 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 4 : eMaskMode = MASK_USER;
283 4 : nMaskBand = nBand;
284 4 : if (bMask)
285 2 : nMaskBand *= -1;
286 : }
287 6 : i ++;
288 : }
289 588 : else if( EQUAL(argv[i],"-not_strict") )
290 0 : bStrict = FALSE;
291 :
292 588 : else if( EQUAL(argv[i],"-strict") )
293 0 : bStrict = TRUE;
294 :
295 588 : else if( EQUAL(argv[i],"-sds") )
296 4 : bCopySubDatasets = TRUE;
297 :
298 608 : else if( EQUAL(argv[i],"-gcp") && i < argc - 4 )
299 : {
300 24 : char* endptr = NULL;
301 : /* -gcp pixel line easting northing [elev] */
302 :
303 24 : nGCPCount++;
304 : pasGCPs = (GDAL_GCP *)
305 24 : CPLRealloc( pasGCPs, sizeof(GDAL_GCP) * nGCPCount );
306 24 : GDALInitGCPs( 1, pasGCPs + nGCPCount - 1 );
307 :
308 24 : pasGCPs[nGCPCount-1].dfGCPPixel = CPLAtofM(argv[++i]);
309 24 : pasGCPs[nGCPCount-1].dfGCPLine = CPLAtofM(argv[++i]);
310 24 : pasGCPs[nGCPCount-1].dfGCPX = CPLAtofM(argv[++i]);
311 24 : pasGCPs[nGCPCount-1].dfGCPY = CPLAtofM(argv[++i]);
312 68 : if( argv[i+1] != NULL
313 44 : && (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 4 : if (endptr && *endptr == 0)
318 4 : pasGCPs[nGCPCount-1].dfGCPZ = CPLAtofM(argv[++i]);
319 : }
320 :
321 : /* should set id and info? */
322 : }
323 :
324 566 : else if( EQUAL(argv[i],"-a_nodata") && i < argc - 1 )
325 : {
326 6 : if (EQUAL(argv[i+1], "none"))
327 : {
328 2 : bUnsetNoData = TRUE;
329 : }
330 : else
331 : {
332 4 : bSetNoData = TRUE;
333 4 : dfNoDataReal = CPLAtofM(argv[i+1]);
334 : }
335 6 : i += 1;
336 : }
337 :
338 556 : else if( EQUAL(argv[i],"-a_ullr") && i < argc - 4 )
339 : {
340 2 : adfULLR[0] = CPLAtofM(argv[i+1]);
341 2 : adfULLR[1] = CPLAtofM(argv[i+2]);
342 2 : adfULLR[2] = CPLAtofM(argv[i+3]);
343 2 : adfULLR[3] = CPLAtofM(argv[i+4]);
344 :
345 2 : bGotBounds = TRUE;
346 :
347 2 : i += 4;
348 : }
349 :
350 556 : else if( EQUAL(argv[i],"-co") && i < argc-1 )
351 : {
352 4 : papszCreateOptions = CSLAddString( papszCreateOptions, argv[++i] );
353 : }
354 :
355 548 : else if( EQUAL(argv[i],"-scale") )
356 : {
357 2 : bScale = TRUE;
358 2 : if( i < argc-2 && ArgIsNumeric(argv[i+1]) )
359 : {
360 2 : bHaveScaleSrc = TRUE;
361 2 : dfScaleSrcMin = CPLAtofM(argv[i+1]);
362 2 : dfScaleSrcMax = CPLAtofM(argv[i+2]);
363 2 : i += 2;
364 : }
365 2 : if( i < argc-2 && bHaveScaleSrc && ArgIsNumeric(argv[i+1]) )
366 : {
367 2 : dfScaleDstMin = CPLAtofM(argv[i+1]);
368 2 : dfScaleDstMax = CPLAtofM(argv[i+2]);
369 2 : i += 2;
370 : }
371 : else
372 : {
373 0 : dfScaleDstMin = 0.0;
374 0 : dfScaleDstMax = 255.999;
375 : }
376 : }
377 :
378 546 : else if( EQUAL(argv[i], "-unscale") )
379 : {
380 0 : bUnscale = TRUE;
381 : }
382 :
383 548 : else if( EQUAL(argv[i],"-mo") && i < argc-1 )
384 : {
385 : papszMetadataOptions = CSLAddString( papszMetadataOptions,
386 2 : argv[++i] );
387 : }
388 :
389 552 : else if( EQUAL(argv[i],"-outsize") && i < argc-2 )
390 : {
391 8 : pszOXSize = argv[++i];
392 8 : pszOYSize = argv[++i];
393 : }
394 :
395 542 : else if( EQUAL(argv[i],"-srcwin") && i < argc-4 )
396 : {
397 6 : anSrcWin[0] = atoi(argv[++i]);
398 6 : anSrcWin[1] = atoi(argv[++i]);
399 6 : anSrcWin[2] = atoi(argv[++i]);
400 6 : anSrcWin[3] = atoi(argv[++i]);
401 : }
402 :
403 532 : else if( EQUAL(argv[i],"-projwin") && i < argc-4 )
404 : {
405 2 : dfULX = CPLAtofM(argv[++i]);
406 2 : dfULY = CPLAtofM(argv[++i]);
407 2 : dfLRX = CPLAtofM(argv[++i]);
408 2 : dfLRY = CPLAtofM(argv[++i]);
409 : }
410 :
411 532 : else if( EQUAL(argv[i],"-a_srs") && i < argc-1 )
412 : {
413 4 : OGRSpatialReference oOutputSRS;
414 :
415 4 : 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 4 : oOutputSRS.exportToWkt( &pszOutputSRS );
424 4 : i++;
425 : }
426 :
427 534 : else if( EQUAL(argv[i],"-expand") && i < argc-1 )
428 : {
429 10 : if (EQUAL(argv[i+1], "gray"))
430 2 : nRGBExpand = 1;
431 8 : else if (EQUAL(argv[i+1], "rgb"))
432 4 : nRGBExpand = 3;
433 4 : else if (EQUAL(argv[i+1], "rgba"))
434 4 : 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 10 : i++;
444 : }
445 :
446 514 : else if( EQUAL(argv[i], "-stats") )
447 : {
448 2 : bStats = TRUE;
449 2 : bApproxStats = FALSE;
450 : }
451 512 : else if( EQUAL(argv[i], "-approx_stats") )
452 : {
453 0 : bStats = TRUE;
454 0 : bApproxStats = TRUE;
455 : }
456 :
457 512 : 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 512 : else if( pszSource == NULL )
466 : {
467 256 : iSrcFileArg = i;
468 256 : pszSource = argv[i];
469 : }
470 256 : else if( pszDest == NULL )
471 : {
472 256 : pszDest = argv[i];
473 256 : 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 256 : if( pszDest == NULL )
486 : {
487 0 : Usage();
488 0 : GDALDestroyDriverManager();
489 0 : exit( 10 );
490 : }
491 :
492 256 : 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 256 : if( strcmp(pszDest, "/vsistdout/") == 0)
500 : {
501 0 : bQuiet = TRUE;
502 0 : pfnProgress = GDALDummyProgress;
503 : }
504 :
505 256 : if (!bQuiet && !bFormatExplicitelySet)
506 102 : CheckExtensionConsistency(pszDest, pszFormat);
507 :
508 : /* -------------------------------------------------------------------- */
509 : /* Attempt to open source file. */
510 : /* -------------------------------------------------------------------- */
511 :
512 256 : hDataset = GDALOpenShared( pszSource, GA_ReadOnly );
513 :
514 256 : 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 256 : 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 256 : if( CSLCount(GDALGetMetadata( hDataset, "SUBDATASETS" )) > 0
538 : && bCopySubDatasets )
539 : {
540 2 : char **papszSubdatasets = GDALGetMetadata(hDataset,"SUBDATASETS");
541 2 : char *pszSubDest = (char *) CPLMalloc(strlen(pszDest)+32);
542 : int i;
543 2 : int bOldSubCall = bSubCall;
544 2 : char** papszDupArgv = CSLDuplicate(argv);
545 2 : int nRet = 0;
546 :
547 2 : CPLFree(papszDupArgv[iDstFileArg]);
548 2 : papszDupArgv[iDstFileArg] = pszSubDest;
549 2 : bSubCall = TRUE;
550 4 : for( i = 0; papszSubdatasets[i] != NULL; i += 2 )
551 : {
552 2 : CPLFree(papszDupArgv[iSrcFileArg]);
553 2 : papszDupArgv[iSrcFileArg] = CPLStrdup(strstr(papszSubdatasets[i],"=")+1);
554 2 : sprintf( pszSubDest, "%s%d", pszDest, i/2 + 1 );
555 2 : nRet = ProxyMain( argc, papszDupArgv );
556 2 : if (nRet != 0)
557 0 : break;
558 : }
559 2 : CSLDestroy(papszDupArgv);
560 :
561 2 : bSubCall = bOldSubCall;
562 2 : CSLDestroy(argv);
563 :
564 2 : GDALClose( hDataset );
565 :
566 2 : if( !bSubCall )
567 : {
568 2 : GDALDumpOpenDatasets( stderr );
569 2 : GDALDestroyDriverManager();
570 : }
571 2 : return nRet;
572 : }
573 :
574 : /* -------------------------------------------------------------------- */
575 : /* Collect some information from the source file. */
576 : /* -------------------------------------------------------------------- */
577 254 : nRasterXSize = GDALGetRasterXSize( hDataset );
578 254 : nRasterYSize = GDALGetRasterYSize( hDataset );
579 :
580 254 : if( !bQuiet )
581 254 : printf( "Input file size is %d, %d\n", nRasterXSize, nRasterYSize );
582 :
583 254 : if( anSrcWin[2] == 0 && anSrcWin[3] == 0 )
584 : {
585 248 : anSrcWin[2] = nRasterXSize;
586 248 : anSrcWin[3] = nRasterYSize;
587 : }
588 :
589 : /* -------------------------------------------------------------------- */
590 : /* Build band list to translate */
591 : /* -------------------------------------------------------------------- */
592 254 : if( nBandCount == 0 )
593 : {
594 244 : nBandCount = GDALGetRasterCount( hDataset );
595 244 : 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 244 : panBandList = (int *) CPLMalloc(sizeof(int)*nBandCount);
603 518 : for( i = 0; i < nBandCount; i++ )
604 274 : panBandList[i] = i+1;
605 : }
606 : else
607 : {
608 42 : for( i = 0; i < nBandCount; i++ )
609 : {
610 32 : 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 10 : if( nBandCount != GDALGetRasterCount( hDataset ) )
621 6 : 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 254 : if( dfULX != 0.0 || dfULY != 0.0
632 : || dfLRX != 0.0 || dfLRY != 0.0 )
633 : {
634 : double adfGeoTransform[6];
635 :
636 2 : GDALGetGeoTransform( hDataset, adfGeoTransform );
637 :
638 2 : 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 2 : ((dfULX - adfGeoTransform[0]) / adfGeoTransform[1] + 0.001);
651 : anSrcWin[1] = (int)
652 2 : ((dfULY - adfGeoTransform[3]) / adfGeoTransform[5] + 0.001);
653 :
654 2 : anSrcWin[2] = (int) ((dfLRX - dfULX) / adfGeoTransform[1] + 0.5);
655 2 : anSrcWin[3] = (int) ((dfLRY - dfULY) / adfGeoTransform[5] + 0.5);
656 :
657 2 : 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 2 : anSrcWin[3] );
664 :
665 6 : if( anSrcWin[0] < 0 || anSrcWin[1] < 0
666 2 : || anSrcWin[0] + anSrcWin[2] > GDALGetRasterXSize(hDataset)
667 2 : || 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 1270 : if( anSrcWin[0] < 0 || anSrcWin[1] < 0
681 508 : || anSrcWin[2] <= 0 || anSrcWin[3] <= 0
682 254 : || anSrcWin[0] + anSrcWin[2] > GDALGetRasterXSize(hDataset)
683 254 : || 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 254 : hDriver = GDALGetDriverByName( pszFormat );
701 254 : 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 506 : anSrcWin[0] == 0 && anSrcWin[1] == 0
741 252 : && anSrcWin[2] == GDALGetRasterXSize(hDataset)
742 248 : && anSrcWin[3] == GDALGetRasterYSize(hDataset)
743 1006 : && pszOXSize == NULL && pszOYSize == NULL );
744 :
745 254 : 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 150 : pfnProgress, NULL );
758 :
759 150 : if( hOutDS != NULL )
760 20 : GDALClose( hOutDS );
761 :
762 150 : GDALClose( hDataset );
763 :
764 150 : CPLFree( panBandList );
765 :
766 150 : if( !bSubCall )
767 : {
768 148 : GDALDumpOpenDatasets( stderr );
769 148 : GDALDestroyDriverManager();
770 : }
771 :
772 150 : CSLDestroy( argv );
773 150 : CSLDestroy( papszCreateOptions );
774 :
775 150 : return hOutDS == NULL;
776 : }
777 :
778 : /* -------------------------------------------------------------------- */
779 : /* Establish some parameters. */
780 : /* -------------------------------------------------------------------- */
781 104 : if( pszOXSize == NULL )
782 : {
783 96 : nOXSize = anSrcWin[2];
784 96 : nOYSize = anSrcWin[3];
785 : }
786 : else
787 : {
788 8 : nOXSize = (int) ((pszOXSize[strlen(pszOXSize)-1]=='%'
789 16 : ? CPLAtofM(pszOXSize)/100*anSrcWin[2] : atoi(pszOXSize)));
790 8 : nOYSize = (int) ((pszOYSize[strlen(pszOYSize)-1]=='%'
791 16 : ? 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 104 : poVDS = (VRTDataset *) VRTCreate( nOXSize, nOYSize );
803 :
804 104 : if( nGCPCount == 0 )
805 : {
806 98 : if( pszOutputSRS != NULL )
807 : {
808 0 : poVDS->SetProjection( pszOutputSRS );
809 : }
810 : else
811 : {
812 98 : pszProjection = GDALGetProjectionRef( hDataset );
813 98 : if( pszProjection != NULL && strlen(pszProjection) > 0 )
814 86 : poVDS->SetProjection( pszProjection );
815 : }
816 : }
817 :
818 104 : if( bGotBounds )
819 : {
820 2 : adfGeoTransform[0] = adfULLR[0];
821 2 : adfGeoTransform[1] = (adfULLR[2] - adfULLR[0]) / nOXSize;
822 2 : adfGeoTransform[2] = 0.0;
823 2 : adfGeoTransform[3] = adfULLR[1];
824 2 : adfGeoTransform[4] = 0.0;
825 2 : adfGeoTransform[5] = (adfULLR[3] - adfULLR[1]) / nOYSize;
826 :
827 2 : poVDS->SetGeoTransform( adfGeoTransform );
828 : }
829 :
830 102 : else if( GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None
831 : && nGCPCount == 0 )
832 : {
833 172 : adfGeoTransform[0] += anSrcWin[0] * adfGeoTransform[1]
834 258 : + anSrcWin[1] * adfGeoTransform[2];
835 172 : adfGeoTransform[3] += anSrcWin[0] * adfGeoTransform[4]
836 258 : + anSrcWin[1] * adfGeoTransform[5];
837 :
838 86 : adfGeoTransform[1] *= anSrcWin[2] / (double) nOXSize;
839 86 : adfGeoTransform[2] *= anSrcWin[3] / (double) nOYSize;
840 86 : adfGeoTransform[4] *= anSrcWin[2] / (double) nOXSize;
841 86 : adfGeoTransform[5] *= anSrcWin[3] / (double) nOYSize;
842 :
843 86 : poVDS->SetGeoTransform( adfGeoTransform );
844 : }
845 :
846 104 : if( nGCPCount != 0 )
847 : {
848 6 : const char *pszGCPProjection = pszOutputSRS;
849 :
850 6 : if( pszGCPProjection == NULL )
851 2 : pszGCPProjection = GDALGetGCPProjection( hDataset );
852 6 : if( pszGCPProjection == NULL )
853 0 : pszGCPProjection = "";
854 :
855 6 : poVDS->SetGCPs( nGCPCount, pasGCPs, pszGCPProjection );
856 :
857 6 : GDALDeinitGCPs( nGCPCount, pasGCPs );
858 6 : CPLFree( pasGCPs );
859 : }
860 :
861 98 : 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 104 : char** papszMetadata = CSLDuplicate(((GDALDataset*)hDataset)->GetMetadata());
887 104 : 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 50 : char** papszIter = papszMetadata;
892 192 : while(papszIter && *papszIter)
893 : {
894 92 : 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 92 : papszIter++;
902 : }
903 : }
904 104 : poVDS->SetMetadata( papszMetadata );
905 104 : CSLDestroy( papszMetadata );
906 104 : AttachMetadata( (GDALDatasetH) poVDS, papszMetadataOptions );
907 :
908 104 : const char* pszInterleave = GDALGetMetadataItem(hDataset, "INTERLEAVE", "IMAGE_STRUCTURE");
909 104 : if (pszInterleave)
910 94 : 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 104 : if( bSpatialArrangementPreserved )
917 : {
918 : char **papszMD;
919 :
920 90 : papszMD = ((GDALDataset*)hDataset)->GetMetadata("RPC");
921 90 : if( papszMD != NULL )
922 0 : poVDS->SetMetadata( papszMD, "RPC" );
923 :
924 90 : papszMD = ((GDALDataset*)hDataset)->GetMetadata("GEOLOCATION");
925 90 : if( papszMD != NULL )
926 0 : poVDS->SetMetadata( papszMD, "GEOLOCATION" );
927 : }
928 :
929 104 : int nSrcBandCount = nBandCount;
930 :
931 104 : if (nRGBExpand != 0)
932 : {
933 : GDALRasterBand *poSrcBand;
934 : poSrcBand = ((GDALDataset *)
935 10 : hDataset)->GetRasterBand(ABS(panBandList[0]));
936 10 : if (panBandList[0] < 0)
937 0 : poSrcBand = poSrcBand->GetMaskBand();
938 10 : GDALColorTable* poColorTable = poSrcBand->GetColorTable();
939 10 : 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 10 : if (nRGBExpand == 1)
953 : {
954 2 : int nColorCount = poColorTable->GetColorEntryCount();
955 : int nColor;
956 6 : for( nColor = 0; nColor < nColorCount; nColor++ )
957 : {
958 4 : const GDALColorEntry* poEntry = poColorTable->GetColorEntry(nColor);
959 4 : 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 10 : if (nBandCount == 1)
968 8 : nBandCount = nRGBExpand;
969 4 : else if (nBandCount == 2 && (nRGBExpand == 3 || nRGBExpand == 4))
970 2 : 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 104 : (bScale || bUnscale || !bSpatialArrangementPreserved || nRGBExpand != 0);
980 :
981 : /* ==================================================================== */
982 : /* Process all bands. */
983 : /* ==================================================================== */
984 262 : for( i = 0; i < nBandCount; i++ )
985 : {
986 : VRTSourcedRasterBand *poVRTBand;
987 : GDALRasterBand *poSrcBand;
988 : GDALDataType eBandType;
989 158 : int nComponent = 0;
990 :
991 : int nSrcBand;
992 158 : if (nRGBExpand != 0)
993 : {
994 32 : if (nSrcBandCount == 2 && nRGBExpand == 4 && i == 3)
995 2 : nSrcBand = panBandList[1];
996 : else
997 : {
998 28 : nSrcBand = panBandList[0];
999 28 : nComponent = i + 1;
1000 : }
1001 : }
1002 : else
1003 128 : nSrcBand = panBandList[i];
1004 :
1005 158 : poSrcBand = ((GDALDataset *) hDataset)->GetRasterBand(ABS(nSrcBand));
1006 :
1007 : /* -------------------------------------------------------------------- */
1008 : /* Select output data type to match source. */
1009 : /* -------------------------------------------------------------------- */
1010 158 : if( eOutputType == GDT_Unknown )
1011 110 : eBandType = poSrcBand->GetRasterDataType();
1012 : else
1013 48 : eBandType = eOutputType;
1014 :
1015 : /* -------------------------------------------------------------------- */
1016 : /* Create this band. */
1017 : /* -------------------------------------------------------------------- */
1018 158 : poVDS->AddBand( eBandType, NULL );
1019 158 : poVRTBand = (VRTSourcedRasterBand *) poVDS->GetRasterBand( i+1 );
1020 158 : if (nSrcBand < 0)
1021 : {
1022 2 : poVRTBand->AddMaskBandSource(poSrcBand);
1023 2 : continue;
1024 : }
1025 :
1026 : /* -------------------------------------------------------------------- */
1027 : /* Do we need to collect scaling information? */
1028 : /* -------------------------------------------------------------------- */
1029 156 : double dfScale=1.0, dfOffset=0.0;
1030 :
1031 156 : 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 156 : if( bScale )
1040 : {
1041 2 : if( dfScaleSrcMax == dfScaleSrcMin )
1042 0 : dfScaleSrcMax += 0.1;
1043 2 : if( dfScaleDstMax == dfScaleDstMin )
1044 0 : dfScaleDstMax += 0.1;
1045 :
1046 : dfScale = (dfScaleDstMax - dfScaleDstMin)
1047 2 : / (dfScaleSrcMax - dfScaleSrcMin);
1048 2 : dfOffset = -1 * dfScaleSrcMin * dfScale + dfScaleDstMin;
1049 : }
1050 :
1051 156 : 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 188 : 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 32 : nComponent );
1070 : }
1071 : else
1072 : poVRTBand->AddSimpleSource( poSrcBand,
1073 : anSrcWin[0], anSrcWin[1],
1074 : anSrcWin[2], anSrcWin[3],
1075 124 : 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 156 : if (nRGBExpand == 1)
1083 : {
1084 2 : poVRTBand->SetColorInterpretation( GCI_GrayIndex );
1085 : }
1086 182 : else if (nRGBExpand != 0 && i < nRGBExpand)
1087 : {
1088 28 : 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 126 : !bSetNoData && !bUnsetNoData );
1100 : }
1101 :
1102 : /* -------------------------------------------------------------------- */
1103 : /* Set a forcable nodata value? */
1104 : /* -------------------------------------------------------------------- */
1105 156 : if( bSetNoData )
1106 : {
1107 4 : double dfVal = dfNoDataReal;
1108 4 : 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 4 : switch(eBandType)
1117 : {
1118 : case GDT_Byte:
1119 4 : CLAMP(dfVal, GByte, 0.0, 255.0);
1120 4 : 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 4 : 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 4 : 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 4 : poVRTBand->SetNoDataValue( dfVal );
1152 : }
1153 :
1154 276 : if (eMaskMode == MASK_AUTO &&
1155 : (GDALGetMaskFlags(GDALGetRasterBand(hDataset, 1)) & GMF_PER_DATASET) == 0 &&
1156 120 : (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 104 : if (eMaskMode == MASK_USER)
1171 : {
1172 : GDALRasterBand *poSrcBand =
1173 4 : (GDALRasterBand*)GDALGetRasterBand(hDataset, ABS(nMaskBand));
1174 4 : if (poSrcBand && poVDS->CreateMaskBand(GMF_PER_DATASET) == CE_None)
1175 : {
1176 : VRTSourcedRasterBand* hMaskVRTBand = (VRTSourcedRasterBand*)
1177 4 : GDALGetMaskBand(GDALGetRasterBand((GDALDatasetH)poVDS, 1));
1178 4 : if (nMaskBand > 0)
1179 : hMaskVRTBand->AddSimpleSource(poSrcBand,
1180 : anSrcWin[0], anSrcWin[1],
1181 : anSrcWin[2], anSrcWin[3],
1182 2 : 0, 0, nOXSize, nOYSize );
1183 : else
1184 : hMaskVRTBand->AddMaskBandSource(poSrcBand,
1185 : anSrcWin[0], anSrcWin[1],
1186 : anSrcWin[2], anSrcWin[3],
1187 2 : 0, 0, nOXSize, nOYSize );
1188 : }
1189 : }
1190 : else
1191 100 : if (eMaskMode == MASK_AUTO && nSrcBandCount > 0 &&
1192 : GDALGetMaskFlags(GDALGetRasterBand(hDataset, 1)) == GMF_PER_DATASET)
1193 : {
1194 2 : if (poVDS->CreateMaskBand(GMF_PER_DATASET) == CE_None)
1195 : {
1196 : VRTSourcedRasterBand* hMaskVRTBand = (VRTSourcedRasterBand*)
1197 2 : GDALGetMaskBand(GDALGetRasterBand((GDALDatasetH)poVDS, 1));
1198 : hMaskVRTBand->AddMaskBandSource((GDALRasterBand*)GDALGetRasterBand(hDataset, 1),
1199 : anSrcWin[0], anSrcWin[1],
1200 : anSrcWin[2], anSrcWin[3],
1201 2 : 0, 0, nOXSize, nOYSize );
1202 : }
1203 : }
1204 :
1205 : /* -------------------------------------------------------------------- */
1206 : /* Compute stats if required. */
1207 : /* -------------------------------------------------------------------- */
1208 104 : if (bStats)
1209 : {
1210 4 : for( i = 0; i < poVDS->GetRasterCount(); i++ )
1211 : {
1212 : double dfMin, dfMax, dfMean, dfStdDev;
1213 : poVDS->GetRasterBand(i+1)->ComputeStatistics( bApproxStats,
1214 2 : &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 104 : pfnProgress, NULL );
1224 104 : if( hOutDS != NULL )
1225 : {
1226 104 : int bHasGotErr = FALSE;
1227 104 : CPLErrorReset();
1228 104 : GDALFlushCache( hOutDS );
1229 104 : if (CPLGetLastErrorType() != CE_None)
1230 0 : bHasGotErr = TRUE;
1231 104 : GDALClose( hOutDS );
1232 104 : if (bHasGotErr)
1233 0 : hOutDS = NULL;
1234 : }
1235 :
1236 104 : GDALClose( (GDALDatasetH) poVDS );
1237 :
1238 104 : GDALClose( hDataset );
1239 :
1240 104 : CPLFree( panBandList );
1241 :
1242 104 : CPLFree( pszOutputSRS );
1243 :
1244 104 : if( !bSubCall )
1245 : {
1246 104 : GDALDumpOpenDatasets( stderr );
1247 104 : GDALDestroyDriverManager();
1248 : }
1249 :
1250 104 : CSLDestroy( argv );
1251 104 : CSLDestroy( papszCreateOptions );
1252 :
1253 104 : return hOutDS == NULL;
1254 : }
1255 :
1256 :
1257 : /************************************************************************/
1258 : /* ArgIsNumeric() */
1259 : /************************************************************************/
1260 :
1261 4 : int ArgIsNumeric( const char *pszArg )
1262 :
1263 : {
1264 4 : if( pszArg[0] == '-' )
1265 0 : pszArg++;
1266 :
1267 4 : if( *pszArg == '\0' )
1268 0 : return FALSE;
1269 :
1270 12 : while( *pszArg != '\0' )
1271 : {
1272 4 : if( (*pszArg < '0' || *pszArg > '9') && *pszArg != '.' )
1273 0 : return FALSE;
1274 4 : pszArg++;
1275 : }
1276 :
1277 4 : return TRUE;
1278 : }
1279 :
1280 : /************************************************************************/
1281 : /* AttachMetadata() */
1282 : /************************************************************************/
1283 :
1284 104 : static void AttachMetadata( GDALDatasetH hDS, char **papszMetadataOptions )
1285 :
1286 : {
1287 104 : int nCount = CSLCount(papszMetadataOptions);
1288 : int i;
1289 :
1290 106 : for( i = 0; i < nCount; i++ )
1291 : {
1292 2 : char *pszKey = NULL;
1293 : const char *pszValue;
1294 :
1295 2 : pszValue = CPLParseNameValue( papszMetadataOptions[i], &pszKey );
1296 2 : GDALSetMetadataItem(hDS,pszKey,pszValue,NULL);
1297 2 : CPLFree( pszKey );
1298 : }
1299 :
1300 104 : CSLDestroy( papszMetadataOptions );
1301 104 : }
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 126 : static void CopyBandInfo( GDALRasterBand * poSrcBand, GDALRasterBand * poDstBand,
1311 : int bCanCopyStatsMetadata, int bCopyScale, int bCopyNoData )
1312 :
1313 : {
1314 : int bSuccess;
1315 : double dfNoData;
1316 :
1317 126 : if (bCanCopyStatsMetadata)
1318 : {
1319 100 : poDstBand->SetMetadata( poSrcBand->GetMetadata() );
1320 : }
1321 : else
1322 : {
1323 26 : char** papszMetadata = poSrcBand->GetMetadata();
1324 26 : char** papszMetadataNew = NULL;
1325 54 : for( int i = 0; papszMetadata != NULL && papszMetadata[i] != NULL; i++ )
1326 : {
1327 28 : if (strncmp(papszMetadata[i], "STATISTICS_", 11) != 0)
1328 2 : papszMetadataNew = CSLAddString(papszMetadataNew, papszMetadata[i]);
1329 : }
1330 26 : poDstBand->SetMetadata( papszMetadataNew );
1331 26 : CSLDestroy(papszMetadataNew);
1332 : }
1333 :
1334 126 : poDstBand->SetColorTable( poSrcBand->GetColorTable() );
1335 126 : poDstBand->SetColorInterpretation(poSrcBand->GetColorInterpretation());
1336 126 : if( strlen(poSrcBand->GetDescription()) > 0 )
1337 2 : poDstBand->SetDescription( poSrcBand->GetDescription() );
1338 :
1339 126 : if (bCopyNoData)
1340 : {
1341 120 : dfNoData = poSrcBand->GetNoDataValue( &bSuccess );
1342 120 : if( bSuccess )
1343 2 : poDstBand->SetNoDataValue( dfNoData );
1344 : }
1345 :
1346 126 : if (bCopyScale)
1347 : {
1348 126 : poDstBand->SetOffset( poSrcBand->GetOffset() );
1349 126 : poDstBand->SetScale( poSrcBand->GetScale() );
1350 : }
1351 :
1352 126 : poDstBand->SetCategoryNames( poSrcBand->GetCategoryNames() );
1353 126 : if( !EQUAL(poSrcBand->GetUnitType(),"") )
1354 2 : poDstBand->SetUnitType( poSrcBand->GetUnitType() );
1355 126 : }
1356 :
1357 : /************************************************************************/
1358 : /* main() */
1359 : /************************************************************************/
1360 :
1361 256 : int main( int argc, char ** argv )
1362 :
1363 : {
1364 256 : return ProxyMain( argc, argv );
1365 : }
1366 :
1367 :
|