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