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