1 : /******************************************************************************
2 : * $Id: gdal_translate.cpp 18419 2009-12-31 20:38:45Z warmerdam $
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 :
37 : CPL_CVSID("$Id: gdal_translate.cpp 18419 2009-12-31 20:38:45Z warmerdam $");
38 :
39 : static int ArgIsNumeric( const char * );
40 : static void AttachMetadata( GDALDatasetH, char ** );
41 : static int bSubCall = FALSE;
42 :
43 : /* ******************************************************************* */
44 : /* Usage() */
45 : /* ******************************************************************** */
46 :
47 0 : static void Usage()
48 :
49 : {
50 : int iDr;
51 :
52 : printf( "Usage: gdal_translate [--help-general]\n"
53 : " [-ot {Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/\n"
54 : " CInt16/CInt32/CFloat32/CFloat64}] [-strict]\n"
55 : " [-of format] [-b band] [-expand {gray|rgb|rgba}]\n"
56 : " [-outsize xsize[%%] ysize[%%]]\n"
57 : " [-unscale] [-scale [src_min src_max [dst_min dst_max]]]\n"
58 : " [-srcwin xoff yoff xsize ysize] [-projwin ulx uly lrx lry]\n"
59 : " [-a_srs srs_def] [-a_ullr ulx uly lrx lry] [-a_nodata value]\n"
60 : " [-gcp pixel line easting northing [elevation]]*\n"
61 : " [-mo \"META-TAG=VALUE\"]* [-q] [-sds]\n"
62 : " [-co \"NAME=VALUE\"]*\n"
63 0 : " src_dataset dst_dataset\n\n" );
64 :
65 0 : printf( "%s\n\n", GDALVersionInfo( "--version" ) );
66 0 : printf( "The following format drivers are configured and support output:\n" );
67 0 : for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
68 : {
69 0 : GDALDriverH hDriver = GDALGetDriver(iDr);
70 :
71 0 : if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
72 : || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY,
73 : NULL ) != NULL )
74 : {
75 : printf( " %s: %s\n",
76 : GDALGetDriverShortName( hDriver ),
77 0 : GDALGetDriverLongName( hDriver ) );
78 : }
79 : }
80 0 : }
81 :
82 : /************************************************************************/
83 : /* ProxyMain() */
84 : /************************************************************************/
85 :
86 24 : static int ProxyMain( int argc, char ** argv )
87 :
88 : {
89 : GDALDatasetH hDataset, hOutDS;
90 : int i;
91 : int nRasterXSize, nRasterYSize;
92 24 : const char *pszSource=NULL, *pszDest=NULL, *pszFormat = "GTiff";
93 : GDALDriverH hDriver;
94 24 : int *panBandList = NULL, nBandCount = 0, bDefBands = TRUE;
95 : double adfGeoTransform[6];
96 24 : GDALDataType eOutputType = GDT_Unknown;
97 24 : int nOXSize = 0, nOYSize = 0;
98 24 : char *pszOXSize=NULL, *pszOYSize=NULL;
99 24 : char **papszCreateOptions = NULL;
100 24 : int anSrcWin[4], bStrict = FALSE;
101 : const char *pszProjection;
102 24 : int bScale = FALSE, bHaveScaleSrc = FALSE, bUnscale=FALSE;
103 24 : double dfScaleSrcMin=0.0, dfScaleSrcMax=255.0;
104 24 : double dfScaleDstMin=0.0, dfScaleDstMax=255.0;
105 : double dfULX, dfULY, dfLRX, dfLRY;
106 24 : char **papszMetadataOptions = NULL;
107 24 : char *pszOutputSRS = NULL;
108 24 : int bQuiet = FALSE, bGotBounds = FALSE;
109 24 : GDALProgressFunc pfnProgress = GDALTermProgress;
110 24 : int nGCPCount = 0;
111 24 : GDAL_GCP *pasGCPs = NULL;
112 24 : int iSrcFileArg = -1, iDstFileArg = -1;
113 24 : int bCopySubDatasets = FALSE;
114 24 : double adfULLR[4] = { 0,0,0,0 };
115 24 : int bSetNoData = FALSE;
116 24 : double dfNoDataReal = 0.0;
117 24 : int nRGBExpand = 0;
118 :
119 :
120 24 : anSrcWin[0] = 0;
121 24 : anSrcWin[1] = 0;
122 24 : anSrcWin[2] = 0;
123 24 : anSrcWin[3] = 0;
124 :
125 24 : dfULX = dfULY = dfLRX = dfLRY = 0.0;
126 :
127 : /* Check strict compilation and runtime library version as we use C++ API */
128 24 : if (! GDAL_CHECK_VERSION(argv[0]))
129 0 : exit(1);
130 :
131 : /* -------------------------------------------------------------------- */
132 : /* Register standard GDAL drivers, and process generic GDAL */
133 : /* command options. */
134 : /* -------------------------------------------------------------------- */
135 24 : GDALAllRegister();
136 24 : argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
137 24 : if( argc < 1 )
138 0 : exit( -argc );
139 :
140 : /* -------------------------------------------------------------------- */
141 : /* Handle command line arguments. */
142 : /* -------------------------------------------------------------------- */
143 103 : for( i = 1; i < argc; i++ )
144 : {
145 80 : if( EQUAL(argv[i], "--utility_version") )
146 : {
147 : printf("%s was compiled against GDAL %s and is running against GDAL %s\n",
148 1 : argv[0], GDAL_RELEASE_NAME, GDALVersionInfo("RELEASE_NAME"));
149 1 : return 0;
150 : }
151 84 : else if( EQUAL(argv[i],"-of") && i < argc-1 )
152 5 : pszFormat = argv[++i];
153 :
154 74 : else if( EQUAL(argv[i],"-q") || EQUAL(argv[i],"-quiet") )
155 : {
156 0 : bQuiet = TRUE;
157 0 : pfnProgress = GDALDummyProgress;
158 : }
159 :
160 76 : else if( EQUAL(argv[i],"-ot") && i < argc-1 )
161 : {
162 : int iType;
163 :
164 24 : for( iType = 1; iType < GDT_TypeCount; iType++ )
165 : {
166 44 : if( GDALGetDataTypeName((GDALDataType)iType) != NULL
167 22 : && EQUAL(GDALGetDataTypeName((GDALDataType)iType),
168 : argv[i+1]) )
169 : {
170 2 : eOutputType = (GDALDataType) iType;
171 : }
172 : }
173 :
174 2 : if( eOutputType == GDT_Unknown )
175 : {
176 0 : printf( "Unknown output pixel type: %s\n", argv[i+1] );
177 0 : Usage();
178 0 : GDALDestroyDriverManager();
179 0 : exit( 2 );
180 : }
181 2 : i++;
182 : }
183 75 : else if( EQUAL(argv[i],"-b") && i < argc-1 )
184 : {
185 3 : if( atoi(argv[i+1]) < 1 )
186 : {
187 0 : printf( "Unrecognizable band number (%s).\n", argv[i+1] );
188 0 : Usage();
189 0 : GDALDestroyDriverManager();
190 0 : exit( 2 );
191 : }
192 :
193 3 : nBandCount++;
194 : panBandList = (int *)
195 3 : CPLRealloc(panBandList, sizeof(int) * nBandCount);
196 3 : panBandList[nBandCount-1] = atoi(argv[++i]);
197 :
198 3 : if( panBandList[nBandCount-1] != nBandCount )
199 2 : bDefBands = FALSE;
200 : }
201 69 : else if( EQUAL(argv[i],"-not_strict") )
202 0 : bStrict = FALSE;
203 :
204 69 : else if( EQUAL(argv[i],"-strict") )
205 0 : bStrict = TRUE;
206 :
207 69 : else if( EQUAL(argv[i],"-sds") )
208 2 : bCopySubDatasets = TRUE;
209 :
210 75 : else if( EQUAL(argv[i],"-gcp") && i < argc - 4 )
211 : {
212 8 : char* endptr = NULL;
213 : /* -gcp pixel line easting northing [elev] */
214 :
215 8 : nGCPCount++;
216 : pasGCPs = (GDAL_GCP *)
217 8 : CPLRealloc( pasGCPs, sizeof(GDAL_GCP) * nGCPCount );
218 8 : GDALInitGCPs( 1, pasGCPs + nGCPCount - 1 );
219 :
220 8 : pasGCPs[nGCPCount-1].dfGCPPixel = atof(argv[++i]);
221 8 : pasGCPs[nGCPCount-1].dfGCPLine = atof(argv[++i]);
222 8 : pasGCPs[nGCPCount-1].dfGCPX = atof(argv[++i]);
223 8 : pasGCPs[nGCPCount-1].dfGCPY = atof(argv[++i]);
224 24 : if( argv[i+1] != NULL
225 16 : && (CPLStrtod(argv[i+1], &endptr) != 0.0 || argv[i+1][0] == '0') )
226 : {
227 : /* Check that last argument is really a number and not a filename */
228 : /* looking like a number (see ticket #863) */
229 2 : if (endptr && *endptr == 0)
230 2 : pasGCPs[nGCPCount-1].dfGCPZ = atof(argv[++i]);
231 : }
232 :
233 : /* should set id and info? */
234 : }
235 :
236 60 : else if( EQUAL(argv[i],"-a_nodata") && i < argc - 1 )
237 : {
238 1 : bSetNoData = TRUE;
239 1 : dfNoDataReal = atof(argv[i+1]);
240 1 : i += 1;
241 : }
242 :
243 59 : else if( EQUAL(argv[i],"-a_ullr") && i < argc - 4 )
244 : {
245 1 : adfULLR[0] = atof(argv[i+1]);
246 1 : adfULLR[1] = atof(argv[i+2]);
247 1 : adfULLR[2] = atof(argv[i+3]);
248 1 : adfULLR[3] = atof(argv[i+4]);
249 :
250 1 : bGotBounds = TRUE;
251 :
252 1 : i += 4;
253 : }
254 :
255 58 : else if( EQUAL(argv[i],"-co") && i < argc-1 )
256 : {
257 1 : papszCreateOptions = CSLAddString( papszCreateOptions, argv[++i] );
258 : }
259 :
260 56 : else if( EQUAL(argv[i],"-scale") )
261 : {
262 0 : bScale = TRUE;
263 0 : if( i < argc-2 && ArgIsNumeric(argv[i+1]) )
264 : {
265 0 : bHaveScaleSrc = TRUE;
266 0 : dfScaleSrcMin = atof(argv[i+1]);
267 0 : dfScaleSrcMax = atof(argv[i+2]);
268 0 : i += 2;
269 : }
270 0 : if( i < argc-2 && bHaveScaleSrc && ArgIsNumeric(argv[i+1]) )
271 : {
272 0 : dfScaleDstMin = atof(argv[i+1]);
273 0 : dfScaleDstMax = atof(argv[i+2]);
274 0 : i += 2;
275 : }
276 : else
277 : {
278 0 : dfScaleDstMin = 0.0;
279 0 : dfScaleDstMax = 255.999;
280 : }
281 : }
282 :
283 56 : else if( EQUAL(argv[i], "-unscale") )
284 : {
285 0 : bUnscale = TRUE;
286 : }
287 :
288 57 : else if( EQUAL(argv[i],"-mo") && i < argc-1 )
289 : {
290 : papszMetadataOptions = CSLAddString( papszMetadataOptions,
291 1 : argv[++i] );
292 : }
293 :
294 57 : else if( EQUAL(argv[i],"-outsize") && i < argc-2 )
295 : {
296 2 : pszOXSize = argv[++i];
297 2 : pszOYSize = argv[++i];
298 : }
299 :
300 54 : else if( EQUAL(argv[i],"-srcwin") && i < argc-4 )
301 : {
302 1 : anSrcWin[0] = atoi(argv[++i]);
303 1 : anSrcWin[1] = atoi(argv[++i]);
304 1 : anSrcWin[2] = atoi(argv[++i]);
305 1 : anSrcWin[3] = atoi(argv[++i]);
306 : }
307 :
308 53 : else if( EQUAL(argv[i],"-projwin") && i < argc-4 )
309 : {
310 1 : dfULX = atof(argv[++i]);
311 1 : dfULY = atof(argv[++i]);
312 1 : dfLRX = atof(argv[++i]);
313 1 : dfLRY = atof(argv[++i]);
314 : }
315 :
316 53 : else if( EQUAL(argv[i],"-a_srs") && i < argc-1 )
317 : {
318 2 : OGRSpatialReference oOutputSRS;
319 :
320 2 : if( oOutputSRS.SetFromUserInput( argv[i+1] ) != OGRERR_NONE )
321 : {
322 : fprintf( stderr, "Failed to process SRS definition: %s\n",
323 0 : argv[i+1] );
324 0 : GDALDestroyDriverManager();
325 0 : exit( 1 );
326 : }
327 :
328 2 : oOutputSRS.exportToWkt( &pszOutputSRS );
329 2 : i++;
330 : }
331 :
332 52 : else if( EQUAL(argv[i],"-expand") && i < argc-1 )
333 : {
334 3 : if (EQUAL(argv[i+1], "gray"))
335 0 : nRGBExpand = 1;
336 3 : else if (EQUAL(argv[i+1], "rgb"))
337 2 : nRGBExpand = 3;
338 1 : else if (EQUAL(argv[i+1], "rgba"))
339 1 : nRGBExpand = 4;
340 : else
341 : {
342 : printf( "Value %s unsupported. Only gray, rgb or rgba are supported.\n\n",
343 0 : argv[i] );
344 0 : Usage();
345 0 : GDALDestroyDriverManager();
346 0 : exit( 2 );
347 : }
348 3 : i++;
349 : }
350 :
351 46 : else if( argv[i][0] == '-' )
352 : {
353 : printf( "Option %s incomplete, or not recognised.\n\n",
354 0 : argv[i] );
355 0 : Usage();
356 0 : GDALDestroyDriverManager();
357 0 : exit( 2 );
358 : }
359 46 : else if( pszSource == NULL )
360 : {
361 23 : iSrcFileArg = i;
362 23 : pszSource = argv[i];
363 : }
364 23 : else if( pszDest == NULL )
365 : {
366 23 : pszDest = argv[i];
367 23 : iDstFileArg = i;
368 : }
369 :
370 : else
371 : {
372 0 : printf( "Too many command options.\n\n" );
373 0 : Usage();
374 0 : GDALDestroyDriverManager();
375 0 : exit( 2 );
376 : }
377 : }
378 :
379 23 : if( pszDest == NULL )
380 : {
381 0 : Usage();
382 0 : GDALDestroyDriverManager();
383 0 : exit( 10 );
384 : }
385 :
386 23 : if ( strcmp(pszSource, pszDest) == 0)
387 : {
388 0 : fprintf(stderr, "Source and destination datasets must be different.\n");
389 0 : GDALDestroyDriverManager();
390 0 : exit( 1 );
391 : }
392 :
393 : /* -------------------------------------------------------------------- */
394 : /* Attempt to open source file. */
395 : /* -------------------------------------------------------------------- */
396 :
397 23 : hDataset = GDALOpenShared( pszSource, GA_ReadOnly );
398 :
399 23 : if( hDataset == NULL )
400 : {
401 : fprintf( stderr,
402 : "GDALOpen failed - %d\n%s\n",
403 0 : CPLGetLastErrorNo(), CPLGetLastErrorMsg() );
404 0 : GDALDestroyDriverManager();
405 0 : exit( 1 );
406 : }
407 :
408 : /* -------------------------------------------------------------------- */
409 : /* Handle subdatasets. */
410 : /* -------------------------------------------------------------------- */
411 23 : if( !bCopySubDatasets
412 : && CSLCount(GDALGetMetadata( hDataset, "SUBDATASETS" )) > 0
413 : && GDALGetRasterCount(hDataset) == 0 )
414 : {
415 : fprintf( stderr,
416 0 : "Input file contains subdatasets. Please, select one of them for reading.\n" );
417 0 : GDALClose( hDataset );
418 0 : GDALDestroyDriverManager();
419 0 : exit( 1 );
420 : }
421 :
422 23 : if( CSLCount(GDALGetMetadata( hDataset, "SUBDATASETS" )) > 0
423 : && bCopySubDatasets )
424 : {
425 1 : char **papszSubdatasets = GDALGetMetadata(hDataset,"SUBDATASETS");
426 1 : char *pszSubDest = (char *) CPLMalloc(strlen(pszDest)+32);
427 : int i;
428 1 : int bOldSubCall = bSubCall;
429 :
430 1 : argv[iDstFileArg] = pszSubDest;
431 1 : bSubCall = TRUE;
432 2 : for( i = 0; papszSubdatasets[i] != NULL; i += 2 )
433 : {
434 1 : argv[iSrcFileArg] = strstr(papszSubdatasets[i],"=")+1;
435 1 : sprintf( pszSubDest, "%s%d", pszDest, i/2 + 1 );
436 1 : if( ProxyMain( argc, argv ) != 0 )
437 0 : break;
438 : }
439 :
440 1 : bSubCall = bOldSubCall;
441 1 : CPLFree( pszSubDest );
442 :
443 1 : GDALClose( hDataset );
444 :
445 1 : if( !bSubCall )
446 : {
447 1 : GDALDumpOpenDatasets( stderr );
448 1 : GDALDestroyDriverManager();
449 : }
450 1 : return 1;
451 : }
452 :
453 : /* -------------------------------------------------------------------- */
454 : /* Collect some information from the source file. */
455 : /* -------------------------------------------------------------------- */
456 22 : nRasterXSize = GDALGetRasterXSize( hDataset );
457 22 : nRasterYSize = GDALGetRasterYSize( hDataset );
458 :
459 22 : if( !bQuiet )
460 22 : printf( "Input file size is %d, %d\n", nRasterXSize, nRasterYSize );
461 :
462 22 : if( anSrcWin[2] == 0 && anSrcWin[3] == 0 )
463 : {
464 21 : anSrcWin[2] = nRasterXSize;
465 21 : anSrcWin[3] = nRasterYSize;
466 : }
467 :
468 : /* -------------------------------------------------------------------- */
469 : /* Build band list to translate */
470 : /* -------------------------------------------------------------------- */
471 22 : if( nBandCount == 0 )
472 : {
473 21 : nBandCount = GDALGetRasterCount( hDataset );
474 21 : if( nBandCount == 0 )
475 : {
476 0 : fprintf( stderr, "Input file has no bands, and so cannot be translated.\n" );
477 0 : GDALDestroyDriverManager();
478 0 : exit(1 );
479 : }
480 :
481 21 : panBandList = (int *) CPLMalloc(sizeof(int)*nBandCount);
482 44 : for( i = 0; i < nBandCount; i++ )
483 23 : panBandList[i] = i+1;
484 : }
485 : else
486 : {
487 4 : for( i = 0; i < nBandCount; i++ )
488 : {
489 3 : if( panBandList[i] < 1 || panBandList[i] > GDALGetRasterCount(hDataset) )
490 : {
491 : fprintf( stderr,
492 : "Band %d requested, but only bands 1 to %d available.\n",
493 0 : panBandList[i], GDALGetRasterCount(hDataset) );
494 0 : GDALDestroyDriverManager();
495 0 : exit( 2 );
496 : }
497 : }
498 :
499 1 : if( nBandCount != GDALGetRasterCount( hDataset ) )
500 0 : bDefBands = FALSE;
501 : }
502 :
503 : /* -------------------------------------------------------------------- */
504 : /* Compute the source window from the projected source window */
505 : /* if the projected coordinates were provided. Note that the */
506 : /* projected coordinates are in ulx, uly, lrx, lry format, */
507 : /* while the anSrcWin is xoff, yoff, xsize, ysize with the */
508 : /* xoff,yoff being the ulx, uly in pixel/line. */
509 : /* -------------------------------------------------------------------- */
510 22 : if( dfULX != 0.0 || dfULY != 0.0
511 : || dfLRX != 0.0 || dfLRY != 0.0 )
512 : {
513 : double adfGeoTransform[6];
514 :
515 1 : GDALGetGeoTransform( hDataset, adfGeoTransform );
516 :
517 1 : if( adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0 )
518 : {
519 : fprintf( stderr,
520 : "The -projwin option was used, but the geotransform is\n"
521 0 : "rotated. This configuration is not supported.\n" );
522 0 : GDALClose( hDataset );
523 0 : CPLFree( panBandList );
524 0 : GDALDestroyDriverManager();
525 0 : exit( 1 );
526 : }
527 :
528 : anSrcWin[0] = (int)
529 1 : ((dfULX - adfGeoTransform[0]) / adfGeoTransform[1] + 0.001);
530 : anSrcWin[1] = (int)
531 1 : ((dfULY - adfGeoTransform[3]) / adfGeoTransform[5] + 0.001);
532 :
533 1 : anSrcWin[2] = (int) ((dfLRX - dfULX) / adfGeoTransform[1] + 0.5);
534 1 : anSrcWin[3] = (int) ((dfLRY - dfULY) / adfGeoTransform[5] + 0.5);
535 :
536 1 : if( !bQuiet )
537 : fprintf( stdout,
538 : "Computed -srcwin %d %d %d %d from projected window.\n",
539 : anSrcWin[0],
540 : anSrcWin[1],
541 : anSrcWin[2],
542 1 : anSrcWin[3] );
543 :
544 3 : if( anSrcWin[0] < 0 || anSrcWin[1] < 0
545 1 : || anSrcWin[0] + anSrcWin[2] > GDALGetRasterXSize(hDataset)
546 1 : || anSrcWin[1] + anSrcWin[3] > GDALGetRasterYSize(hDataset) )
547 : {
548 : fprintf( stderr,
549 : "Computed -srcwin falls outside raster size of %dx%d.\n",
550 : GDALGetRasterXSize(hDataset),
551 0 : GDALGetRasterYSize(hDataset) );
552 0 : exit( 1 );
553 : }
554 : }
555 :
556 : /* -------------------------------------------------------------------- */
557 : /* Verify source window. */
558 : /* -------------------------------------------------------------------- */
559 110 : if( anSrcWin[0] < 0 || anSrcWin[1] < 0
560 44 : || anSrcWin[2] <= 0 || anSrcWin[3] <= 0
561 22 : || anSrcWin[0] + anSrcWin[2] > GDALGetRasterXSize(hDataset)
562 22 : || anSrcWin[1] + anSrcWin[3] > GDALGetRasterYSize(hDataset) )
563 : {
564 : fprintf( stderr,
565 : "-srcwin %d %d %d %d falls outside raster size of %dx%d\n"
566 : "or is otherwise illegal.\n",
567 : anSrcWin[0],
568 : anSrcWin[1],
569 : anSrcWin[2],
570 : anSrcWin[3],
571 : GDALGetRasterXSize(hDataset),
572 0 : GDALGetRasterYSize(hDataset) );
573 0 : exit( 1 );
574 : }
575 :
576 : /* -------------------------------------------------------------------- */
577 : /* Find the output driver. */
578 : /* -------------------------------------------------------------------- */
579 22 : hDriver = GDALGetDriverByName( pszFormat );
580 22 : if( hDriver == NULL )
581 : {
582 : int iDr;
583 :
584 0 : printf( "Output driver `%s' not recognised.\n", pszFormat );
585 0 : printf( "The following format drivers are configured and support output:\n" );
586 0 : for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
587 : {
588 0 : GDALDriverH hDriver = GDALGetDriver(iDr);
589 :
590 0 : if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
591 : || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY,
592 : NULL ) != NULL )
593 : {
594 : printf( " %s: %s\n",
595 : GDALGetDriverShortName( hDriver ),
596 0 : GDALGetDriverLongName( hDriver ) );
597 : }
598 : }
599 0 : printf( "\n" );
600 0 : Usage();
601 :
602 0 : GDALClose( hDataset );
603 0 : CPLFree( panBandList );
604 0 : GDALDestroyDriverManager();
605 0 : CSLDestroy( argv );
606 0 : CSLDestroy( papszCreateOptions );
607 0 : exit( 1 );
608 : }
609 :
610 : /* -------------------------------------------------------------------- */
611 : /* The short form is to CreateCopy(). We use this if the input */
612 : /* matches the whole dataset. Eventually we should rewrite */
613 : /* this entire program to use virtual datasets to construct a */
614 : /* virtual input source to copy from. */
615 : /* -------------------------------------------------------------------- */
616 93 : if( eOutputType == GDT_Unknown
617 : && !bScale && !bUnscale
618 : && CSLCount(papszMetadataOptions) == 0 && bDefBands
619 36 : && anSrcWin[0] == 0 && anSrcWin[1] == 0
620 18 : && anSrcWin[2] == GDALGetRasterXSize(hDataset)
621 17 : && anSrcWin[3] == GDALGetRasterYSize(hDataset)
622 : && pszOXSize == NULL && pszOYSize == NULL
623 : && nGCPCount == 0 && !bGotBounds
624 : && pszOutputSRS == NULL && !bSetNoData
625 : && nRGBExpand == 0)
626 : {
627 :
628 : hOutDS = GDALCreateCopy( hDriver, pszDest, hDataset,
629 : bStrict, papszCreateOptions,
630 8 : pfnProgress, NULL );
631 :
632 8 : if( hOutDS != NULL )
633 8 : GDALClose( hOutDS );
634 :
635 8 : GDALClose( hDataset );
636 :
637 8 : CPLFree( panBandList );
638 :
639 8 : if( !bSubCall )
640 : {
641 7 : GDALDumpOpenDatasets( stderr );
642 7 : GDALDestroyDriverManager();
643 : }
644 :
645 8 : CSLDestroy( argv );
646 8 : CSLDestroy( papszCreateOptions );
647 :
648 8 : return hOutDS == NULL;
649 : }
650 :
651 : /* -------------------------------------------------------------------- */
652 : /* Establish some parameters. */
653 : /* -------------------------------------------------------------------- */
654 14 : if( pszOXSize == NULL )
655 : {
656 12 : nOXSize = anSrcWin[2];
657 12 : nOYSize = anSrcWin[3];
658 : }
659 : else
660 : {
661 2 : nOXSize = (int) ((pszOXSize[strlen(pszOXSize)-1]=='%'
662 4 : ? atof(pszOXSize)/100*anSrcWin[2] : atoi(pszOXSize)));
663 2 : nOYSize = (int) ((pszOYSize[strlen(pszOYSize)-1]=='%'
664 4 : ? atof(pszOYSize)/100*anSrcWin[3] : atoi(pszOYSize)));
665 : }
666 :
667 : /* ==================================================================== */
668 : /* Create a virtual dataset. */
669 : /* ==================================================================== */
670 : VRTDataset *poVDS;
671 :
672 : /* -------------------------------------------------------------------- */
673 : /* Make a virtual clone. */
674 : /* -------------------------------------------------------------------- */
675 14 : poVDS = (VRTDataset *) VRTCreate( nOXSize, nOYSize );
676 :
677 14 : if( nGCPCount == 0 )
678 : {
679 12 : if( pszOutputSRS != NULL )
680 : {
681 0 : poVDS->SetProjection( pszOutputSRS );
682 : }
683 : else
684 : {
685 12 : pszProjection = GDALGetProjectionRef( hDataset );
686 12 : if( pszProjection != NULL && strlen(pszProjection) > 0 )
687 9 : poVDS->SetProjection( pszProjection );
688 : }
689 : }
690 :
691 14 : if( bGotBounds )
692 : {
693 1 : adfGeoTransform[0] = adfULLR[0];
694 1 : adfGeoTransform[1] = (adfULLR[2] - adfULLR[0]) / nOXSize;
695 1 : adfGeoTransform[2] = 0.0;
696 1 : adfGeoTransform[3] = adfULLR[1];
697 1 : adfGeoTransform[4] = 0.0;
698 1 : adfGeoTransform[5] = (adfULLR[3] - adfULLR[1]) / nOYSize;
699 :
700 1 : poVDS->SetGeoTransform( adfGeoTransform );
701 : }
702 :
703 13 : else if( GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None
704 : && nGCPCount == 0 )
705 : {
706 18 : adfGeoTransform[0] += anSrcWin[0] * adfGeoTransform[1]
707 27 : + anSrcWin[1] * adfGeoTransform[2];
708 18 : adfGeoTransform[3] += anSrcWin[0] * adfGeoTransform[4]
709 27 : + anSrcWin[1] * adfGeoTransform[5];
710 :
711 9 : adfGeoTransform[1] *= anSrcWin[2] / (double) nOXSize;
712 9 : adfGeoTransform[2] *= anSrcWin[3] / (double) nOYSize;
713 9 : adfGeoTransform[4] *= anSrcWin[2] / (double) nOXSize;
714 9 : adfGeoTransform[5] *= anSrcWin[3] / (double) nOYSize;
715 :
716 9 : poVDS->SetGeoTransform( adfGeoTransform );
717 : }
718 :
719 14 : if( nGCPCount != 0 )
720 : {
721 2 : const char *pszGCPProjection = pszOutputSRS;
722 :
723 2 : if( pszGCPProjection == NULL )
724 0 : pszGCPProjection = GDALGetGCPProjection( hDataset );
725 2 : if( pszGCPProjection == NULL )
726 0 : pszGCPProjection = "";
727 :
728 2 : poVDS->SetGCPs( nGCPCount, pasGCPs, pszGCPProjection );
729 :
730 2 : GDALDeinitGCPs( nGCPCount, pasGCPs );
731 2 : CPLFree( pasGCPs );
732 : }
733 :
734 12 : else if( GDALGetGCPCount( hDataset ) > 0 )
735 : {
736 : GDAL_GCP *pasGCPs;
737 0 : int nGCPs = GDALGetGCPCount( hDataset );
738 :
739 0 : pasGCPs = GDALDuplicateGCPs( nGCPs, GDALGetGCPs( hDataset ) );
740 :
741 0 : for( i = 0; i < nGCPs; i++ )
742 : {
743 0 : pasGCPs[i].dfGCPPixel -= anSrcWin[0];
744 0 : pasGCPs[i].dfGCPLine -= anSrcWin[1];
745 0 : pasGCPs[i].dfGCPPixel *= (nOXSize / (double) anSrcWin[2] );
746 0 : pasGCPs[i].dfGCPLine *= (nOYSize / (double) anSrcWin[3] );
747 : }
748 :
749 : poVDS->SetGCPs( nGCPs, pasGCPs,
750 0 : GDALGetGCPProjection( hDataset ) );
751 :
752 0 : GDALDeinitGCPs( nGCPs, pasGCPs );
753 0 : CPLFree( pasGCPs );
754 : }
755 :
756 : /* -------------------------------------------------------------------- */
757 : /* Transfer generally applicable metadata. */
758 : /* -------------------------------------------------------------------- */
759 14 : poVDS->SetMetadata( ((GDALDataset*)hDataset)->GetMetadata() );
760 14 : AttachMetadata( (GDALDatasetH) poVDS, papszMetadataOptions );
761 :
762 : /* -------------------------------------------------------------------- */
763 : /* Transfer metadata that remains valid if the spatial */
764 : /* arrangement of the data is unaltered. */
765 : /* -------------------------------------------------------------------- */
766 41 : if( anSrcWin[0] == 0 && anSrcWin[1] == 0
767 14 : && anSrcWin[2] == GDALGetRasterXSize(hDataset)
768 13 : && anSrcWin[3] == GDALGetRasterYSize(hDataset)
769 : && pszOXSize == NULL && pszOYSize == NULL )
770 : {
771 : char **papszMD;
772 :
773 11 : papszMD = ((GDALDataset*)hDataset)->GetMetadata("RPC");
774 11 : if( papszMD != NULL )
775 0 : poVDS->SetMetadata( papszMD, "RPC" );
776 : }
777 :
778 14 : if (nRGBExpand != 0)
779 3 : nBandCount += nRGBExpand - 1;
780 :
781 : /* ==================================================================== */
782 : /* Process all bands. */
783 : /* ==================================================================== */
784 37 : for( i = 0; i < nBandCount; i++ )
785 : {
786 : VRTSourcedRasterBand *poVRTBand;
787 : GDALRasterBand *poSrcBand;
788 : GDALDataType eBandType;
789 :
790 33 : if (nRGBExpand != 0 && i < nRGBExpand)
791 : {
792 : poSrcBand = ((GDALDataset *)
793 10 : hDataset)->GetRasterBand(panBandList[0]);
794 10 : GDALColorTable* poColorTable = poSrcBand->GetColorTable();
795 10 : if (poColorTable == NULL)
796 : {
797 0 : fprintf(stderr, "Error : band %d has no color table\n", panBandList[0]);
798 0 : GDALClose( hDataset );
799 0 : CPLFree( panBandList );
800 0 : GDALDestroyDriverManager();
801 0 : CSLDestroy( argv );
802 0 : CSLDestroy( papszCreateOptions );
803 0 : exit( 1 );
804 : }
805 :
806 : /* Check that the color table only contains gray levels */
807 : /* when using -expand gray */
808 10 : if (nRGBExpand == 1)
809 : {
810 0 : int nColorCount = poColorTable->GetColorEntryCount();
811 : int nColor;
812 0 : for( nColor = 0; nColor < nColorCount; nColor++ )
813 : {
814 0 : const GDALColorEntry* poEntry = poColorTable->GetColorEntry(nColor);
815 0 : if (poEntry->c1 != poEntry->c2 || poEntry->c1 != poEntry->c2)
816 : {
817 0 : fprintf(stderr, "Warning : color table contains non gray levels colors\n");
818 0 : break;
819 : }
820 : }
821 : }
822 : }
823 : else
824 : poSrcBand = ((GDALDataset *)
825 13 : hDataset)->GetRasterBand(panBandList[i]);
826 :
827 : /* -------------------------------------------------------------------- */
828 : /* Select output data type to match source. */
829 : /* -------------------------------------------------------------------- */
830 23 : if( eOutputType == GDT_Unknown )
831 21 : eBandType = poSrcBand->GetRasterDataType();
832 : else
833 2 : eBandType = eOutputType;
834 :
835 : /* -------------------------------------------------------------------- */
836 : /* Create this band. */
837 : /* -------------------------------------------------------------------- */
838 23 : poVDS->AddBand( eBandType, NULL );
839 23 : poVRTBand = (VRTSourcedRasterBand *) poVDS->GetRasterBand( i+1 );
840 :
841 : /* -------------------------------------------------------------------- */
842 : /* Do we need to collect scaling information? */
843 : /* -------------------------------------------------------------------- */
844 23 : double dfScale=1.0, dfOffset=0.0;
845 :
846 23 : if( bScale && !bHaveScaleSrc )
847 : {
848 : double adfCMinMax[2];
849 0 : GDALComputeRasterMinMax( poSrcBand, TRUE, adfCMinMax );
850 0 : dfScaleSrcMin = adfCMinMax[0];
851 0 : dfScaleSrcMax = adfCMinMax[1];
852 : }
853 :
854 23 : if( bScale )
855 : {
856 0 : if( dfScaleSrcMax == dfScaleSrcMin )
857 0 : dfScaleSrcMax += 0.1;
858 0 : if( dfScaleDstMax == dfScaleDstMin )
859 0 : dfScaleDstMax += 0.1;
860 :
861 : dfScale = (dfScaleDstMax - dfScaleDstMin)
862 0 : / (dfScaleSrcMax - dfScaleSrcMin);
863 0 : dfOffset = -1 * dfScaleSrcMin * dfScale + dfScaleDstMin;
864 : }
865 :
866 23 : if( bUnscale )
867 : {
868 0 : dfScale = poSrcBand->GetScale();
869 0 : dfOffset = poSrcBand->GetOffset();
870 : }
871 :
872 : /* -------------------------------------------------------------------- */
873 : /* Create a simple or complex data source depending on the */
874 : /* translation type required. */
875 : /* -------------------------------------------------------------------- */
876 33 : if( bUnscale || bScale || (nRGBExpand != 0 && i < nRGBExpand) )
877 : {
878 : poVRTBand->AddComplexSource( poSrcBand,
879 : anSrcWin[0], anSrcWin[1],
880 : anSrcWin[2], anSrcWin[3],
881 : 0, 0, nOXSize, nOYSize,
882 : dfOffset, dfScale,
883 : VRT_NODATA_UNSET,
884 10 : (nRGBExpand != 0 && i < nRGBExpand) ? i + 1 : 0 );
885 : }
886 : else
887 : poVRTBand->AddSimpleSource( poSrcBand,
888 : anSrcWin[0], anSrcWin[1],
889 : anSrcWin[2], anSrcWin[3],
890 13 : 0, 0, nOXSize, nOYSize );
891 :
892 : /* -------------------------------------------------------------------- */
893 : /* In case of color table translate, we only set the color */
894 : /* interpretation other info copied by CopyCommonInfoFrom are */
895 : /* not relevant in RGB expansion. */
896 : /* -------------------------------------------------------------------- */
897 23 : if (nRGBExpand == 1)
898 : {
899 0 : poVRTBand->SetColorInterpretation( GCI_GrayIndex );
900 : }
901 33 : else if (nRGBExpand != 0 && i < nRGBExpand)
902 : {
903 10 : poVRTBand->SetColorInterpretation( (GDALColorInterp) (GCI_RedBand + i) );
904 : }
905 :
906 : /* -------------------------------------------------------------------- */
907 : /* copy over some other information of interest. */
908 : /* -------------------------------------------------------------------- */
909 : else
910 : {
911 13 : poVRTBand->CopyCommonInfoFrom( poSrcBand );
912 :
913 13 : if( bUnscale )
914 : {
915 0 : poVRTBand->SetOffset( 0.0 );
916 0 : poVRTBand->SetScale( 1.0 );
917 : }
918 : }
919 :
920 : /* -------------------------------------------------------------------- */
921 : /* Set a forcable nodata value? */
922 : /* -------------------------------------------------------------------- */
923 23 : if( bSetNoData )
924 : {
925 1 : double dfVal = dfNoDataReal;
926 1 : int bClamped = FALSE, bRounded = FALSE;
927 :
928 : #define CLAMP(val,type,minval,maxval) \
929 : do { if (val < minval) { bClamped = TRUE; val = minval; } \
930 : else if (val > maxval) { bClamped = TRUE; val = maxval; } \
931 : else if (val != (type)val) { bRounded = TRUE; val = (type)(val + 0.5); } } \
932 : while(0)
933 :
934 1 : switch(eBandType)
935 : {
936 : case GDT_Byte:
937 1 : CLAMP(dfVal, GByte, 0.0, 255.0);
938 1 : break;
939 : case GDT_Int16:
940 0 : CLAMP(dfVal, GInt16, -32768.0, 32767.0);
941 0 : break;
942 : case GDT_UInt16:
943 0 : CLAMP(dfVal, GUInt16, 0.0, 65535.0);
944 0 : break;
945 : case GDT_Int32:
946 0 : CLAMP(dfVal, GInt32, -2147483648.0, 2147483647.0);
947 0 : break;
948 : case GDT_UInt32:
949 0 : CLAMP(dfVal, GUInt32, 0.0, 4294967295.0);
950 : break;
951 : default:
952 : break;
953 : }
954 :
955 1 : if (bClamped)
956 : {
957 : printf( "for band %d, nodata value has been clamped "
958 : "to %.0f, the original value being out of range.\n",
959 0 : i + 1, dfVal);
960 : }
961 1 : else if(bRounded)
962 : {
963 : printf("for band %d, nodata value has been rounded "
964 : "to %.0f, %s being an integer datatype.\n",
965 : i + 1, dfVal,
966 0 : GDALGetDataTypeName(eBandType));
967 : }
968 :
969 1 : poVRTBand->SetNoDataValue( dfVal );
970 : }
971 : }
972 :
973 : /* -------------------------------------------------------------------- */
974 : /* Write to the output file using CopyCreate(). */
975 : /* -------------------------------------------------------------------- */
976 : hOutDS = GDALCreateCopy( hDriver, pszDest, (GDALDatasetH) poVDS,
977 : bStrict, papszCreateOptions,
978 14 : pfnProgress, NULL );
979 14 : if( hOutDS != NULL )
980 : {
981 14 : GDALClose( hOutDS );
982 : }
983 :
984 14 : GDALClose( (GDALDatasetH) poVDS );
985 :
986 14 : GDALClose( hDataset );
987 :
988 14 : CPLFree( panBandList );
989 :
990 14 : CPLFree( pszOutputSRS );
991 :
992 14 : if( !bSubCall )
993 : {
994 14 : GDALDumpOpenDatasets( stderr );
995 14 : GDALDestroyDriverManager();
996 : }
997 :
998 14 : CSLDestroy( argv );
999 14 : CSLDestroy( papszCreateOptions );
1000 :
1001 14 : return hOutDS == NULL;
1002 : }
1003 :
1004 :
1005 : /************************************************************************/
1006 : /* ArgIsNumeric() */
1007 : /************************************************************************/
1008 :
1009 0 : int ArgIsNumeric( const char *pszArg )
1010 :
1011 : {
1012 0 : if( pszArg[0] == '-' )
1013 0 : pszArg++;
1014 :
1015 0 : if( *pszArg == '\0' )
1016 0 : return FALSE;
1017 :
1018 0 : while( *pszArg != '\0' )
1019 : {
1020 0 : if( (*pszArg < '0' || *pszArg > '9') && *pszArg != '.' )
1021 0 : return FALSE;
1022 0 : pszArg++;
1023 : }
1024 :
1025 0 : return TRUE;
1026 : }
1027 :
1028 : /************************************************************************/
1029 : /* AttachMetadata() */
1030 : /************************************************************************/
1031 :
1032 14 : static void AttachMetadata( GDALDatasetH hDS, char **papszMetadataOptions )
1033 :
1034 : {
1035 14 : int nCount = CSLCount(papszMetadataOptions);
1036 : int i;
1037 :
1038 15 : for( i = 0; i < nCount; i++ )
1039 : {
1040 1 : char *pszKey = NULL;
1041 : const char *pszValue;
1042 :
1043 1 : pszValue = CPLParseNameValue( papszMetadataOptions[i], &pszKey );
1044 1 : GDALSetMetadataItem(hDS,pszKey,pszValue,NULL);
1045 1 : CPLFree( pszKey );
1046 : }
1047 :
1048 14 : CSLDestroy( papszMetadataOptions );
1049 14 : }
1050 :
1051 : /************************************************************************/
1052 : /* main() */
1053 : /************************************************************************/
1054 :
1055 23 : int main( int argc, char ** argv )
1056 :
1057 : {
1058 23 : return ProxyMain( argc, argv );
1059 : }
1060 :
1061 :
|