1 /*
2 * keadataset.cpp
3 *
4 * Created by Pete Bunting on 01/08/2012.
5 * Copyright 2012 LibKEA. All rights reserved.
6 *
7 * This file is part of LibKEA.
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify,
13 * merge, publish, distribute, sublicense, and/or sell copies of the
14 * Software, and to permit persons to whom the Software is furnished
15 * to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
24 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
25 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 *
28 */
29
30 #include "keadataset.h"
31 #include "keaband.h"
32 #include "keacopy.h"
33 #include "../frmts/hdf5/hdf5vfl.h"
34
35 CPL_CVSID("$Id: keadataset.cpp fa752ad6eabafaf630a704e1892a9d837d683cb3 2021-03-06 17:04:38 +0100 Even Rouault $")
36
37 /************************************************************************/
38 /* KEADatasetDriverUnload() */
39 /************************************************************************/
40
KEADatasetDriverUnload(GDALDriver *)41 void KEADatasetDriverUnload(GDALDriver*)
42 {
43 HDF5VFLUnloadFileDriver();
44 }
45
46 // Function for converting a libkea type into a GDAL type
KEA_to_GDAL_Type(kealib::KEADataType ekeaType)47 GDALDataType KEA_to_GDAL_Type( kealib::KEADataType ekeaType )
48 {
49 GDALDataType egdalType = GDT_Unknown;
50 switch( ekeaType )
51 {
52 case kealib::kea_8int:
53 case kealib::kea_8uint:
54 egdalType = GDT_Byte;
55 break;
56 case kealib::kea_16int:
57 egdalType = GDT_Int16;
58 break;
59 case kealib::kea_32int:
60 egdalType = GDT_Int32;
61 break;
62 case kealib::kea_16uint:
63 egdalType = GDT_UInt16;
64 break;
65 case kealib::kea_32uint:
66 egdalType = GDT_UInt32;
67 break;
68 case kealib::kea_32float:
69 egdalType = GDT_Float32;
70 break;
71 case kealib::kea_64float:
72 egdalType = GDT_Float64;
73 break;
74 default:
75 egdalType = GDT_Unknown;
76 break;
77 }
78 return egdalType;
79 }
80
81 // function for converting a GDAL type to a kealib type
GDAL_to_KEA_Type(GDALDataType egdalType)82 kealib::KEADataType GDAL_to_KEA_Type( GDALDataType egdalType )
83 {
84 kealib::KEADataType ekeaType = kealib::kea_undefined;
85 switch( egdalType )
86 {
87 case GDT_Byte:
88 ekeaType = kealib::kea_8uint;
89 break;
90 case GDT_Int16:
91 ekeaType = kealib::kea_16int;
92 break;
93 case GDT_Int32:
94 ekeaType = kealib::kea_32int;
95 break;
96 case GDT_UInt16:
97 ekeaType = kealib::kea_16uint;
98 break;
99 case GDT_UInt32:
100 ekeaType = kealib::kea_32uint;
101 break;
102 case GDT_Float32:
103 ekeaType = kealib::kea_32float;
104 break;
105 case GDT_Float64:
106 ekeaType = kealib::kea_64float;
107 break;
108 default:
109 ekeaType = kealib::kea_undefined;
110 break;
111 }
112 return ekeaType;
113 }
114
115 // static function - pointer set in driver
Open(GDALOpenInfo * poOpenInfo)116 GDALDataset *KEADataset::Open( GDALOpenInfo * poOpenInfo )
117 {
118 if( Identify( poOpenInfo ) )
119 {
120 try
121 {
122 // try and open it in the appropriate mode
123 H5::H5File *pH5File;
124 if( poOpenInfo->eAccess == GA_ReadOnly )
125 {
126 // use the virtual driver so we can open files using
127 // /vsicurl etc
128 // do this same as libkea
129 H5::FileAccPropList keaAccessPlist = H5::FileAccPropList(H5::FileAccPropList::DEFAULT);
130 keaAccessPlist.setCache(kealib::KEA_MDC_NELMTS, kealib::KEA_RDCC_NELMTS,
131 kealib::KEA_RDCC_NBYTES, kealib::KEA_RDCC_W0);
132 keaAccessPlist.setSieveBufSize(kealib::KEA_SIEVE_BUF);
133 hsize_t blockSize = kealib::KEA_META_BLOCKSIZE;
134 keaAccessPlist.setMetaBlockSize(blockSize);
135 // but set the driver
136 keaAccessPlist.setDriver(HDF5VFLGetFileDriver(), nullptr);
137
138 const H5std_string keaImgFilePath(poOpenInfo->pszFilename);
139 pH5File = new H5::H5File(keaImgFilePath, H5F_ACC_RDONLY, H5::FileCreatPropList::DEFAULT, keaAccessPlist);
140 }
141 else
142 {
143 // Must be a local file
144 pH5File = kealib::KEAImageIO::openKeaH5RW( poOpenInfo->pszFilename );
145 }
146 // create the KEADataset object
147 KEADataset *pDataset = new KEADataset( pH5File, poOpenInfo->eAccess );
148
149 // set the description as the name
150 pDataset->SetDescription( poOpenInfo->pszFilename );
151
152 return pDataset;
153 }
154 catch (const kealib::KEAIOException &)
155 {
156 // was a problem - can't be a valid file
157 return nullptr;
158 }
159 }
160 else
161 {
162 // not a KEA file
163 return nullptr;
164 }
165 }
166
167 // static function- pointer set in driver
168 // this function is called in preference to Open
169 //
Identify(GDALOpenInfo * poOpenInfo)170 int KEADataset::Identify( GDALOpenInfo * poOpenInfo )
171 {
172
173 /* -------------------------------------------------------------------- */
174 /* Is it an HDF5 file? */
175 /* -------------------------------------------------------------------- */
176 static const char achSignature[] = "\211HDF\r\n\032\n";
177
178 if( poOpenInfo->pabyHeader == nullptr ||
179 memcmp(poOpenInfo->pabyHeader,achSignature,8) != 0 )
180 {
181 return 0;
182 }
183
184 // avoid using kealib::KEAImageIO::isKEAImage as this is likely
185 // to be too slow over curl etc (and doesn't take a HDF5 file handle
186 // anyway).
187 // Just test the extension
188 CPLString osExt(CPLGetExtension(poOpenInfo->pszFilename));
189 if( EQUAL(osExt, "KEA") )
190 return 1;
191 else
192 return 0;
193 }
194
195 // static function
CreateLL(const char * pszFilename,int nXSize,int nYSize,int nBands,GDALDataType eType,char ** papszParamList)196 H5::H5File *KEADataset::CreateLL( const char * pszFilename,
197 int nXSize, int nYSize, int nBands,
198 GDALDataType eType,
199 char ** papszParamList )
200 {
201 GDALDriverH hDriver = GDALGetDriverByName( "KEA" );
202 if( ( hDriver == nullptr ) || !GDALValidateCreationOptions( hDriver, papszParamList ) )
203 {
204 CPLError( CE_Failure, CPLE_OpenFailed,
205 "Attempt to create file `%s' failed. Invalid creation option(s)\n", pszFilename);
206 return nullptr;
207 }
208 // process any creation options in papszParamList
209 // default value
210 unsigned int nimageblockSize = kealib::KEA_IMAGE_CHUNK_SIZE;
211 // see if they have provided a different value
212 const char *pszValue = CSLFetchNameValue( papszParamList, "IMAGEBLOCKSIZE" );
213 if( pszValue != nullptr )
214 nimageblockSize = (unsigned int) atol( pszValue );
215
216 unsigned int nattblockSize = kealib::KEA_ATT_CHUNK_SIZE;
217 pszValue = CSLFetchNameValue( papszParamList, "ATTBLOCKSIZE" );
218 if( pszValue != nullptr )
219 nattblockSize = (unsigned int) atol( pszValue );
220
221 unsigned int nmdcElmts = kealib::KEA_MDC_NELMTS;
222 pszValue = CSLFetchNameValue( papszParamList, "MDC_NELMTS" );
223 if( pszValue != nullptr )
224 nmdcElmts = (unsigned int) atol( pszValue );
225
226 hsize_t nrdccNElmts = kealib::KEA_RDCC_NELMTS;
227 pszValue = CSLFetchNameValue( papszParamList, "RDCC_NELMTS" );
228 if( pszValue != nullptr )
229 nrdccNElmts = (unsigned int) atol( pszValue );
230
231 hsize_t nrdccNBytes = kealib::KEA_RDCC_NBYTES;
232 pszValue = CSLFetchNameValue( papszParamList, "RDCC_NBYTES" );
233 if( pszValue != nullptr )
234 nrdccNBytes = (unsigned int) atol( pszValue );
235
236 double nrdccW0 = kealib::KEA_RDCC_W0;
237 pszValue = CSLFetchNameValue( papszParamList, "RDCC_W0" );
238 if( pszValue != nullptr )
239 nrdccW0 = CPLAtof( pszValue );
240
241 hsize_t nsieveBuf = kealib::KEA_SIEVE_BUF;
242 pszValue = CSLFetchNameValue( papszParamList, "SIEVE_BUF" );
243 if( pszValue != nullptr )
244 nsieveBuf = (unsigned int) atol( pszValue );
245
246 hsize_t nmetaBlockSize = kealib::KEA_META_BLOCKSIZE;
247 pszValue = CSLFetchNameValue( papszParamList, "META_BLOCKSIZE" );
248 if( pszValue != nullptr )
249 nmetaBlockSize = (unsigned int) atol( pszValue );
250
251 unsigned int ndeflate = kealib::KEA_DEFLATE;
252 pszValue = CSLFetchNameValue( papszParamList, "DEFLATE" );
253 if( pszValue != nullptr )
254 ndeflate = (unsigned int) atol( pszValue );
255
256 kealib::KEADataType keaDataType = GDAL_to_KEA_Type( eType );
257 if( nBands > 0 && keaDataType == kealib::kea_undefined )
258 {
259 CPLError( CE_Failure, CPLE_NotSupported,
260 "Data type %s not supported in KEA",
261 GDALGetDataTypeName(eType) );
262 return nullptr;
263 }
264
265 try
266 {
267 // now create it
268 H5::H5File *keaImgH5File = kealib::KEAImageIO::createKEAImage( pszFilename,
269 keaDataType,
270 nXSize, nYSize, nBands,
271 nullptr, nullptr, nimageblockSize,
272 nattblockSize, nmdcElmts, nrdccNElmts,
273 nrdccNBytes, nrdccW0, nsieveBuf,
274 nmetaBlockSize, ndeflate );
275 return keaImgH5File;
276 }
277 catch (kealib::KEAIOException &e)
278 {
279 CPLError( CE_Failure, CPLE_OpenFailed,
280 "Attempt to create file `%s' failed. Error: %s\n",
281 pszFilename, e.what() );
282 return nullptr;
283 }
284 }
285
286 // static function- pointer set in driver
Create(const char * pszFilename,int nXSize,int nYSize,int nBands,GDALDataType eType,char ** papszParamList)287 GDALDataset *KEADataset::Create( const char * pszFilename,
288 int nXSize, int nYSize, int nBands,
289 GDALDataType eType,
290 char ** papszParamList )
291 {
292 H5::H5File *keaImgH5File = CreateLL( pszFilename, nXSize, nYSize, nBands,
293 eType, papszParamList );
294 if( keaImgH5File == nullptr )
295 return nullptr;
296
297 bool bThematic =
298 CPLTestBool(CSLFetchNameValueDef( papszParamList, "THEMATIC", "FALSE" ));
299
300 try
301 {
302 // create our dataset object
303 KEADataset *pDataset = new KEADataset( keaImgH5File, GA_Update );
304
305 pDataset->SetDescription( pszFilename );
306
307 // set all to thematic if asked
308 if( bThematic )
309 {
310 for( int nCount = 0; nCount < nBands; nCount++ )
311 {
312 GDALRasterBand *pBand = pDataset->GetRasterBand(nCount+1);
313 pBand->SetMetadataItem("LAYER_TYPE", "thematic");
314 }
315 }
316
317 return pDataset;
318 }
319 catch (kealib::KEAIOException &e)
320 {
321 CPLError( CE_Failure, CPLE_OpenFailed,
322 "Attempt to create file `%s' failed. Error: %s\n",
323 pszFilename, e.what() );
324 return nullptr;
325 }
326 }
327
CreateCopy(const char * pszFilename,GDALDataset * pSrcDs,CPL_UNUSED int bStrict,char ** papszParamList,GDALProgressFunc pfnProgress,void * pProgressData)328 GDALDataset *KEADataset::CreateCopy( const char * pszFilename, GDALDataset *pSrcDs,
329 CPL_UNUSED int bStrict, char ** papszParamList,
330 GDALProgressFunc pfnProgress, void *pProgressData )
331 {
332 // get the data out of the input dataset
333 int nXSize = pSrcDs->GetRasterXSize();
334 int nYSize = pSrcDs->GetRasterYSize();
335 int nBands = pSrcDs->GetRasterCount();
336
337 GDALDataType eType = (nBands == 0) ? GDT_Unknown : pSrcDs->GetRasterBand(1)->GetRasterDataType();
338 H5::H5File *keaImgH5File = CreateLL( pszFilename, nXSize, nYSize, nBands,
339 eType, papszParamList );
340 if( keaImgH5File == nullptr )
341 return nullptr;
342
343 bool bThematic =
344 CPLTestBool(CSLFetchNameValueDef( papszParamList, "THEMATIC", "FALSE" ));
345
346 try
347 {
348 // create the imageio
349 kealib::KEAImageIO *pImageIO = new kealib::KEAImageIO();
350
351 // open the file
352 pImageIO->openKEAImageHeader( keaImgH5File );
353
354 // copy file
355 if( !KEACopyFile( pSrcDs, pImageIO, pfnProgress, pProgressData) )
356 {
357 delete pImageIO;
358 return nullptr;
359 }
360
361 // close it
362 try
363 {
364 pImageIO->close();
365 }
366 catch (const kealib::KEAIOException &)
367 {
368 }
369 delete pImageIO;
370
371 // now open it again - because the constructor loads all the info
372 // in we need to copy the data first....
373 keaImgH5File = kealib::KEAImageIO::openKeaH5RW( pszFilename );
374
375 // and wrap it in a dataset
376 KEADataset *pDataset = new KEADataset( keaImgH5File, GA_Update );
377 pDataset->SetDescription( pszFilename );
378
379 // set all to thematic if asked - overrides whatever set by CopyFile
380 if( bThematic )
381 {
382 for( int nCount = 0; nCount < nBands; nCount++ )
383 {
384 GDALRasterBand *pBand = pDataset->GetRasterBand(nCount+1);
385 pBand->SetMetadataItem("LAYER_TYPE", "thematic");
386 }
387 }
388
389 for( int nCount = 0; nCount < nBands; nCount++ )
390 {
391 pDataset->GetRasterBand(nCount+1)->SetColorInterpretation(
392 pSrcDs->GetRasterBand(nCount+1)->GetColorInterpretation());
393 }
394
395 // KEA has no concept of per-dataset mask band for now.
396 for( int nCount = 0; nCount < nBands; nCount++ )
397 {
398 if( pSrcDs->GetRasterBand(nCount+1)->GetMaskFlags() == 0 ) // Per-band mask
399 {
400 pDataset->GetRasterBand(nCount+1)->CreateMaskBand(0);
401 if( GDALRasterBandCopyWholeRaster(
402 (GDALRasterBandH)pSrcDs->GetRasterBand(nCount+1)->GetMaskBand(),
403 (GDALRasterBandH)pDataset->GetRasterBand(nCount+1)->GetMaskBand(),
404 nullptr, nullptr, nullptr) != CE_None )
405 {
406 delete pDataset;
407 return nullptr;
408 }
409 }
410 }
411
412 return pDataset;
413 }
414 catch (kealib::KEAException &e)
415 {
416 CPLError( CE_Failure, CPLE_OpenFailed,
417 "Attempt to create file `%s' failed. Error: %s\n",
418 pszFilename, e.what() );
419 return nullptr;
420 }
421 }
422
423 // constructor
KEADataset(H5::H5File * keaImgH5File,GDALAccess eAccessIn)424 KEADataset::KEADataset( H5::H5File *keaImgH5File, GDALAccess eAccessIn )
425 {
426 this->m_hMutex = CPLCreateMutex();
427 CPLReleaseMutex( this->m_hMutex );
428 try
429 {
430 // Create the image IO and initialize the refcount.
431 m_pImageIO = new kealib::KEAImageIO();
432 m_pRefcount = new LockedRefCount();
433
434 // NULL until we read them in.
435 m_papszMetadataList = nullptr;
436 m_pGCPs = nullptr;
437 m_pszGCPProjection = nullptr;
438
439 // open the file
440 m_pImageIO->openKEAImageHeader( keaImgH5File );
441 kealib::KEAImageSpatialInfo *pSpatialInfo = m_pImageIO->getSpatialInfo();
442
443 // get the dimensions
444 this->nBands = m_pImageIO->getNumOfImageBands();
445 this->nRasterXSize = static_cast<int>(pSpatialInfo->xSize);
446 this->nRasterYSize = static_cast<int>(pSpatialInfo->ySize);
447 this->eAccess = eAccessIn;
448
449 // create all the bands
450 for( int nCount = 0; nCount < nBands; nCount++ )
451 {
452 // Note: GDAL uses indices starting at 1 and so does kealib.
453 // Create band object.
454 KEARasterBand *pBand = new KEARasterBand(
455 this, nCount + 1, eAccess, m_pImageIO, m_pRefcount );
456 // read in overviews
457 pBand->readExistingOverviews();
458 // set the band into this dataset
459 this->SetBand( nCount + 1, pBand );
460 }
461
462 // read in the metadata
463 this->UpdateMetadataList();
464 }
465 catch (const kealib::KEAIOException &e)
466 {
467 // ignore?
468 CPLError( CE_Warning, CPLE_AppDefined,
469 "Caught exception in KEADataset constructor %s", e.what() );
470 }
471 }
472
~KEADataset()473 KEADataset::~KEADataset()
474 {
475 {
476 CPLMutexHolderD( &m_hMutex );
477 // destroy the metadata
478 CSLDestroy(m_papszMetadataList);
479 this->DestroyGCPs();
480 CPLFree( m_pszGCPProjection );
481 }
482 if( m_pRefcount->DecRef() )
483 {
484 try
485 {
486 m_pImageIO->close();
487 }
488 catch (const kealib::KEAIOException &)
489 {
490 }
491 delete m_pImageIO;
492 delete m_pRefcount;
493 }
494
495 CPLDestroyMutex( m_hMutex );
496 m_hMutex = nullptr;
497 }
498
499 // read in the metadata into our CSLStringList
UpdateMetadataList()500 void KEADataset::UpdateMetadataList()
501 {
502 CPLMutexHolderD( &m_hMutex );
503 std::vector< std::pair<std::string, std::string> > odata;
504 // get all the metadata
505 odata = this->m_pImageIO->getImageMetaData();
506 for(std::vector< std::pair<std::string, std::string> >::iterator iterMetaData = odata.begin(); iterMetaData != odata.end(); ++iterMetaData)
507 {
508 m_papszMetadataList = CSLSetNameValue(m_papszMetadataList, iterMetaData->first.c_str(), iterMetaData->second.c_str());
509 }
510 }
511
512 // read in the geotransform
GetGeoTransform(double * padfTransform)513 CPLErr KEADataset::GetGeoTransform( double * padfTransform )
514 {
515 try
516 {
517 kealib::KEAImageSpatialInfo *pSpatialInfo = m_pImageIO->getSpatialInfo();
518 // GDAL uses an array format
519 padfTransform[0] = pSpatialInfo->tlX;
520 padfTransform[1] = pSpatialInfo->xRes;
521 padfTransform[2] = pSpatialInfo->xRot;
522 padfTransform[3] = pSpatialInfo->tlY;
523 padfTransform[4] = pSpatialInfo->yRot;
524 padfTransform[5] = pSpatialInfo->yRes;
525
526 return CE_None;
527 }
528 catch (const kealib::KEAIOException &e)
529 {
530 CPLError( CE_Warning, CPLE_AppDefined,
531 "Unable to read geotransform: %s", e.what() );
532 return CE_Failure;
533 }
534 }
535
536 // read in the projection ref
_GetProjectionRef()537 const char *KEADataset::_GetProjectionRef()
538 {
539 try
540 {
541 kealib::KEAImageSpatialInfo *pSpatialInfo = m_pImageIO->getSpatialInfo();
542 // should be safe since pSpatialInfo should be around a while...
543 return pSpatialInfo->wktString.c_str();
544 }
545 catch (const kealib::KEAIOException &)
546 {
547 return nullptr;
548 }
549 }
550
551 // set the geotransform
SetGeoTransform(double * padfTransform)552 CPLErr KEADataset::SetGeoTransform (double *padfTransform )
553 {
554 try
555 {
556 // get the spatial info and update it
557 kealib::KEAImageSpatialInfo *pSpatialInfo = m_pImageIO->getSpatialInfo();
558 // convert back from GDAL's array format
559 pSpatialInfo->tlX = padfTransform[0];
560 pSpatialInfo->xRes = padfTransform[1];
561 pSpatialInfo->xRot = padfTransform[2];
562 pSpatialInfo->tlY = padfTransform[3];
563 pSpatialInfo->yRot = padfTransform[4];
564 pSpatialInfo->yRes = padfTransform[5];
565
566 m_pImageIO->setSpatialInfo( pSpatialInfo );
567 return CE_None;
568 }
569 catch (const kealib::KEAIOException &e)
570 {
571 CPLError( CE_Warning, CPLE_AppDefined,
572 "Unable to write geotransform: %s", e.what() );
573 return CE_Failure;
574 }
575 }
576
577 // set the projection
_SetProjection(const char * pszWKT)578 CPLErr KEADataset::_SetProjection( const char *pszWKT )
579 {
580 try
581 {
582 // get the spatial info and update it
583 kealib::KEAImageSpatialInfo *pSpatialInfo = m_pImageIO->getSpatialInfo();
584
585 pSpatialInfo->wktString = pszWKT;
586
587 m_pImageIO->setSpatialInfo( pSpatialInfo );
588 return CE_None;
589 }
590 catch (const kealib::KEAIOException &e)
591 {
592 CPLError( CE_Warning, CPLE_AppDefined,
593 "Unable to write projection: %s", e.what() );
594 return CE_Failure;
595 }
596 }
597
598 // Thought this might be handy to pass back to the application
GetInternalHandle(const char *)599 void * KEADataset::GetInternalHandle(const char *)
600 {
601 return m_pImageIO;
602 }
603
604 // this is called by GDALDataset::BuildOverviews. we implement this function to support
605 // building of overviews
IBuildOverviews(const char * pszResampling,int nOverviews,int * panOverviewList,int nListBands,int * panBandList,GDALProgressFunc pfnProgress,void * pProgressData)606 CPLErr KEADataset::IBuildOverviews(const char *pszResampling, int nOverviews, int *panOverviewList,
607 int nListBands, int *panBandList, GDALProgressFunc pfnProgress,
608 void *pProgressData)
609 {
610 // go through the list of bands that have been passed in
611 int nCurrentBand, nOK = 1;
612 for( int nBandCount = 0; (nBandCount < nListBands) && nOK; nBandCount++ )
613 {
614 // get the band number
615 nCurrentBand = panBandList[nBandCount];
616 // get the band
617 KEARasterBand *pBand = (KEARasterBand*)this->GetRasterBand(nCurrentBand);
618 // create the overview object
619 pBand->CreateOverviews( nOverviews, panOverviewList );
620
621 // get GDAL to do the hard work. It will calculate the overviews and write them
622 // back into the objects
623 if( GDALRegenerateOverviews( (GDALRasterBandH)pBand, nOverviews, (GDALRasterBandH*)pBand->GetOverviewList(),
624 pszResampling, pfnProgress, pProgressData ) != CE_None )
625 {
626 nOK = 0;
627 }
628 }
629 if( !nOK )
630 {
631 return CE_Failure;
632 }
633 else
634 {
635 return CE_None;
636 }
637 }
638
639 // set a single metadata item
SetMetadataItem(const char * pszName,const char * pszValue,const char * pszDomain)640 CPLErr KEADataset::SetMetadataItem(const char *pszName, const char *pszValue, const char *pszDomain)
641 {
642 CPLMutexHolderD( &m_hMutex );
643 // only deal with 'default' domain - no geolocation etc
644 if( ( pszDomain != nullptr ) && ( *pszDomain != '\0' ) )
645 return CE_Failure;
646
647 try
648 {
649 this->m_pImageIO->setImageMetaData(pszName, pszValue );
650 // CSLSetNameValue will update if already there
651 m_papszMetadataList = CSLSetNameValue( m_papszMetadataList, pszName, pszValue );
652 return CE_None;
653 }
654 catch (const kealib::KEAIOException &e)
655 {
656 CPLError( CE_Failure, CPLE_AppDefined,
657 "Unable to write metadata: %s", e.what() );
658 return CE_Failure;
659 }
660 }
661
662 // get a single metadata item
GetMetadataItem(const char * pszName,const char * pszDomain)663 const char *KEADataset::GetMetadataItem (const char *pszName, const char *pszDomain)
664 {
665 CPLMutexHolderD( &m_hMutex );
666 // only deal with 'default' domain - no geolocation etc
667 if( ( pszDomain != nullptr ) && ( *pszDomain != '\0' ) )
668 return nullptr;
669 // string returned from CSLFetchNameValue should be persistent
670 return CSLFetchNameValue(m_papszMetadataList, pszName);
671 }
672
673 // get the whole metadata as CSLStringList - note may be thread safety issues
GetMetadata(const char * pszDomain)674 char **KEADataset::GetMetadata(const char *pszDomain)
675 {
676 // only deal with 'default' domain - no geolocation etc
677 if( ( pszDomain != nullptr ) && ( *pszDomain != '\0' ) )
678 return nullptr;
679 // this is what we store it as anyway
680 return m_papszMetadataList;
681 }
682
683 // set the whole metadata as a CSLStringList
SetMetadata(char ** papszMetadata,const char * pszDomain)684 CPLErr KEADataset::SetMetadata(char **papszMetadata, const char *pszDomain)
685 {
686 CPLMutexHolderD( &m_hMutex );
687 // only deal with 'default' domain - no geolocation etc
688 if( ( pszDomain != nullptr ) && ( *pszDomain != '\0' ) )
689 return CE_Failure;
690
691 int nIndex = 0;
692 try
693 {
694 // go through each item
695 while( papszMetadata[nIndex] != nullptr )
696 {
697 // get the value/name
698 char *pszName = nullptr;
699 const char *pszValue =
700 CPLParseNameValue( papszMetadata[nIndex], &pszName );
701 if( pszValue == nullptr )
702 pszValue = "";
703 if( pszName != nullptr )
704 {
705 // set it with imageio
706 this->m_pImageIO->setImageMetaData(pszName, pszValue );
707 CPLFree(pszName);
708 }
709 nIndex++;
710 }
711 }
712 catch (const kealib::KEAIOException &e)
713 {
714 CPLError( CE_Failure, CPLE_AppDefined,
715 "Unable to write metadata: %s", e.what() );
716 return CE_Failure;
717 }
718
719 // destroy our one and replace it
720 CSLDestroy(m_papszMetadataList);
721 m_papszMetadataList = CSLDuplicate(papszMetadata);
722 return CE_None;
723 }
724
AddBand(GDALDataType eType,char ** papszOptions)725 CPLErr KEADataset::AddBand(GDALDataType eType, char **papszOptions)
726 {
727 // process any creation options in papszOptions
728 unsigned int nimageBlockSize = kealib::KEA_IMAGE_CHUNK_SIZE;
729 unsigned int nattBlockSize = kealib::KEA_ATT_CHUNK_SIZE;
730 unsigned int ndeflate = kealib::KEA_DEFLATE;
731 if (papszOptions != nullptr) {
732 const char *pszValue = CSLFetchNameValue(papszOptions,"IMAGEBLOCKSIZE");
733 if ( pszValue != nullptr ) {
734 nimageBlockSize = atoi(pszValue);
735 }
736
737 pszValue = CSLFetchNameValue(papszOptions, "ATTBLOCKSIZE");
738 if (pszValue != nullptr) {
739 nattBlockSize = atoi(pszValue);
740 }
741
742 pszValue = CSLFetchNameValue(papszOptions, "DEFLATE");
743 if (pszValue != nullptr) {
744 ndeflate = atoi(pszValue);
745 }
746 }
747
748 kealib::KEADataType keaDataType = GDAL_to_KEA_Type( eType );
749 if( keaDataType == kealib::kea_undefined )
750 {
751 CPLError( CE_Failure, CPLE_NotSupported,
752 "Data type %s not supported in KEA",
753 GDALGetDataTypeName(eType) );
754 return CE_Failure;
755 }
756
757 try {
758 m_pImageIO->addImageBand(keaDataType, "", nimageBlockSize,
759 nattBlockSize, ndeflate);
760 } catch (const kealib::KEAIOException &e) {
761 CPLError( CE_Failure, CPLE_AppDefined,
762 "Unable to create band: %s", e.what() );
763 return CE_Failure;
764 }
765
766 // create a new band and add it to the dataset
767 // note GDAL uses indices starting at 1 and so does kealib
768 KEARasterBand *pBand = new KEARasterBand(this, this->nBands+1, this->eAccess,
769 m_pImageIO, m_pRefcount);
770 this->SetBand(this->nBands+1, pBand);
771
772 return CE_None;
773 }
774
GetGCPCount()775 int KEADataset::GetGCPCount()
776 {
777 try
778 {
779 return m_pImageIO->getGCPCount();
780 }
781 catch (const kealib::KEAIOException &)
782 {
783 return 0;
784 }
785 }
786
_GetGCPProjection()787 const char* KEADataset::_GetGCPProjection()
788 {
789 CPLMutexHolderD( &m_hMutex );
790 if( m_pszGCPProjection == nullptr )
791 {
792 try
793 {
794 std::string sProj = m_pImageIO->getGCPProjection();
795 m_pszGCPProjection = CPLStrdup( sProj.c_str() );
796 }
797 catch (const kealib::KEAIOException &)
798 {
799 return nullptr;
800 }
801 }
802 return m_pszGCPProjection;
803 }
804
GetGCPs()805 const GDAL_GCP* KEADataset::GetGCPs()
806 {
807 CPLMutexHolderD( &m_hMutex );
808 if( m_pGCPs == nullptr )
809 {
810 // convert to GDAL data structures
811 try
812 {
813 unsigned int nCount = m_pImageIO->getGCPCount();
814 std::vector<kealib::KEAImageGCP*> *pKEAGCPs = m_pImageIO->getGCPs();
815
816 m_pGCPs = (GDAL_GCP*)CPLCalloc(nCount, sizeof(GDAL_GCP));
817 for( unsigned int nIndex = 0; nIndex < nCount; nIndex++)
818 {
819 GDAL_GCP *pGCP = &m_pGCPs[nIndex];
820 kealib::KEAImageGCP *pKEAGCP = pKEAGCPs->at(nIndex);
821 pGCP->pszId = CPLStrdup( pKEAGCP->pszId.c_str() );
822 pGCP->pszInfo = CPLStrdup( pKEAGCP->pszInfo.c_str() );
823 pGCP->dfGCPPixel = pKEAGCP->dfGCPPixel;
824 pGCP->dfGCPLine = pKEAGCP->dfGCPLine;
825 pGCP->dfGCPX = pKEAGCP->dfGCPX;
826 pGCP->dfGCPY = pKEAGCP->dfGCPY;
827 pGCP->dfGCPZ = pKEAGCP->dfGCPZ;
828
829 delete pKEAGCP;
830 }
831
832 delete pKEAGCPs;
833 }
834 catch (const kealib::KEAIOException &)
835 {
836 return nullptr;
837 }
838 }
839 return m_pGCPs;
840 }
841
_SetGCPs(int nGCPCount,const GDAL_GCP * pasGCPList,const char * pszGCPProjection)842 CPLErr KEADataset::_SetGCPs(int nGCPCount, const GDAL_GCP *pasGCPList, const char *pszGCPProjection)
843 {
844 CPLMutexHolderD( &m_hMutex );
845 this->DestroyGCPs();
846 CPLFree( m_pszGCPProjection );
847 m_pszGCPProjection = nullptr;
848 CPLErr result = CE_None;
849
850 std::vector<kealib::KEAImageGCP*> *pKEAGCPs = new std::vector<kealib::KEAImageGCP*>(nGCPCount);
851 for( int nIndex = 0; nIndex < nGCPCount; nIndex++ )
852 {
853 const GDAL_GCP *pGCP = &pasGCPList[nIndex];
854 kealib::KEAImageGCP *pKEA = new kealib::KEAImageGCP;
855 pKEA->pszId = pGCP->pszId;
856 pKEA->pszInfo = pGCP->pszInfo;
857 pKEA->dfGCPPixel = pGCP->dfGCPPixel;
858 pKEA->dfGCPLine = pGCP->dfGCPLine;
859 pKEA->dfGCPX = pGCP->dfGCPX;
860 pKEA->dfGCPY = pGCP->dfGCPY;
861 pKEA->dfGCPZ = pGCP->dfGCPZ;
862 pKEAGCPs->at(nIndex) = pKEA;
863 }
864 try
865 {
866 m_pImageIO->setGCPs(pKEAGCPs, pszGCPProjection);
867 }
868 catch (const kealib::KEAIOException &e)
869 {
870 CPLError( CE_Warning, CPLE_AppDefined,
871 "Unable to write GCPs: %s", e.what() );
872 result = CE_Failure;
873 }
874
875 for( std::vector<kealib::KEAImageGCP*>::iterator itr = pKEAGCPs->begin(); itr != pKEAGCPs->end(); ++itr)
876 {
877 kealib::KEAImageGCP *pKEA = (*itr);
878 delete pKEA;
879 }
880 delete pKEAGCPs;
881
882 return result;
883 }
884
DestroyGCPs()885 void KEADataset::DestroyGCPs()
886 {
887 CPLMutexHolderD( &m_hMutex );
888 if( m_pGCPs != nullptr )
889 {
890 // we assume this is always the same as the internal list...
891 int nCount = this->GetGCPCount();
892 for( int nIndex = 0; nIndex < nCount; nIndex++ )
893 {
894 GDAL_GCP *pGCP = &m_pGCPs[nIndex];
895 CPLFree( pGCP->pszId );
896 CPLFree( pGCP->pszInfo );
897 }
898 CPLFree( m_pGCPs );
899 m_pGCPs = nullptr;
900 }
901 }
902