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