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

Generated by: LCOV version 1.14