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