Line data Source code
1 : /*
2 : * keacopy.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 <cmath>
14 : #include "gdal_priv.h"
15 : #include "gdal_rat.h"
16 :
17 : #include "keacopy.h"
18 :
19 : // Support functions for CreateCopy()
20 :
21 : // Copies GDAL Band to KEA Band if nOverview == -1
22 : // Otherwise it is assumed we are writing to the specified overview
23 90 : static bool KEACopyRasterData(GDALRasterBand *pBand,
24 : kealib::KEAImageIO *pImageIO, int nBand,
25 : int nOverview, int nTotalBands,
26 : GDALProgressFunc pfnProgress, void *pProgressData)
27 : {
28 : // get some info
29 90 : kealib::KEADataType eKeaType = pImageIO->getImageBandDataType(nBand);
30 : unsigned int nBlockSize;
31 90 : if (nOverview == -1)
32 89 : nBlockSize = pImageIO->getImageBlockSize(nBand);
33 : else
34 1 : nBlockSize = pImageIO->getOverviewBlockSize(nBand, nOverview);
35 :
36 90 : GDALDataType eGDALType = pBand->GetRasterDataType();
37 90 : unsigned int nXSize = pBand->GetXSize();
38 90 : unsigned int nYSize = pBand->GetYSize();
39 :
40 : // allocate some space
41 90 : const int nPixelSize = GDALGetDataTypeSizeBytes(eGDALType);
42 90 : void *pData = VSIMalloc3(nPixelSize, nBlockSize, nBlockSize);
43 90 : if (pData == nullptr)
44 : {
45 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unable to allocate memory");
46 0 : return false;
47 : }
48 : // for progress
49 90 : const uint64_t nTotalBlocks =
50 90 : static_cast<uint64_t>(DIV_ROUND_UP(nXSize, nBlockSize)) *
51 90 : DIV_ROUND_UP(nYSize, nBlockSize);
52 90 : uint64_t nBlocksComplete = 0;
53 90 : double dLastFraction = -1;
54 : // go through the image
55 181 : for (unsigned int nY = 0; nY < nYSize; nY += nBlockSize)
56 : {
57 : // adjust for edge blocks
58 91 : unsigned int nysize = nBlockSize;
59 91 : unsigned int nytotalsize = nY + nBlockSize;
60 91 : if (nytotalsize > nYSize)
61 1 : nysize -= (nytotalsize - nYSize);
62 184 : for (unsigned int nX = 0; nX < nXSize; nX += nBlockSize)
63 : {
64 : // adjust for edge blocks
65 93 : unsigned int nxsize = nBlockSize;
66 93 : unsigned int nxtotalsize = nX + nBlockSize;
67 93 : if (nxtotalsize > nXSize)
68 2 : nxsize -= (nxtotalsize - nXSize);
69 :
70 : // read in from GDAL
71 186 : if (pBand->RasterIO(GF_Read, nX, nY, nxsize, nysize, pData, nxsize,
72 : nysize, eGDALType, nPixelSize,
73 93 : nPixelSize * nBlockSize, nullptr) != CE_None)
74 : {
75 0 : CPLError(CE_Failure, CPLE_AppDefined,
76 : "Unable to read block at %d %d\n", nX, nY);
77 0 : return false;
78 : }
79 : // write out to KEA
80 93 : if (nOverview == -1)
81 92 : pImageIO->writeImageBlock2Band(nBand, pData, nX, nY, nxsize,
82 : nysize, nBlockSize, nBlockSize,
83 : eKeaType);
84 : else
85 1 : pImageIO->writeToOverview(nBand, nOverview, pData, nX, nY,
86 : nxsize, nysize, nBlockSize,
87 : nBlockSize, eKeaType);
88 :
89 : // progress
90 93 : nBlocksComplete++;
91 93 : if (nOverview == -1)
92 : {
93 92 : double dFraction =
94 92 : (((double)nBlocksComplete / (double)nTotalBlocks) /
95 92 : (double)nTotalBands) +
96 92 : ((double)(nBand - 1) * (1.0 / (double)nTotalBands));
97 92 : if (dFraction != dLastFraction)
98 : {
99 92 : if (!pfnProgress(dFraction, nullptr, pProgressData))
100 : {
101 0 : CPLFree(pData);
102 0 : return false;
103 : }
104 92 : dLastFraction = dFraction;
105 : }
106 : }
107 : }
108 : }
109 :
110 90 : CPLFree(pData);
111 90 : return true;
112 : }
113 :
114 : // copies the raster attribute table
115 89 : static void KEACopyRAT(GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO,
116 : int nBand)
117 : {
118 89 : const GDALRasterAttributeTable *gdalAtt = pBand->GetDefaultRAT();
119 89 : if ((gdalAtt != nullptr) && (gdalAtt->GetRowCount() > 0))
120 : {
121 : // some operations depend on whether the input dataset is HFA
122 : int bInputHFA =
123 6 : pBand->GetDataset()->GetDriver() != nullptr &&
124 3 : EQUAL(pBand->GetDataset()->GetDriver()->GetDescription(), "HFA");
125 :
126 : kealib::KEAAttributeTable *keaAtt =
127 3 : pImageIO->getAttributeTable(kealib::kea_att_file, nBand);
128 :
129 : /*bool redDef = false;
130 : int redIdx = -1;
131 : bool greenDef = false;
132 : int greenIdx = -1;
133 : bool blueDef = false;
134 : int blueIdx = -1;
135 : bool alphaDef = false;
136 : int alphaIdx = -1;*/
137 :
138 3 : int numCols = gdalAtt->GetColumnCount();
139 : std::vector<kealib::KEAATTField *> *fields =
140 3 : new std::vector<kealib::KEAATTField *>();
141 : kealib::KEAATTField *field;
142 21 : for (int ni = 0; ni < numCols; ++ni)
143 : {
144 18 : field = new kealib::KEAATTField();
145 18 : field->name = gdalAtt->GetNameOfCol(ni);
146 :
147 18 : field->dataType = kealib::kea_att_string;
148 18 : switch (gdalAtt->GetTypeOfCol(ni))
149 : {
150 12 : case GFT_Integer:
151 12 : field->dataType = kealib::kea_att_int;
152 12 : break;
153 2 : case GFT_Real:
154 2 : field->dataType = kealib::kea_att_float;
155 2 : break;
156 3 : case GFT_String:
157 3 : field->dataType = kealib::kea_att_string;
158 3 : break;
159 1 : case GFT_Boolean:
160 1 : field->dataType = kealib::kea_att_bool;
161 1 : break;
162 0 : case GFT_DateTime:
163 : case GFT_WKBGeometry:
164 : // leave as "kea_att_string"
165 0 : break;
166 : }
167 :
168 18 : if (bInputHFA && (field->name == "Histogram"))
169 : {
170 0 : field->usage = "PixelCount";
171 0 : field->dataType = kealib::kea_att_int;
172 : }
173 18 : else if (bInputHFA && (field->name == "Opacity"))
174 : {
175 0 : field->name = "Alpha";
176 0 : field->usage = "Alpha";
177 0 : field->dataType = kealib::kea_att_int;
178 : /*alphaDef = true;
179 : alphaIdx = ni;*/
180 : }
181 : else
182 : {
183 18 : field->usage = "Generic";
184 18 : switch (gdalAtt->GetUsageOfCol(ni))
185 : {
186 1 : case GFU_PixelCount:
187 1 : field->usage = "PixelCount";
188 1 : break;
189 1 : case GFU_Name:
190 1 : field->usage = "Name";
191 1 : break;
192 3 : case GFU_Red:
193 3 : field->usage = "Red";
194 3 : if (bInputHFA)
195 : {
196 0 : field->dataType = kealib::kea_att_int;
197 : /*redDef = true;
198 : redIdx = ni;*/
199 : }
200 3 : break;
201 3 : case GFU_Green:
202 3 : field->usage = "Green";
203 3 : if (bInputHFA)
204 : {
205 0 : field->dataType = kealib::kea_att_int;
206 : /*greenDef = true;
207 : greenIdx = ni;*/
208 : }
209 3 : break;
210 3 : case GFU_Blue:
211 3 : field->usage = "Blue";
212 3 : if (bInputHFA)
213 : {
214 0 : field->dataType = kealib::kea_att_int;
215 : /*blueDef = true;
216 : blueIdx = ni;*/
217 : }
218 3 : break;
219 3 : case GFU_Alpha:
220 3 : field->usage = "Alpha";
221 3 : break;
222 4 : default:
223 : // leave as "Generic"
224 4 : break;
225 : }
226 : }
227 :
228 18 : fields->push_back(field);
229 : }
230 :
231 : // This function will populate the field indexes used within
232 : // the KEA RAT.
233 3 : keaAtt->addFields(fields);
234 :
235 3 : int numRows = gdalAtt->GetRowCount();
236 3 : keaAtt->addRows(numRows);
237 :
238 3 : bool *pbBuffer = nullptr;
239 3 : int *pnIntBuffer = nullptr;
240 3 : int64_t *pnInt64Buffer = nullptr;
241 3 : double *pfDoubleBuffer = nullptr;
242 6 : for (int ni = 0; ni < numRows; ni += kealib::KEA_ATT_CHUNK_SIZE)
243 : {
244 3 : int nLength = kealib::KEA_ATT_CHUNK_SIZE;
245 3 : if ((ni + nLength) > numRows)
246 : {
247 3 : nLength = numRows - ni;
248 : }
249 21 : for (int nj = 0; nj < numCols; ++nj)
250 : {
251 18 : field = fields->at(nj);
252 :
253 18 : switch (field->dataType)
254 : {
255 1 : case kealib::kea_att_bool:
256 1 : if (!pbBuffer)
257 1 : pbBuffer = new bool[kealib::KEA_ATT_CHUNK_SIZE];
258 : ((GDALRasterAttributeTable *)gdalAtt)
259 1 : ->ValuesIO(GF_Read, nj, ni, nLength, pbBuffer);
260 1 : keaAtt->setBoolFields(ni, nLength, field->idx,
261 1 : pbBuffer);
262 1 : break;
263 12 : case kealib::kea_att_int:
264 12 : if (!pnIntBuffer)
265 3 : pnIntBuffer = new int[kealib::KEA_ATT_CHUNK_SIZE];
266 12 : if (!pnInt64Buffer)
267 : pnInt64Buffer =
268 3 : new int64_t[kealib::KEA_ATT_CHUNK_SIZE];
269 : ((GDALRasterAttributeTable *)gdalAtt)
270 12 : ->ValuesIO(GF_Read, nj, ni, nLength, pnIntBuffer);
271 40 : for (int i = 0; i < nLength; i++)
272 : {
273 28 : pnInt64Buffer[i] = pnIntBuffer[i];
274 : }
275 12 : keaAtt->setIntFields(ni, nLength, field->idx,
276 12 : pnInt64Buffer);
277 12 : break;
278 2 : case kealib::kea_att_float:
279 2 : if (!pfDoubleBuffer)
280 : pfDoubleBuffer =
281 1 : new double[kealib::KEA_ATT_CHUNK_SIZE];
282 : ((GDALRasterAttributeTable *)gdalAtt)
283 2 : ->ValuesIO(GF_Read, nj, ni, nLength,
284 2 : pfDoubleBuffer);
285 2 : keaAtt->setFloatFields(ni, nLength, field->idx,
286 2 : pfDoubleBuffer);
287 2 : break;
288 3 : case kealib::kea_att_string:
289 : {
290 : char **papszColData =
291 3 : (char **)VSIMalloc2(nLength, sizeof(char *));
292 : ((GDALRasterAttributeTable *)gdalAtt)
293 3 : ->ValuesIO(GF_Read, nj, ni, nLength, papszColData);
294 :
295 6 : std::vector<std::string> aStringBuffer;
296 6 : for (int i = 0; i < nLength; i++)
297 : {
298 3 : aStringBuffer.push_back(papszColData[i]);
299 : }
300 :
301 6 : for (int i = 0; i < nLength; i++)
302 3 : CPLFree(papszColData[i]);
303 3 : CPLFree(papszColData);
304 :
305 3 : keaAtt->setStringFields(ni, nLength, field->idx,
306 3 : &aStringBuffer);
307 : }
308 3 : break;
309 0 : default:
310 : // Ignore as data type is not known or available from a
311 : // HFA/GDAL RAT."
312 0 : break;
313 : }
314 : }
315 : }
316 :
317 3 : delete[] pbBuffer;
318 3 : delete[] pnIntBuffer;
319 3 : delete[] pnInt64Buffer;
320 3 : delete[] pfDoubleBuffer;
321 :
322 3 : delete keaAtt;
323 18 : for (std::vector<kealib::KEAATTField *>::iterator iterField =
324 3 : fields->begin();
325 39 : iterField != fields->end(); ++iterField)
326 : {
327 18 : delete *iterField;
328 : }
329 3 : delete fields;
330 : }
331 89 : }
332 :
333 : // copies the metadata
334 : // pass nBand == -1 to copy a dataset's metadata
335 : // or band index to copy a band's metadata
336 151 : static void KEACopyMetadata(GDALMajorObject *pObject,
337 : kealib::KEAImageIO *pImageIO, int nBand)
338 : {
339 151 : char **ppszMetadata = pObject->GetMetadata();
340 151 : if (ppszMetadata != nullptr)
341 : {
342 86 : int nCount = 0;
343 252 : while (ppszMetadata[nCount] != nullptr)
344 : {
345 166 : char *pszName = nullptr;
346 : const char *pszValue =
347 166 : CPLParseNameValue(ppszMetadata[nCount], &pszName);
348 166 : if (pszValue == nullptr)
349 12 : pszValue = "";
350 166 : if (pszName != nullptr)
351 : {
352 : // it is LAYER_TYPE and a Band? if so handle separately
353 154 : if ((nBand != -1) && EQUAL(pszName, "LAYER_TYPE"))
354 : {
355 55 : if (EQUAL(pszValue, "athematic"))
356 : {
357 53 : pImageIO->setImageBandLayerType(nBand,
358 : kealib::kea_continuous);
359 : }
360 : else
361 : {
362 2 : pImageIO->setImageBandLayerType(nBand,
363 : kealib::kea_thematic);
364 : }
365 : }
366 99 : else if ((nBand != -1) &&
367 84 : EQUAL(pszName, "STATISTICS_HISTOBINVALUES"))
368 : {
369 : // This gets copied across as part of the attributes
370 : // so ignore for now.
371 : }
372 : else
373 : {
374 : // write it into the image
375 99 : if (nBand != -1)
376 84 : pImageIO->setImageBandMetaData(nBand, pszName,
377 : pszValue);
378 : else
379 15 : pImageIO->setImageMetaData(pszName, pszValue);
380 : }
381 154 : CPLFree(pszName);
382 : }
383 166 : nCount++;
384 : }
385 : }
386 151 : }
387 :
388 : // copies the description over
389 89 : static void KEACopyDescription(GDALRasterBand *pBand,
390 : kealib::KEAImageIO *pImageIO, int nBand)
391 : {
392 89 : const char *pszDesc = pBand->GetDescription();
393 89 : pImageIO->setImageBandDescription(nBand, pszDesc);
394 89 : }
395 :
396 : // copies the no data value across
397 89 : static void KEACopyNoData(GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO,
398 : int nBand)
399 : {
400 89 : int bSuccess = 0;
401 89 : double dNoData = pBand->GetNoDataValue(&bSuccess);
402 89 : if (bSuccess)
403 : {
404 17 : pImageIO->setNoDataValue(nBand, &dNoData, kealib::kea_64float);
405 : }
406 89 : }
407 :
408 89 : static bool KEACopyBand(GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO,
409 : int nBand, int nTotalbands,
410 : GDALProgressFunc pfnProgress, void *pProgressData)
411 : {
412 : // first copy the raster data over
413 89 : if (!KEACopyRasterData(pBand, pImageIO, nBand, -1, nTotalbands, pfnProgress,
414 : pProgressData))
415 0 : return false;
416 :
417 : // are there any overviews?
418 89 : int nOverviews = pBand->GetOverviewCount();
419 90 : for (int nOverviewCount = 0; nOverviewCount < nOverviews; nOverviewCount++)
420 : {
421 1 : GDALRasterBand *pOverview = pBand->GetOverview(nOverviewCount);
422 1 : int nOverviewXSize = pOverview->GetXSize();
423 1 : int nOverviewYSize = pOverview->GetYSize();
424 1 : pImageIO->createOverview(nBand, nOverviewCount + 1, nOverviewXSize,
425 : nOverviewYSize);
426 1 : if (!KEACopyRasterData(pOverview, pImageIO, nBand, nOverviewCount + 1,
427 : nTotalbands, pfnProgress, pProgressData))
428 0 : return false;
429 : }
430 :
431 : // now metadata
432 89 : KEACopyMetadata(pBand, pImageIO, nBand);
433 :
434 : // and attributes
435 89 : KEACopyRAT(pBand, pImageIO, nBand);
436 :
437 : // and description
438 89 : KEACopyDescription(pBand, pImageIO, nBand);
439 :
440 : // and no data
441 89 : KEACopyNoData(pBand, pImageIO, nBand);
442 :
443 89 : return true;
444 : }
445 :
446 62 : static void KEACopySpatialInfo(GDALDataset *pDataset,
447 : kealib::KEAImageIO *pImageIO)
448 : {
449 62 : kealib::KEAImageSpatialInfo *pSpatialInfo = pImageIO->getSpatialInfo();
450 :
451 62 : GDALGeoTransform gt;
452 62 : if (pDataset->GetGeoTransform(gt) == CE_None)
453 : {
454 : // convert back from GDAL's array format
455 62 : pSpatialInfo->tlX = gt[0];
456 62 : pSpatialInfo->xRes = gt[1];
457 62 : pSpatialInfo->xRot = gt[2];
458 62 : pSpatialInfo->tlY = gt[3];
459 62 : pSpatialInfo->yRot = gt[4];
460 62 : pSpatialInfo->yRes = gt[5];
461 : }
462 :
463 62 : const char *pszProjection = pDataset->GetProjectionRef();
464 62 : pSpatialInfo->wktString = pszProjection;
465 :
466 62 : pImageIO->setSpatialInfo(pSpatialInfo);
467 62 : }
468 :
469 : // copies the GCP's across
470 62 : static void KEACopyGCPs(GDALDataset *pDataset, kealib::KEAImageIO *pImageIO)
471 : {
472 62 : int nGCPs = pDataset->GetGCPCount();
473 :
474 62 : if (nGCPs > 0)
475 : {
476 2 : std::vector<kealib::KEAImageGCP *> KEAGCPs;
477 1 : const GDAL_GCP *pGDALGCPs = pDataset->GetGCPs();
478 :
479 3 : for (int n = 0; n < nGCPs; n++)
480 : {
481 2 : kealib::KEAImageGCP *pGCP = new kealib::KEAImageGCP;
482 2 : pGCP->pszId = pGDALGCPs[n].pszId;
483 2 : pGCP->pszInfo = pGDALGCPs[n].pszInfo;
484 2 : pGCP->dfGCPPixel = pGDALGCPs[n].dfGCPPixel;
485 2 : pGCP->dfGCPLine = pGDALGCPs[n].dfGCPLine;
486 2 : pGCP->dfGCPX = pGDALGCPs[n].dfGCPX;
487 2 : pGCP->dfGCPY = pGDALGCPs[n].dfGCPY;
488 2 : pGCP->dfGCPZ = pGDALGCPs[n].dfGCPZ;
489 2 : KEAGCPs.push_back(pGCP);
490 : }
491 :
492 1 : const char *pszGCPProj = pDataset->GetGCPProjection();
493 : try
494 : {
495 1 : pImageIO->setGCPs(&KEAGCPs, pszGCPProj);
496 : }
497 0 : catch (const kealib::KEAException &)
498 : {
499 : }
500 :
501 3 : for (std::vector<kealib::KEAImageGCP *>::iterator itr = KEAGCPs.begin();
502 5 : itr != KEAGCPs.end(); ++itr)
503 : {
504 2 : delete (*itr);
505 : }
506 : }
507 62 : }
508 :
509 62 : bool KEACopyFile(GDALDataset *pDataset, kealib::KEAImageIO *pImageIO,
510 : GDALProgressFunc pfnProgress, void *pProgressData)
511 : {
512 : // Main function - copies pDataset to pImageIO
513 :
514 : // Copy across the spatial info.
515 62 : KEACopySpatialInfo(pDataset, pImageIO);
516 :
517 : // dataset metadata
518 62 : KEACopyMetadata(pDataset, pImageIO, -1);
519 :
520 : // GCPs
521 62 : KEACopyGCPs(pDataset, pImageIO);
522 :
523 : // now copy all the bands over
524 62 : int nBands = pDataset->GetRasterCount();
525 151 : for (int nBand = 0; nBand < nBands; nBand++)
526 : {
527 89 : GDALRasterBand *pBand = pDataset->GetRasterBand(nBand + 1);
528 89 : if (!KEACopyBand(pBand, pImageIO, nBand + 1, nBands, pfnProgress,
529 : pProgressData))
530 0 : return false;
531 : }
532 :
533 62 : pfnProgress(1.0, nullptr, pProgressData);
534 62 : return true;
535 : }
|