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