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