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