LCOV - code coverage report
Current view: top level - frmts/kea - keacopy.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 230 252 91.3 %
Date: 2024-11-21 22:18:42 Functions: 9 9 100.0 %

          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             : }

Generated by: LCOV version 1.14