root/tags/gdal_1_2_3/gcore/gdaldriver.cpp

Revision 4862, 17.5 kB (checked in by sperkins, 6 years ago)

default CreateCopy?() now copies metadata

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /******************************************************************************
2  * $Id$
3  *
4  * Project:  GDAL Core
5  * Purpose:  Implementation of GDALDriver class (and C wrappers)
6  * Author:   Frank Warmerdam, warmerdam@pobox.com
7  *
8  ******************************************************************************
9  * Copyright (c) 1998, 2000, 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  * $Log$
31  * Revision 1.30  2003/05/23 20:42:24  sperkins
32  * default CreateCopy() now copies metadata
33  *
34  * Revision 1.29  2003/04/30 17:13:48  warmerda
35  * added docs for many C functions
36  *
37  * Revision 1.28  2002/09/11 14:17:23  warmerda
38  * copy ct/metadata/description for bands in CreateCopy()
39  *
40  * Revision 1.27  2002/09/06 01:28:30  warmerda
41  * fixed logic for setting descriptions in created files
42  *
43  * Revision 1.26  2002/09/04 06:52:05  warmerda
44  * added unload driver support to GDALDriver
45  *
46  * Revision 1.25  2002/07/09 20:33:12  warmerda
47  * expand tabs
48  *
49  * Revision 1.24  2002/06/12 21:13:27  warmerda
50  * use metadata based driver info
51  *
52  * Revision 1.23  2001/12/15 15:47:54  warmerda
53  * don't replace existing descriptions
54  *
55  * Revision 1.22  2001/12/15 15:42:27  warmerda
56  * *** empty log message ***
57  *
58  * Revision 1.21  2001/10/05 20:35:26  warmerda
59  * CreateCopy() won't try to write default geotransform
60  *
61  * Revision 1.20  2001/09/24 15:58:27  warmerda
62  * improved progress reporting in createcopy
63  *
64  * Revision 1.19  2001/07/18 04:04:30  warmerda
65  * added CPL_CVSID
66  *
67  * Revision 1.18  2001/02/15 16:30:34  warmerda
68  * added create debug message
69  */
70
71 #include "gdal_priv.h"
72
73 CPL_CVSID("$Id$");
74
75 /************************************************************************/
76 /*                             GDALDriver()                             */
77 /************************************************************************/
78
79 GDALDriver::GDALDriver()
80
81 {
82     pfnOpen = NULL;
83     pfnCreate = NULL;
84     pfnDelete = NULL;
85     pfnCreateCopy = NULL;
86     pfnUnloadDriver = NULL;
87     pDriverData = NULL;
88 }
89
90 /************************************************************************/
91 /*                            ~GDALDriver()                             */
92 /************************************************************************/
93
94 GDALDriver::~GDALDriver()
95
96 {
97     if( pfnUnloadDriver != NULL )
98         pfnUnloadDriver( this );
99 }
100
101 /************************************************************************/
102 /*                               Create()                               */
103 /************************************************************************/
104
105 /**
106  * Create a new dataset with this driver.
107  *
108  * What argument values are legal for particular drivers is driver specific,
109  * and there is no way to query in advance to establish legal values.
110  *
111  * Equivelent of the C function GDALCreate().
112  *
113  * @param pszFilename the name of the dataset to create.
114  * @param nXSize width of created raster in pixels.
115  * @param nYSize height of created raster in pixels.
116  * @param nBands number of bands.
117  * @param eType type of raster.
118  * @param papszParmList list of driver specific control parameters.
119  *
120  * @return NULL on failure, or a new GDALDataset.
121  */
122
123 GDALDataset * GDALDriver::Create( const char * pszFilename,
124                                   int nXSize, int nYSize, int nBands,
125                                   GDALDataType eType, char ** papszParmList )
126
127 {
128     /* notdef: should add a bunch of error checking here */
129
130     if( pfnCreate == NULL )
131     {
132         CPLError( CE_Failure, CPLE_NotSupported,
133                   "GDALDriver::Create() ... no create method implemented"
134                   " for this format.\n" );
135
136         return NULL;
137     }
138     else
139     {
140         GDALDataset *poDS;
141
142         CPLDebug( "GDAL", "GDALDriver::Create(%s,%s,%d,%d,%d,%s,%p)",
143                   GetDescription(), pszFilename, nXSize, nYSize, nBands,
144                   GDALGetDataTypeName( eType ),
145                   papszParmList );
146              
147         poDS = pfnCreate( pszFilename, nXSize, nYSize, nBands, eType,
148                           papszParmList );
149
150         if( poDS != NULL )
151         {
152             if( poDS->GetDescription() == NULL
153                 || strlen(poDS->GetDescription()) == 0 )
154                 poDS->SetDescription( pszFilename );
155
156             if( poDS->poDriver == NULL )
157                 poDS->poDriver = this;
158         }
159
160         return poDS;
161     }
162 }
163
164 /************************************************************************/
165 /*                             GDALCreate()                             */
166 /************************************************************************/
167
168 /**
169  * @see GDALDriver::Create()
170  */
171
172 GDALDatasetH CPL_DLL GDALCreate( GDALDriverH hDriver,
173                                  const char * pszFilename,
174                                  int nXSize, int nYSize, int nBands,
175                                  GDALDataType eBandType,
176                                  char ** papszOptions )
177
178 {
179     return( ((GDALDriver *) hDriver)->Create( pszFilename,
180                                               nXSize, nYSize, nBands,
181                                               eBandType, papszOptions ) );
182 }
183
184 /************************************************************************/
185 /*                             CreateCopy()                             */
186 /************************************************************************/
187
188 /**
189  * Create a copy of a dataset.
190  *
191  * This method will attempt to create a copy of a raster dataset with the
192  * indicated filename, and in this drivers format.  Band number, size,
193  * type, projection, geotransform and so forth are all to be copied from
194  * the provided template dataset. 
195  *
196  * Note that many sequential write once formats (such as JPEG and PNG) don't
197  * implement the Create() method but do implement this CreateCopy() method.
198  * If the driver doesn't implement CreateCopy(), but does implement Create()
199  * then the default CreateCopy() mechanism built on calling Create() will
200  * be used.                                                             
201  *
202  * It is intended that CreateCopy() would often be used with a source dataset
203  * which is a virtual dataset allowing configuration of band types, and
204  * other information without actually duplicating raster data.  This virtual
205  * dataset format hasn't yet been implemented at the time of this documentation
206  * being written.
207  *
208  * @param pszFilename the name for the new dataset.
209  * @param poSrcDS the dataset being duplicated.
210  * @param bStrict TRUE if the copy must be strictly equivelent, or more
211  * normally FALSE indicating that the copy may adapt as needed for the
212  * output format.
213  * @param papszOptions additional format dependent options controlling
214  * creation of the output file.
215  * @param pfnProgress a function to be used to report progress of the copy.
216  * @param pProgressData application data passed into progress function.
217  *
218  * @return a pointer to the newly created dataset (may be read-only access).
219  */
220
221 GDALDataset *GDALDriver::CreateCopy( const char * pszFilename,
222                                      GDALDataset * poSrcDS,
223                                      int bStrict, char ** papszOptions,
224                                      GDALProgressFunc pfnProgress,
225                                      void * pProgressData )
226
227 {
228     if( pfnProgress == NULL )
229         pfnProgress = GDALDummyProgress;
230
231 /* -------------------------------------------------------------------- */
232 /*      If the format provides a CreateCopy() method use that,          */
233 /*      otherwise fallback to the internal implementation using the     */
234 /*      Create() method.                                                */
235 /* -------------------------------------------------------------------- */
236     if( pfnCreateCopy != NULL )
237     {
238         GDALDataset *poDstDS;
239
240         poDstDS = pfnCreateCopy( pszFilename, poSrcDS, bStrict, papszOptions,
241                                  pfnProgress, pProgressData );
242         if( poDstDS != NULL )
243         {
244             if( poDstDS->GetDescription() == NULL
245                 || strlen(poDstDS->GetDescription()) > 0 )
246                 poDstDS->SetDescription( pszFilename );
247
248             if( poDstDS->poDriver == NULL )
249                 poDstDS->poDriver = this;
250         }
251
252         return poDstDS;
253     }
254    
255 /* -------------------------------------------------------------------- */
256 /*      Create destination dataset.                                     */
257 /* -------------------------------------------------------------------- */
258     GDALDataset  *poDstDS;
259     int          nXSize = poSrcDS->GetRasterXSize();
260     int          nYSize = poSrcDS->GetRasterYSize();
261     GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
262     CPLErr       eErr;
263
264     CPLDebug( "GDAL", "Using default GDALDriver::CreateCopy implementation." );
265
266     if( !pfnProgress( 0.0, NULL, pProgressData ) )
267     {
268         CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
269         return NULL;
270     }
271
272     poDstDS = Create( pszFilename, nXSize, nYSize,
273                       poSrcDS->GetRasterCount(), eType, papszOptions );
274
275     if( poDstDS == NULL )
276         return NULL;
277
278 /* -------------------------------------------------------------------- */
279 /*      Try setting the projection and geotransform if it seems         */
280 /*      suitable.  For now we don't try and copy GCPs, though I         */
281 /*      suppose we should. Also copy metadata.                          */
282 /* -------------------------------------------------------------------- */
283     double      adfGeoTransform[6];
284
285     if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None
286         && (adfGeoTransform[0] != 0.0
287             || adfGeoTransform[1] != 1.0
288             || adfGeoTransform[2] != 0.0
289             || adfGeoTransform[3] != 0.0
290             || adfGeoTransform[4] != 0.0
291             || adfGeoTransform[5] != 1.0) )
292     {
293         poDstDS->SetGeoTransform( adfGeoTransform );
294     }
295
296     if( poSrcDS->GetProjectionRef() != NULL
297         && strlen(poSrcDS->GetProjectionRef()) > 0 )
298     {
299         poDstDS->SetProjection( poSrcDS->GetProjectionRef() );
300     }
301
302     poDstDS->SetMetadata( poSrcDS->GetMetadata() );
303
304 /* -------------------------------------------------------------------- */
305 /*      Loop copying bands.                                             */
306 /* -------------------------------------------------------------------- */
307     for( int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++ )
308     {
309         GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
310         GDALRasterBand *poDstBand = poDstDS->GetRasterBand( iBand+1 );
311
312 /* -------------------------------------------------------------------- */
313 /*      Do we need to copy a colortable or other metadata?              */
314 /* -------------------------------------------------------------------- */
315         GDALColorTable *poCT;
316
317         poCT = poSrcBand->GetColorTable();
318         if( poCT != NULL )
319             poDstBand->SetColorTable( poCT );
320
321         if( strlen(poSrcBand->GetDescription()) > 0 )
322             poDstBand->SetDescription( poSrcBand->GetDescription() );
323
324         poDstBand->SetMetadata( poSrcBand->GetMetadata() );
325
326 /* -------------------------------------------------------------------- */
327 /*      Copy image data.                                                */
328 /* -------------------------------------------------------------------- */
329         void           *pData;
330
331         pData = CPLMalloc(nXSize * GDALGetDataTypeSize(eType) / 8);
332
333         for( int iLine = 0; iLine < nYSize; iLine++ )
334         {
335             eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
336                                         pData, nXSize, 1, eType, 0, 0 );
337             if( eErr != CE_None )
338             {
339                 return NULL;
340             }
341            
342             eErr = poDstBand->RasterIO( GF_Write, 0, iLine, nXSize, 1,
343                                         pData, nXSize, 1, eType, 0, 0 );
344
345             if( eErr != CE_None )
346             {
347                 return NULL;
348             }
349
350             if( !pfnProgress( (iBand + (iLine+1) / (double) nYSize)
351                               / (double) poSrcDS->GetRasterCount(),
352                               NULL, pProgressData ) )
353             {
354                 CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
355                 delete poDstDS;
356                 Delete( pszFilename );
357                 return NULL;
358             }
359         }
360
361         CPLFree( pData );
362     }
363
364     return poDstDS;
365 }
366
367 /************************************************************************/
368 /*                           GDALCreateCopy()                           */
369 /************************************************************************/
370
371 /**
372  * @see GDALDriver::CreateCopy()
373  */
374
375 GDALDatasetH GDALCreateCopy( GDALDriverH hDriver,
376                              const char * pszFilename,
377                              GDALDatasetH hSrcDS,
378                              int bStrict, char ** papszOptions,
379                              GDALProgressFunc pfnProgress,
380                              void * pProgressData )
381
382 {
383     return (GDALDatasetH) ((GDALDriver *) hDriver)->
384         CreateCopy( pszFilename, (GDALDataset *) hSrcDS, bStrict, papszOptions,
385                     pfnProgress, pProgressData );
386 }
387
388 /************************************************************************/
389 /*                               Delete()                               */
390 /************************************************************************/
391
392 /**
393  * Delete named dataset.
394  *
395  * The driver will attempt to delete the named dataset in a driver specific
396  * fashion.  Full featured drivers will delete all associated files,
397  * database objects, or whatever is appropriate.  The default behaviour when
398  * no driver specific behaviour is provided is to attempt to delete the
399  * passed name as a single file.
400  *
401  * It is unwise to have open dataset handles on this dataset when it is
402  * deleted.
403  *
404  * Equivelent of the C function GDALDeleteDataset().
405  *
406  * @param pszFilename name of dataset to delete.
407  *
408  * @return CE_None on success, or CE_Failure if the operation fails.
409  */
410
411 CPLErr GDALDriver::Delete( const char * pszFilename )
412
413 {
414     if( pfnDelete != NULL )
415         return pfnDelete( pszFilename );
416     else
417     {
418         VSIStatBuf      sStat;
419
420         if( VSIStat( pszFilename, &sStat ) == 0 && VSI_ISREG( sStat.st_mode ) )
421         {
422             if( VSIUnlink( pszFilename ) == 0 )
423                 return CE_None;
424             else
425             {
426                 CPLError( CE_Failure, CPLE_AppDefined,
427                           "%s: Attempt to unlink %s failed.\n",
428                           GetDescription(), pszFilename );
429                 return CE_Failure;
430             }
431         }
432         else
433         {
434             CPLError( CE_Failure, CPLE_AppDefined,
435                       "%s: Unable to delete %s, not a file.\n",
436                       GetDescription(), pszFilename );
437             return CE_Failure;
438         }
439     }
440 }
441
442 /************************************************************************/
443 /*                             GDALDelete()                             */
444 /************************************************************************/
445
446 /**
447  * @see GDALDriver::Delete()
448  */
449
450 CPLErr GDALDeleteDataset( GDALDriverH hDriver, const char * pszFilename )
451
452 {
453     return ((GDALDriver *) hDriver)->Delete( pszFilename );
454 }
455
456 /************************************************************************/
457 /*                       GDALGetDriverShortName()                       */
458 /************************************************************************/
459
460 const char * GDALGetDriverShortName( GDALDriverH hDriver )
461
462 {
463     if( hDriver == NULL )
464         return NULL;
465     else
466         return ((GDALDriver *) hDriver)->GetDescription();
467 }
468
469 /************************************************************************/
470 /*                       GDALGetDriverLongName()                        */
471 /************************************************************************/
472
473 const char * GDALGetDriverLongName( GDALDriverH hDriver )
474
475 {
476     if( hDriver == NULL )
477         return NULL;
478
479     const char *pszLongName =
480         ((GDALDriver *) hDriver)->GetMetadataItem( GDAL_DMD_LONGNAME );
481
482     if( pszLongName == NULL )
483         return "";
484     else
485         return pszLongName;
486 }
487
488 /************************************************************************/
489 /*                       GDALGetDriverHelpTopic()                       */
490 /************************************************************************/
491
492 const char * GDALGetDriverHelpTopic( GDALDriverH hDriver )
493
494 {
495     if( hDriver == NULL )
496         return NULL;
497
498     return ((GDALDriver *) hDriver)->GetMetadataItem( GDAL_DMD_HELPTOPIC );
499 }
500
Note: See TracBrowser for help on using the browser.