LCOV - code coverage report
Current view: top level - frmts/kea - keaband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 517 716 72.2 %
Date: 2024-04-27 17:22:41 Functions: 33 38 86.8 %

          Line data    Source code
       1             : /*
       2             :  *  keaband.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 "keaband.h"
      31             : #include "keaoverview.h"
      32             : #include "keamaskband.h"
      33             : #include "kearat.h"
      34             : 
      35             : #include "gdal_rat.h"
      36             : 
      37             : #include <map>
      38             : #include <vector>
      39             : #include <limits>
      40             : 
      41             : // constructor
      42         352 : KEARasterBand::KEARasterBand(KEADataset *pDataset, int nSrcBand,
      43             :                              GDALAccess eAccessIn, kealib::KEAImageIO *pImageIO,
      44         352 :                              LockedRefCount *pRefCount)
      45         704 :     : m_eKEADataType(pImageIO->getImageBandDataType(
      46         352 :           nSrcBand))  // get the data type as KEA enum
      47             : {
      48         352 :     this->m_hMutex = CPLCreateMutex();
      49         352 :     CPLReleaseMutex(this->m_hMutex);
      50             : 
      51         352 :     this->poDS = pDataset;   // our pointer onto the dataset
      52         352 :     this->nBand = nSrcBand;  // this is the band we are
      53         352 :     this->eDataType = KEA_to_GDAL_Type(m_eKEADataType);  // convert to GDAL enum
      54         352 :     this->nBlockXSize =
      55         352 :         pImageIO->getImageBlockSize(nSrcBand);  // get the native blocksize
      56         352 :     this->nBlockYSize = pImageIO->getImageBlockSize(nSrcBand);
      57         352 :     this->nRasterXSize =
      58         352 :         this->poDS
      59         352 :             ->GetRasterXSize();  // ask the dataset for the total image size
      60         352 :     this->nRasterYSize = this->poDS->GetRasterYSize();
      61         352 :     this->eAccess = eAccessIn;
      62             : 
      63         352 :     if (pImageIO->attributeTablePresent(nSrcBand))
      64             :     {
      65          10 :         this->m_nAttributeChunkSize =
      66          10 :             pImageIO->getAttributeTableChunkSize(nSrcBand);
      67             :     }
      68             :     else
      69             :     {
      70         342 :         this->m_nAttributeChunkSize = -1;  // don't report
      71             :     }
      72             : 
      73             :     // grab the imageio class and its refcount
      74         352 :     this->m_pImageIO = pImageIO;
      75         352 :     this->m_pRefCount = pRefCount;
      76             :     // increment the refcount as we now have a reference to imageio
      77         352 :     this->m_pRefCount->IncRef();
      78             : 
      79             :     // Initialize overview variables
      80         352 :     m_nOverviews = 0;
      81         352 :     m_panOverviewBands = nullptr;
      82             : 
      83             :     // mask band
      84         352 :     m_pMaskBand = nullptr;
      85         352 :     m_bMaskBandOwned = false;
      86             : 
      87             :     // grab the description here
      88         352 :     this->sDescription = pImageIO->getImageBandDescription(nSrcBand);
      89             : 
      90         352 :     this->m_pAttributeTable = nullptr;  // no RAT yet
      91         352 :     this->m_pColorTable = nullptr;      // no color table yet
      92             : 
      93             :     // Initialize the metadata as a CPLStringList.
      94         352 :     m_papszMetadataList = nullptr;
      95         352 :     this->UpdateMetadataList();
      96         352 :     m_pszHistoBinValues = nullptr;
      97         352 : }
      98             : 
      99             : // destructor
     100         701 : KEARasterBand::~KEARasterBand()
     101             : {
     102             :     {
     103         704 :         CPLMutexHolderD(&m_hMutex);
     104             :         // destroy RAT if any
     105         352 :         delete this->m_pAttributeTable;
     106             :         // destroy color table if any
     107         352 :         delete this->m_pColorTable;
     108             :         // destroy the metadata
     109         352 :         CSLDestroy(this->m_papszMetadataList);
     110         352 :         if (this->m_pszHistoBinValues != nullptr)
     111             :         {
     112             :             // histogram bin values as a string
     113           0 :             CPLFree(this->m_pszHistoBinValues);
     114             :         }
     115             :         // delete any overview bands
     116         352 :         this->deleteOverviewObjects();
     117             : 
     118             :         // if GDAL created the mask it will delete it
     119         352 :         if (m_bMaskBandOwned)
     120             :         {
     121           3 :             delete m_pMaskBand;
     122             :         }
     123             :     }
     124             : 
     125             :     // according to the docs, this is required
     126         352 :     this->FlushCache(true);
     127             : 
     128             :     // decrement the recount and delete if needed
     129         352 :     if (m_pRefCount->DecRef())
     130             :     {
     131             :         try
     132             :         {
     133         246 :             m_pImageIO->close();
     134             :         }
     135           0 :         catch (const kealib::KEAIOException &)
     136             :         {
     137             :         }
     138         246 :         delete m_pImageIO;
     139         246 :         delete m_pRefCount;
     140             :     }
     141         701 : }
     142             : 
     143             : // internal method that updates the metadata into m_papszMetadataList
     144         352 : void KEARasterBand::UpdateMetadataList()
     145             : {
     146         704 :     CPLMutexHolderD(&m_hMutex);
     147         704 :     std::vector<std::pair<std::string, std::string>> data;
     148             : 
     149             :     // get all the metadata and iterate through
     150         352 :     data = this->m_pImageIO->getImageBandMetaData(this->nBand);
     151         127 :     for (std::vector<std::pair<std::string, std::string>>::iterator
     152         352 :              iterMetaData = data.begin();
     153         479 :          iterMetaData != data.end(); ++iterMetaData)
     154             :     {
     155             :         // add to our list
     156         127 :         m_papszMetadataList =
     157         127 :             CSLSetNameValue(m_papszMetadataList, iterMetaData->first.c_str(),
     158         127 :                             iterMetaData->second.c_str());
     159             :     }
     160             :     // we have a pseudo metadata item that tells if we are thematic
     161             :     // or continuous like the HFA driver
     162         352 :     if (this->m_pImageIO->getImageBandLayerType(this->nBand) ==
     163             :         kealib::kea_continuous)
     164             :     {
     165         343 :         m_papszMetadataList =
     166         343 :             CSLSetNameValue(m_papszMetadataList, "LAYER_TYPE", "athematic");
     167             :     }
     168             :     else
     169             :     {
     170           9 :         m_papszMetadataList =
     171           9 :             CSLSetNameValue(m_papszMetadataList, "LAYER_TYPE", "thematic");
     172             :     }
     173             : 
     174             :     // STATISTICS_HISTONUMBINS
     175         352 :     const GDALRasterAttributeTable *pTable = KEARasterBand::GetDefaultRAT();
     176         352 :     if (pTable != nullptr)
     177             :     {
     178         704 :         CPLString osWorkingResult;
     179         352 :         osWorkingResult.Printf("%lu", (unsigned long)pTable->GetRowCount());
     180         352 :         m_papszMetadataList = CSLSetNameValue(
     181             :             m_papszMetadataList, "STATISTICS_HISTONUMBINS", osWorkingResult);
     182             : 
     183             :         // attribute table chunksize
     184         352 :         if (this->m_nAttributeChunkSize != -1)
     185             :         {
     186          10 :             osWorkingResult.Printf("%d", this->m_nAttributeChunkSize);
     187          10 :             m_papszMetadataList =
     188          10 :                 CSLSetNameValue(m_papszMetadataList, "ATTRIBUTETABLE_CHUNKSIZE",
     189             :                                 osWorkingResult);
     190             :         }
     191             :     }
     192         352 : }
     193             : 
     194             : // internal method to set the histogram column from a string (for metadata)
     195             : 
     196           0 : CPLErr KEARasterBand::SetHistogramFromString(const char *pszString)
     197             : {
     198             :     // copy it so we can change it (put nulls in etc)
     199           0 :     char *pszBinValues = CPLStrdup(pszString);
     200           0 :     if (pszBinValues == nullptr)
     201           0 :         return CE_Failure;
     202             : 
     203             :     // find the number of | chars
     204           0 :     int nRows = 0, i = 0;
     205           0 :     while (pszBinValues[i] != '\0')
     206             :     {
     207           0 :         if (pszBinValues[i] == '|')
     208           0 :             nRows++;
     209           0 :         i++;
     210             :     }
     211             : 
     212           0 :     GDALRasterAttributeTable *pTable = this->GetDefaultRAT();
     213           0 :     if (pTable == nullptr)
     214             :     {
     215           0 :         CPLFree(pszBinValues);
     216           0 :         return CE_Failure;
     217             :     }
     218             : 
     219             :     // find histogram column if it exists
     220           0 :     int nCol = pTable->GetColOfUsage(GFU_PixelCount);
     221           0 :     if (nCol == -1)
     222             :     {
     223           0 :         if (pTable->CreateColumn("Histogram", GFT_Real, GFU_PixelCount) !=
     224             :             CE_None)
     225             :         {
     226           0 :             CPLFree(pszBinValues);
     227           0 :             return CE_Failure;
     228             :         }
     229             : 
     230           0 :         nCol = pTable->GetColumnCount() - 1;
     231             :     }
     232             : 
     233           0 :     if (nRows > pTable->GetRowCount())
     234           0 :         pTable->SetRowCount(nRows);
     235             : 
     236           0 :     char *pszWork = pszBinValues;
     237           0 :     for (int nBin = 0; nBin < nRows; ++nBin)
     238             :     {
     239           0 :         char *pszEnd = strchr(pszWork, '|');
     240           0 :         if (pszEnd != nullptr)
     241             :         {
     242           0 :             *pszEnd = 0;
     243           0 :             double dValue = CPLAtof(pszWork);
     244           0 :             pTable->SetValue(nBin, nCol, dValue);
     245           0 :             pszWork = pszEnd + 1;
     246             :         }
     247             :     }
     248             : 
     249           0 :     CPLFree(pszBinValues);
     250             : 
     251           0 :     return CE_None;
     252             : }
     253             : 
     254             : // get histogram as string with values separated by '|'
     255           0 : char *KEARasterBand::GetHistogramAsString()
     256             : {
     257           0 :     const GDALRasterAttributeTable *pTable = this->GetDefaultRAT();
     258           0 :     if (pTable == nullptr)
     259           0 :         return nullptr;
     260           0 :     int nRows = pTable->GetRowCount();
     261             :     // find histogram column if it exists
     262           0 :     int nCol = pTable->GetColOfUsage(GFU_PixelCount);
     263           0 :     if (nCol == -1)
     264           0 :         return nullptr;
     265             : 
     266           0 :     unsigned int nBufSize = 1024;
     267           0 :     char *pszBinValues = (char *)CPLMalloc(nBufSize);
     268           0 :     int nBinValuesLen = 0;
     269           0 :     pszBinValues[0] = 0;
     270             : 
     271           0 :     for (int nBin = 0; nBin < nRows; ++nBin)
     272             :     {
     273             :         char szBuf[32];
     274             :         // RAT's don't handle GUIntBig - use double instead. Cast back
     275           0 :         snprintf(szBuf, 31, CPL_FRMT_GUIB,
     276           0 :                  (GUIntBig)pTable->GetValueAsDouble(nBin, nCol));
     277           0 :         if ((nBinValuesLen + strlen(szBuf) + 2) > nBufSize)
     278             :         {
     279           0 :             nBufSize *= 2;
     280           0 :             char *pszNewBinValues = (char *)VSIRealloc(pszBinValues, nBufSize);
     281           0 :             if (pszNewBinValues == nullptr)
     282             :             {
     283           0 :                 break;
     284             :             }
     285             : 
     286           0 :             pszBinValues = pszNewBinValues;
     287             :         }
     288             : 
     289           0 :         strcat(pszBinValues + nBinValuesLen, szBuf);
     290           0 :         strcat(pszBinValues + nBinValuesLen, "|");
     291           0 :         nBinValuesLen += static_cast<int>(strlen(pszBinValues + nBinValuesLen));
     292             :     }
     293             : 
     294           0 :     return pszBinValues;
     295             : }
     296             : 
     297             : // internal method to create the overviews
     298           1 : void KEARasterBand::CreateOverviews(int nOverviews, const int *panOverviewList)
     299             : {
     300           2 :     CPLMutexHolderD(&m_hMutex);
     301             :     // delete any existing overview bands
     302           1 :     this->deleteOverviewObjects();
     303             : 
     304             :     // allocate space
     305           1 :     m_panOverviewBands =
     306           1 :         (KEAOverview **)CPLMalloc(sizeof(KEAOverview *) * nOverviews);
     307           1 :     m_nOverviews = nOverviews;
     308             : 
     309             :     // loop through and create the overviews
     310             :     int nFactor, nXSize, nYSize;
     311           2 :     for (int nCount = 0; nCount < m_nOverviews; nCount++)
     312             :     {
     313           1 :         nFactor = panOverviewList[nCount];
     314             :         // divide by the factor to get the new size
     315           1 :         nXSize = this->nRasterXSize / nFactor;
     316           1 :         nYSize = this->nRasterYSize / nFactor;
     317             : 
     318             :         // tell image io to create a new overview
     319           1 :         this->m_pImageIO->createOverview(this->nBand, nCount + 1, nXSize,
     320             :                                          nYSize);
     321             : 
     322             :         // create one of our objects to represent it
     323           1 :         m_panOverviewBands[nCount] = new KEAOverview(
     324           1 :             (KEADataset *)this->poDS, this->nBand, GA_Update, this->m_pImageIO,
     325           1 :             this->m_pRefCount, nCount + 1, nXSize, nYSize);
     326             :     }
     327           1 : }
     328             : 
     329             : // virtual method to read a block
     330         144 : CPLErr KEARasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     331             : {
     332             :     try
     333             :     {
     334             :         // GDAL deals in blocks - if we are at the end of a row
     335             :         // we need to adjust the amount read so we don't go over the edge
     336         144 :         int nxsize = this->nBlockXSize;
     337         144 :         int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
     338         144 :         if (nxtotalsize > this->nRasterXSize)
     339             :         {
     340          11 :             nxsize -= (nxtotalsize - this->nRasterXSize);
     341             :         }
     342         144 :         int nysize = this->nBlockYSize;
     343         144 :         int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
     344         144 :         if (nytotalsize > this->nRasterYSize)
     345             :         {
     346          11 :             nysize -= (nytotalsize - this->nRasterYSize);
     347             :         }
     348         144 :         this->m_pImageIO->readImageBlock2Band(
     349         144 :             this->nBand, pImage, this->nBlockXSize * nBlockXOff,
     350         144 :             this->nBlockYSize * nBlockYOff, nxsize, nysize, this->nBlockXSize,
     351         144 :             this->nBlockYSize, this->m_eKEADataType);
     352         144 :         return CE_None;
     353             :     }
     354           0 :     catch (const kealib::KEAIOException &e)
     355             :     {
     356           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to read file: %s",
     357           0 :                  e.what());
     358           0 :         return CE_Failure;
     359             :     }
     360             : }
     361             : 
     362             : // virtual method to write a block
     363          12 : CPLErr KEARasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void *pImage)
     364             : {
     365             :     try
     366             :     {
     367             :         // GDAL deals in blocks - if we are at the end of a row
     368             :         // we need to adjust the amount written so we don't go over the edge
     369          12 :         int nxsize = this->nBlockXSize;
     370          12 :         int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
     371          12 :         if (nxtotalsize > this->nRasterXSize)
     372             :         {
     373           0 :             nxsize -= (nxtotalsize - this->nRasterXSize);
     374             :         }
     375          12 :         int nysize = this->nBlockYSize;
     376          12 :         int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
     377          12 :         if (nytotalsize > this->nRasterYSize)
     378             :         {
     379           0 :             nysize -= (nytotalsize - this->nRasterYSize);
     380             :         }
     381             : 
     382          12 :         this->m_pImageIO->writeImageBlock2Band(
     383          12 :             this->nBand, pImage, this->nBlockXSize * nBlockXOff,
     384          12 :             this->nBlockYSize * nBlockYOff, nxsize, nysize, this->nBlockXSize,
     385          12 :             this->nBlockYSize, this->m_eKEADataType);
     386          12 :         return CE_None;
     387             :     }
     388           0 :     catch (const kealib::KEAIOException &e)
     389             :     {
     390           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to write file: %s",
     391           0 :                  e.what());
     392           0 :         return CE_Failure;
     393             :     }
     394             : }
     395             : 
     396           1 : void KEARasterBand::SetDescription(const char *pszDescription)
     397             : {
     398           2 :     CPLMutexHolderD(&m_hMutex);
     399             :     try
     400             :     {
     401           1 :         this->m_pImageIO->setImageBandDescription(this->nBand, pszDescription);
     402           1 :         GDALPamRasterBand::SetDescription(pszDescription);
     403             :     }
     404           0 :     catch (const kealib::KEAIOException &)
     405             :     {
     406             :         // ignore?
     407             :     }
     408           1 : }
     409             : 
     410             : // set a metadata item
     411           7 : CPLErr KEARasterBand::SetMetadataItem(const char *pszName, const char *pszValue,
     412             :                                       const char *pszDomain)
     413             : {
     414          14 :     CPLMutexHolderD(&m_hMutex);
     415             :     // only deal with 'default' domain - no geolocation etc
     416           7 :     if ((pszDomain != nullptr) && (*pszDomain != '\0'))
     417           1 :         return CE_Failure;
     418             : 
     419             :     // kealib doesn't currently support removing values
     420           6 :     if (pszValue == nullptr)
     421           0 :         return CE_Failure;
     422             : 
     423             :     try
     424             :     {
     425             :         // if it is LAYER_TYPE handle it separately
     426           6 :         if (EQUAL(pszName, "LAYER_TYPE"))
     427             :         {
     428           6 :             if (EQUAL(pszValue, "athematic"))
     429             :             {
     430           1 :                 this->m_pImageIO->setImageBandLayerType(this->nBand,
     431             :                                                         kealib::kea_continuous);
     432             :             }
     433             :             else
     434             :             {
     435           5 :                 this->m_pImageIO->setImageBandLayerType(this->nBand,
     436             :                                                         kealib::kea_thematic);
     437             :             }
     438             :         }
     439           0 :         else if (EQUAL(pszName, "STATISTICS_HISTOBINVALUES"))
     440             :         {
     441           0 :             if (this->SetHistogramFromString(pszValue) != CE_None)
     442           0 :                 return CE_Failure;
     443             :             else
     444           0 :                 return CE_None;
     445             :         }
     446           0 :         else if (EQUAL(pszName, "STATISTICS_HISTONUMBINS"))
     447             :         {
     448           0 :             GDALRasterAttributeTable *pTable = this->GetDefaultRAT();
     449           0 :             if (pTable != nullptr)
     450           0 :                 pTable->SetRowCount(atoi(pszValue));
     451             :             // leave to update m_papszMetadataList below
     452             :         }
     453             :         else
     454             :         {
     455             :             // otherwise set it as normal
     456           0 :             this->m_pImageIO->setImageBandMetaData(this->nBand, pszName,
     457             :                                                    pszValue);
     458             :         }
     459             :         // CSLSetNameValue will update if already there
     460           6 :         m_papszMetadataList =
     461           6 :             CSLSetNameValue(m_papszMetadataList, pszName, pszValue);
     462           6 :         return CE_None;
     463             :     }
     464           0 :     catch (const kealib::KEAIOException &)
     465             :     {
     466           0 :         return CE_Failure;
     467             :     }
     468             : }
     469             : 
     470             : // get a single metadata item
     471          14 : const char *KEARasterBand::GetMetadataItem(const char *pszName,
     472             :                                            const char *pszDomain)
     473             : {
     474          28 :     CPLMutexHolderD(&m_hMutex);
     475             :     // only deal with 'default' domain - no geolocation etc
     476          14 :     if ((pszDomain != nullptr) && (*pszDomain != '\0'))
     477           7 :         return nullptr;
     478             : 
     479           7 :     if (EQUAL(pszName, "STATISTICS_HISTOBINVALUES"))
     480             :     {
     481           0 :         if (m_pszHistoBinValues != nullptr)
     482           0 :             CPLFree(m_pszHistoBinValues);  // could have changed
     483           0 :         m_pszHistoBinValues = this->GetHistogramAsString();
     484           0 :         return m_pszHistoBinValues;
     485             :     }
     486             : 
     487             :     // get it out of the CSLStringList so we can be sure it is persistent
     488           7 :     return CSLFetchNameValue(m_papszMetadataList, pszName);
     489             : }
     490             : 
     491             : // get all the metadata as a CSLStringList
     492          57 : char **KEARasterBand::GetMetadata(const char *pszDomain)
     493             : {
     494             :     // only deal with 'default' domain - no geolocation etc
     495          57 :     if ((pszDomain != nullptr) && (*pszDomain != '\0'))
     496           1 :         return nullptr;
     497             :     // Note: ignoring STATISTICS_HISTOBINVALUES as these are likely to be very
     498             :     // long not sure user should get those unless they really ask...
     499             : 
     500             :     // conveniently we already have it in this format
     501          56 :     return m_papszMetadataList;
     502             : }
     503             : 
     504             : // set the metadata as a CSLStringList
     505           4 : CPLErr KEARasterBand::SetMetadata(char **papszMetadata, const char *pszDomain)
     506             : {
     507           8 :     CPLMutexHolderD(&m_hMutex);
     508             :     // only deal with 'default' domain - no geolocation etc
     509           4 :     if ((pszDomain != nullptr) && (*pszDomain != '\0'))
     510           1 :         return CE_Failure;
     511           3 :     int nIndex = 0;
     512             :     try
     513             :     {
     514             :         // iterate through each one
     515           6 :         while (papszMetadata[nIndex] != nullptr)
     516             :         {
     517           3 :             char *pszName = nullptr;
     518             :             const char *pszValue =
     519           3 :                 CPLParseNameValue(papszMetadata[nIndex], &pszName);
     520           3 :             if (pszValue == nullptr)
     521           0 :                 pszValue = "";
     522           3 :             if (pszName != nullptr)
     523             :             {
     524             :                 // it is LAYER_TYPE? if so handle separately
     525           3 :                 if (EQUAL(pszName, "LAYER_TYPE"))
     526             :                 {
     527           2 :                     if (EQUAL(pszValue, "athematic"))
     528             :                     {
     529           1 :                         this->m_pImageIO->setImageBandLayerType(
     530           1 :                             this->nBand, kealib::kea_continuous);
     531             :                     }
     532             :                     else
     533             :                     {
     534           1 :                         this->m_pImageIO->setImageBandLayerType(
     535           1 :                             this->nBand, kealib::kea_thematic);
     536             :                     }
     537             :                 }
     538           1 :                 else if (EQUAL(pszName, "STATISTICS_HISTOBINVALUES"))
     539             :                 {
     540           0 :                     if (this->SetHistogramFromString(pszValue) != CE_None)
     541             :                     {
     542           0 :                         CPLFree(pszName);
     543           0 :                         return CE_Failure;
     544             :                     }
     545             :                 }
     546             :                 else
     547             :                 {
     548             :                     // write it into the image
     549           1 :                     this->m_pImageIO->setImageBandMetaData(this->nBand, pszName,
     550             :                                                            pszValue);
     551             :                 }
     552           3 :                 CPLFree(pszName);
     553             :             }
     554           3 :             nIndex++;
     555             :         }
     556             :     }
     557           0 :     catch (const kealib::KEAIOException &)
     558             :     {
     559           0 :         return CE_Failure;
     560             :     }
     561             :     // destroy our list and duplicate the one passed in
     562             :     // and use that as our list from now on
     563           3 :     CSLDestroy(m_papszMetadataList);
     564           3 :     m_papszMetadataList = CSLDuplicate(papszMetadata);
     565           3 :     return CE_None;
     566             : }
     567             : 
     568             : // get the no data value
     569         282 : double KEARasterBand::GetNoDataValue(int *pbSuccess)
     570             : {
     571             :     try
     572             :     {
     573             :         double dVal;
     574         282 :         this->m_pImageIO->getNoDataValue(this->nBand, &dVal,
     575             :                                          kealib::kea_64float);
     576          65 :         if (pbSuccess != nullptr)
     577          53 :             *pbSuccess = 1;
     578             : 
     579          65 :         return dVal;
     580             :     }
     581         217 :     catch (const kealib::KEAIOException &)
     582             :     {
     583         217 :         if (pbSuccess != nullptr)
     584         217 :             *pbSuccess = 0;
     585         217 :         return -1;
     586             :     }
     587             : }
     588             : 
     589          22 : int64_t KEARasterBand::GetNoDataValueAsInt64(int *pbSuccess)
     590             : {
     591             :     try
     592             :     {
     593             :         int64_t nVal;
     594          22 :         this->m_pImageIO->getNoDataValue(this->nBand, &nVal, kealib::kea_64int);
     595          12 :         if (pbSuccess != nullptr)
     596           9 :             *pbSuccess = 1;
     597             : 
     598          12 :         return nVal;
     599             :     }
     600          10 :     catch (const kealib::KEAIOException &)
     601             :     {
     602          10 :         if (pbSuccess != nullptr)
     603          10 :             *pbSuccess = 0;
     604          10 :         return -1;
     605             :     }
     606             : }
     607             : 
     608          16 : uint64_t KEARasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
     609             : {
     610             :     try
     611             :     {
     612             :         uint64_t nVal;
     613          16 :         this->m_pImageIO->getNoDataValue(this->nBand, &nVal,
     614             :                                          kealib::kea_64uint);
     615           8 :         if (pbSuccess != nullptr)
     616           6 :             *pbSuccess = 1;
     617             : 
     618           8 :         return nVal;
     619             :     }
     620           8 :     catch (const kealib::KEAIOException &)
     621             :     {
     622           8 :         if (pbSuccess != nullptr)
     623           8 :             *pbSuccess = 0;
     624           8 :         return std::numeric_limits<uint64_t>::max();
     625             :     }
     626             : }
     627             : 
     628             : // set the no data value
     629          22 : CPLErr KEARasterBand::SetNoDataValue(double dfNoData)
     630             : {
     631             :     // need to check for out of range values
     632          22 :     bool bSet = true;
     633          22 :     GDALDataType dtype = this->GetRasterDataType();
     634          22 :     switch (dtype)
     635             :     {
     636           5 :         case GDT_Byte:
     637           5 :             bSet = (dfNoData >= 0) && (dfNoData <= UCHAR_MAX);
     638           5 :             break;
     639           4 :         case GDT_UInt16:
     640           4 :             bSet = (dfNoData >= 0) && (dfNoData <= USHRT_MAX);
     641           4 :             break;
     642           4 :         case GDT_Int16:
     643           4 :             bSet = (dfNoData >= SHRT_MIN) && (dfNoData <= SHRT_MAX);
     644           4 :             break;
     645           4 :         case GDT_UInt32:
     646           4 :             bSet = (dfNoData >= 0) && (dfNoData <= UINT_MAX);
     647           4 :             break;
     648           4 :         case GDT_Int32:
     649           4 :             bSet = (dfNoData >= INT_MIN) && (dfNoData <= INT_MAX);
     650           4 :             break;
     651           1 :         default:
     652             :             // for other types we can't really tell if outside the range
     653           1 :             break;
     654             :     }
     655             : 
     656             :     try
     657             :     {
     658          22 :         if (bSet)
     659             :         {
     660          12 :             this->m_pImageIO->setNoDataValue(this->nBand, &dfNoData,
     661             :                                              kealib::kea_64float);
     662             :         }
     663             :         else
     664             :         {
     665          10 :             this->m_pImageIO->undefineNoDataValue(this->nBand);
     666             :         }
     667          12 :         return CE_None;
     668             :     }
     669          10 :     catch (const kealib::KEAIOException &)
     670             :     {
     671          10 :         return CE_Failure;
     672             :     }
     673             : }
     674             : 
     675           3 : CPLErr KEARasterBand::SetNoDataValueAsInt64(int64_t nNoData)
     676             : {
     677             :     try
     678             :     {
     679           3 :         this->m_pImageIO->setNoDataValue(this->nBand, &nNoData,
     680             :                                          kealib::kea_64int);
     681             :     }
     682           0 :     catch (const kealib::KEAIOException &)
     683             :     {
     684           0 :         return CE_Failure;
     685             :     }
     686           3 :     return CE_None;
     687             : }
     688             : 
     689           2 : CPLErr KEARasterBand::SetNoDataValueAsUInt64(uint64_t nNoData)
     690             : {
     691             :     try
     692             :     {
     693           2 :         this->m_pImageIO->setNoDataValue(this->nBand, &nNoData,
     694             :                                          kealib::kea_64uint);
     695             :     }
     696           0 :     catch (const kealib::KEAIOException &)
     697             :     {
     698           0 :         return CE_Failure;
     699             :     }
     700           2 :     return CE_None;
     701             : }
     702             : 
     703          27 : CPLErr KEARasterBand::DeleteNoDataValue()
     704             : {
     705             :     try
     706             :     {
     707          27 :         m_pImageIO->undefineNoDataValue(this->nBand);
     708          17 :         return CE_None;
     709             :     }
     710          10 :     catch (const kealib::KEAIOException &)
     711             :     {
     712          10 :         return CE_Failure;
     713             :     }
     714             : }
     715             : 
     716           0 : CPLErr KEARasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
     717             :                                           int *pnBuckets,
     718             :                                           GUIntBig **ppanHistogram, int bForce,
     719             :                                           GDALProgressFunc fn,
     720             :                                           void *pProgressData)
     721             : {
     722           0 :     if (bForce)
     723             :     {
     724           0 :         return GDALPamRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
     725             :                                                       ppanHistogram, bForce, fn,
     726           0 :                                                       pProgressData);
     727             :     }
     728             :     else
     729             :     {
     730             :         // returned cached if avail
     731             :         // I've used the RAT interface here as it deals with data type
     732             :         // conversions. Would be nice to have GUIntBig support in RAT though...
     733           0 :         GDALRasterAttributeTable *pTable = this->GetDefaultRAT();
     734           0 :         if (pTable == nullptr)
     735           0 :             return CE_Failure;
     736           0 :         int nRows = pTable->GetRowCount();
     737             : 
     738             :         // find histogram column if it exists
     739           0 :         int nCol = pTable->GetColOfUsage(GFU_PixelCount);
     740           0 :         if (nCol == -1)
     741           0 :             return CE_Warning;
     742             : 
     743             :         double dfRow0Min, dfBinSize;
     744           0 :         if (!pTable->GetLinearBinning(&dfRow0Min, &dfBinSize))
     745           0 :             return CE_Warning;
     746             : 
     747           0 :         *ppanHistogram = (GUIntBig *)VSIMalloc2(nRows, sizeof(GUIntBig));
     748           0 :         if (*ppanHistogram == nullptr)
     749             :         {
     750           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     751             :                      "Memory Allocation failed in "
     752             :                      "KEARasterBand::GetDefaultHistogram");
     753           0 :             return CE_Failure;
     754             :         }
     755             : 
     756           0 :         double *pDoubleHisto = (double *)VSIMalloc2(nRows, sizeof(double));
     757           0 :         if (pDoubleHisto == nullptr)
     758             :         {
     759           0 :             CPLFree(*ppanHistogram);
     760           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     761             :                      "Memory Allocation failed in "
     762             :                      "KEARasterBand::GetDefaultHistogram");
     763           0 :             return CE_Failure;
     764             :         }
     765             : 
     766           0 :         if (pTable->ValuesIO(GF_Read, nCol, 0, nRows, pDoubleHisto) != CE_None)
     767           0 :             return CE_Failure;
     768             : 
     769             :         // convert to GUIntBig
     770           0 :         for (int n = 0; n < nRows; n++)
     771           0 :             (*ppanHistogram)[n] = static_cast<GUIntBig>(pDoubleHisto[n]);
     772             : 
     773           0 :         CPLFree(pDoubleHisto);
     774             : 
     775           0 :         *pnBuckets = nRows;
     776           0 :         *pdfMin = dfRow0Min;
     777           0 :         *pdfMax = dfRow0Min + ((nRows + 1) * dfBinSize);
     778           0 :         return CE_None;
     779             :     }
     780             : }
     781             : 
     782           0 : CPLErr KEARasterBand::SetDefaultHistogram(double /*dfMin*/, double /*dfMax*/,
     783             :                                           int nBuckets, GUIntBig *panHistogram)
     784             : {
     785             : 
     786           0 :     GDALRasterAttributeTable *pTable = this->GetDefaultRAT();
     787           0 :     if (pTable == nullptr)
     788           0 :         return CE_Failure;
     789           0 :     int nRows = pTable->GetRowCount();
     790             : 
     791             :     // find histogram column if it exists
     792           0 :     int nCol = pTable->GetColOfUsage(GFU_PixelCount);
     793           0 :     if (nCol == -1)
     794             :     {
     795           0 :         if (pTable->CreateColumn("Histogram", GFT_Real, GFU_PixelCount) !=
     796             :             CE_None)
     797           0 :             return CE_Failure;
     798             : 
     799           0 :         nCol = pTable->GetColumnCount() - 1;
     800             :     }
     801             : 
     802           0 :     if (nBuckets > nRows)
     803           0 :         pTable->SetRowCount(nBuckets);
     804             : 
     805             :     // convert to double (RATs don't take GUIntBig yet)
     806           0 :     double *pDoubleHist = (double *)VSIMalloc2(nBuckets, sizeof(double));
     807             : 
     808           0 :     if (pDoubleHist == nullptr)
     809             :     {
     810           0 :         CPLError(
     811             :             CE_Failure, CPLE_OutOfMemory,
     812             :             "Memory Allocation failed in KEARasterBand::SetDefaultHistogram");
     813           0 :         return CE_Failure;
     814             :     }
     815             : 
     816           0 :     for (int n = 0; n < nBuckets; n++)
     817           0 :         pDoubleHist[n] = static_cast<double>(panHistogram[n]);
     818             : 
     819           0 :     if (pTable->ValuesIO(GF_Write, nCol, 0, nBuckets, pDoubleHist) != CE_None)
     820             :     {
     821           0 :         CPLFree(pDoubleHist);
     822           0 :         return CE_Failure;
     823             :     }
     824             : 
     825           0 :     CPLFree(pDoubleHist);
     826             : 
     827           0 :     return CE_None;
     828             : }
     829             : 
     830         420 : GDALRasterAttributeTable *KEARasterBand::GetDefaultRAT()
     831             : {
     832         420 :     CPLMutexHolderD(&m_hMutex);
     833         420 :     if (this->m_pAttributeTable == nullptr)
     834             :     {
     835             :         try
     836             :         {
     837             :             // we assume this is never NULL - creates a new one if none exists
     838             :             // (or raises exception)
     839             :             kealib::KEAAttributeTable *pKEATable =
     840         704 :                 this->m_pImageIO->getAttributeTable(kealib::kea_att_file,
     841         352 :                                                     this->nBand);
     842         352 :             this->m_pAttributeTable =
     843         352 :                 new KEARasterAttributeTable(pKEATable, this);
     844             :         }
     845           0 :         catch (const kealib::KEAException &e)
     846             :         {
     847           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     848           0 :                      "Failed to read attributes: %s", e.what());
     849             :         }
     850             :     }
     851         840 :     return this->m_pAttributeTable;
     852             : }
     853             : 
     854           3 : CPLErr KEARasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT)
     855             : {
     856           3 :     if (poRAT == nullptr)
     857           1 :         return CE_Failure;
     858             : 
     859             :     try
     860             :     {
     861             :         KEARasterAttributeTable *pKEATable =
     862           2 :             (KEARasterAttributeTable *)this->GetDefaultRAT();
     863           2 :         if (pKEATable == nullptr)
     864           0 :             return CE_Failure;
     865             : 
     866           2 :         int numRows = poRAT->GetRowCount();
     867           2 :         pKEATable->SetRowCount(numRows);
     868             : 
     869          10 :         for (int nGDALColumnIndex = 0;
     870          10 :              nGDALColumnIndex < poRAT->GetColumnCount(); nGDALColumnIndex++)
     871             :         {
     872           8 :             const char *pszColumnName = poRAT->GetNameOfCol(nGDALColumnIndex);
     873           8 :             GDALRATFieldType eFieldType = poRAT->GetTypeOfCol(nGDALColumnIndex);
     874             : 
     875             :             // do we have it?
     876           8 :             bool bExists = false;
     877             :             int nKEAColumnIndex;
     878          29 :             for (nKEAColumnIndex = 0;
     879          29 :                  nKEAColumnIndex < pKEATable->GetColumnCount();
     880             :                  nKEAColumnIndex++)
     881             :             {
     882          29 :                 if (EQUAL(pszColumnName,
     883             :                           pKEATable->GetNameOfCol(nKEAColumnIndex)))
     884             :                 {
     885           8 :                     bExists = true;
     886           8 :                     break;
     887             :                 }
     888             :             }
     889             : 
     890           8 :             if (!bExists)
     891             :             {
     892           0 :                 if (pKEATable->CreateColumn(
     893             :                         pszColumnName, eFieldType,
     894           0 :                         poRAT->GetUsageOfCol(nGDALColumnIndex)) != CE_None)
     895             :                 {
     896           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     897             :                              "Failed to create column");
     898           0 :                     return CE_Failure;
     899             :                 }
     900           0 :                 nKEAColumnIndex = pKEATable->GetColumnCount() - 1;
     901             :             }
     902             : 
     903           8 :             if (numRows == 0)
     904           1 :                 continue;
     905             : 
     906             :             // ok now copy data
     907           7 :             if (eFieldType == GFT_Integer)
     908             :             {
     909             :                 int *panIntData =
     910           4 :                     (int *)VSI_MALLOC2_VERBOSE(numRows, sizeof(int));
     911           4 :                 if (panIntData == nullptr)
     912             :                 {
     913           0 :                     return CE_Failure;
     914             :                 }
     915             : 
     916           4 :                 if (((GDALRasterAttributeTable *)poRAT)
     917           8 :                         ->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows,
     918           4 :                                    panIntData) == CE_None)
     919             :                 {
     920           4 :                     pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0, numRows,
     921           4 :                                         panIntData);
     922             :                 }
     923           4 :                 CPLFree(panIntData);
     924             :             }
     925           3 :             else if (eFieldType == GFT_Real)
     926             :             {
     927             :                 double *padfFloatData =
     928           2 :                     (double *)VSI_MALLOC2_VERBOSE(numRows, sizeof(double));
     929           2 :                 if (padfFloatData == nullptr)
     930             :                 {
     931           0 :                     return CE_Failure;
     932             :                 }
     933             : 
     934           2 :                 if (((GDALRasterAttributeTable *)poRAT)
     935           4 :                         ->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows,
     936           2 :                                    padfFloatData) == CE_None)
     937             :                 {
     938           2 :                     pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0, numRows,
     939           2 :                                         padfFloatData);
     940             :                 }
     941           2 :                 CPLFree(padfFloatData);
     942             :             }
     943             :             else
     944             :             {
     945             :                 char **papszStringData =
     946           1 :                     (char **)VSI_MALLOC2_VERBOSE(numRows, sizeof(char *));
     947           1 :                 if (papszStringData == nullptr)
     948             :                 {
     949           0 :                     return CE_Failure;
     950             :                 }
     951             : 
     952           1 :                 if (((GDALRasterAttributeTable *)poRAT)
     953           2 :                         ->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows,
     954           1 :                                    papszStringData) == CE_None)
     955             :                 {
     956           1 :                     pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0, numRows,
     957           1 :                                         papszStringData);
     958           2 :                     for (int n = 0; n < numRows; n++)
     959           1 :                         CPLFree(papszStringData[n]);
     960             :                 }
     961           1 :                 CPLFree(papszStringData);
     962             :             }
     963             :         }
     964             :     }
     965           0 :     catch (const kealib::KEAException &e)
     966             :     {
     967           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to write attributes: %s",
     968           0 :                  e.what());
     969           0 :         return CE_Failure;
     970             :     }
     971           2 :     return CE_None;
     972             : }
     973             : 
     974           4 : GDALColorTable *KEARasterBand::GetColorTable()
     975             : {
     976           4 :     CPLMutexHolderD(&m_hMutex);
     977           4 :     if (this->m_pColorTable == nullptr)
     978             :     {
     979             :         try
     980             :         {
     981           4 :             GDALRasterAttributeTable *pKEATable = this->GetDefaultRAT();
     982           4 :             int nRedIdx = -1;
     983           4 :             int nGreenIdx = -1;
     984           4 :             int nBlueIdx = -1;
     985           4 :             int nAlphaIdx = -1;
     986             : 
     987          12 :             for (int nColIdx = 0; nColIdx < pKEATable->GetColumnCount();
     988             :                  nColIdx++)
     989             :             {
     990           8 :                 if (pKEATable->GetTypeOfCol(nColIdx) == GFT_Integer)
     991             :                 {
     992             :                     GDALRATFieldUsage eFieldUsage =
     993           8 :                         pKEATable->GetUsageOfCol(nColIdx);
     994           8 :                     if (eFieldUsage == GFU_Red)
     995           2 :                         nRedIdx = nColIdx;
     996           6 :                     else if (eFieldUsage == GFU_Green)
     997           2 :                         nGreenIdx = nColIdx;
     998           4 :                     else if (eFieldUsage == GFU_Blue)
     999           2 :                         nBlueIdx = nColIdx;
    1000           2 :                     else if (eFieldUsage == GFU_Alpha)
    1001           2 :                         nAlphaIdx = nColIdx;
    1002             :                 }
    1003             :             }
    1004             : 
    1005           4 :             if ((nRedIdx != -1) && (nGreenIdx != -1) && (nBlueIdx != -1) &&
    1006             :                 (nAlphaIdx != -1))
    1007             :             {
    1008             :                 // we need to create one - only do RGB palettes
    1009           2 :                 this->m_pColorTable = new GDALColorTable(GPI_RGB);
    1010             : 
    1011             :                 // OK go through each row and fill in the fields
    1012           8 :                 for (int nRowIndex = 0; nRowIndex < pKEATable->GetRowCount();
    1013             :                      nRowIndex++)
    1014             :                 {
    1015             :                     // maybe could be more efficient using ValuesIO
    1016             :                     GDALColorEntry colorEntry;
    1017           6 :                     colorEntry.c1 = static_cast<short>(
    1018           6 :                         pKEATable->GetValueAsInt(nRowIndex, nRedIdx));
    1019           6 :                     colorEntry.c2 = static_cast<short>(
    1020           6 :                         pKEATable->GetValueAsInt(nRowIndex, nGreenIdx));
    1021           6 :                     colorEntry.c3 = static_cast<short>(
    1022           6 :                         pKEATable->GetValueAsInt(nRowIndex, nBlueIdx));
    1023           6 :                     colorEntry.c4 = static_cast<short>(
    1024           6 :                         pKEATable->GetValueAsInt(nRowIndex, nAlphaIdx));
    1025           6 :                     this->m_pColorTable->SetColorEntry(nRowIndex, &colorEntry);
    1026             :                 }
    1027             :             }
    1028             :         }
    1029           0 :         catch (const kealib::KEAException &e)
    1030             :         {
    1031           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1032           0 :                      "Failed to read color table: %s", e.what());
    1033           0 :             delete this->m_pColorTable;
    1034           0 :             this->m_pColorTable = nullptr;
    1035             :         }
    1036             :     }
    1037           8 :     return this->m_pColorTable;
    1038             : }
    1039             : 
    1040           5 : CPLErr KEARasterBand::SetColorTable(GDALColorTable *poCT)
    1041             : {
    1042           5 :     if (poCT == nullptr)
    1043           2 :         return CE_Failure;
    1044             : 
    1045           6 :     CPLMutexHolderD(&m_hMutex);
    1046             :     try
    1047             :     {
    1048           3 :         GDALRasterAttributeTable *pKEATable = this->GetDefaultRAT();
    1049           3 :         if (pKEATable == nullptr)
    1050           0 :             return CE_Failure;
    1051           3 :         int nRedIdx = -1;
    1052           3 :         int nGreenIdx = -1;
    1053           3 :         int nBlueIdx = -1;
    1054           3 :         int nAlphaIdx = -1;
    1055             : 
    1056           3 :         if (poCT->GetColorEntryCount() > pKEATable->GetRowCount())
    1057             :         {
    1058           2 :             pKEATable->SetRowCount(poCT->GetColorEntryCount());
    1059             :         }
    1060             : 
    1061           7 :         for (int nColIdx = 0; nColIdx < pKEATable->GetColumnCount(); nColIdx++)
    1062             :         {
    1063           4 :             if (pKEATable->GetTypeOfCol(nColIdx) == GFT_Integer)
    1064             :             {
    1065             :                 GDALRATFieldUsage eFieldUsage =
    1066           4 :                     pKEATable->GetUsageOfCol(nColIdx);
    1067           4 :                 if (eFieldUsage == GFU_Red)
    1068           1 :                     nRedIdx = nColIdx;
    1069           3 :                 else if (eFieldUsage == GFU_Green)
    1070           1 :                     nGreenIdx = nColIdx;
    1071           2 :                 else if (eFieldUsage == GFU_Blue)
    1072           1 :                     nBlueIdx = nColIdx;
    1073           1 :                 else if (eFieldUsage == GFU_Alpha)
    1074           1 :                     nAlphaIdx = nColIdx;
    1075             :             }
    1076             :         }
    1077             : 
    1078             :         // create if needed
    1079           3 :         if (nRedIdx == -1)
    1080             :         {
    1081           2 :             if (pKEATable->CreateColumn("Red", GFT_Integer, GFU_Red) != CE_None)
    1082             :             {
    1083           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1084             :                          "Failed to create column");
    1085           0 :                 return CE_Failure;
    1086             :             }
    1087           2 :             nRedIdx = pKEATable->GetColumnCount() - 1;
    1088             :         }
    1089           3 :         if (nGreenIdx == -1)
    1090             :         {
    1091           2 :             if (pKEATable->CreateColumn("Green", GFT_Integer, GFU_Green) !=
    1092             :                 CE_None)
    1093             :             {
    1094           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1095             :                          "Failed to create column");
    1096           0 :                 return CE_Failure;
    1097             :             }
    1098           2 :             nGreenIdx = pKEATable->GetColumnCount() - 1;
    1099             :         }
    1100           3 :         if (nBlueIdx == -1)
    1101             :         {
    1102           2 :             if (pKEATable->CreateColumn("Blue", GFT_Integer, GFU_Blue) !=
    1103             :                 CE_None)
    1104             :             {
    1105           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1106             :                          "Failed to create column");
    1107           0 :                 return CE_Failure;
    1108             :             }
    1109           2 :             nBlueIdx = pKEATable->GetColumnCount() - 1;
    1110             :         }
    1111           3 :         if (nAlphaIdx == -1)
    1112             :         {
    1113           2 :             if (pKEATable->CreateColumn("Alpha", GFT_Integer, GFU_Alpha) !=
    1114             :                 CE_None)
    1115             :             {
    1116           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1117             :                          "Failed to create column");
    1118           0 :                 return CE_Failure;
    1119             :             }
    1120           2 :             nAlphaIdx = pKEATable->GetColumnCount() - 1;
    1121             :         }
    1122             : 
    1123             :         // OK go through each row and fill in the fields
    1124          12 :         for (int nRowIndex = 0; nRowIndex < poCT->GetColorEntryCount();
    1125             :              nRowIndex++)
    1126             :         {
    1127             :             // maybe could be more efficient using ValuesIO
    1128             :             GDALColorEntry colorEntry;
    1129           9 :             poCT->GetColorEntryAsRGB(nRowIndex, &colorEntry);
    1130           9 :             pKEATable->SetValue(nRowIndex, nRedIdx, colorEntry.c1);
    1131           9 :             pKEATable->SetValue(nRowIndex, nGreenIdx, colorEntry.c2);
    1132           9 :             pKEATable->SetValue(nRowIndex, nBlueIdx, colorEntry.c3);
    1133           9 :             pKEATable->SetValue(nRowIndex, nAlphaIdx, colorEntry.c4);
    1134             :         }
    1135             : 
    1136             :         // out of date
    1137           3 :         delete this->m_pColorTable;
    1138           3 :         this->m_pColorTable = nullptr;
    1139             :     }
    1140           0 :     catch (const kealib::KEAException &e)
    1141             :     {
    1142           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to write color table: %s",
    1143           0 :                  e.what());
    1144           0 :         return CE_Failure;
    1145             :     }
    1146           3 :     return CE_None;
    1147             : }
    1148             : 
    1149          72 : GDALColorInterp KEARasterBand::GetColorInterpretation()
    1150             : {
    1151             :     kealib::KEABandClrInterp ekeainterp;
    1152             :     try
    1153             :     {
    1154          72 :         ekeainterp = this->m_pImageIO->getImageBandClrInterp(this->nBand);
    1155             :     }
    1156           0 :     catch (const kealib::KEAException &)
    1157             :     {
    1158           0 :         return GCI_GrayIndex;
    1159             :     }
    1160             : 
    1161             :     GDALColorInterp egdalinterp;
    1162          72 :     switch (ekeainterp)
    1163             :     {
    1164          42 :         case kealib::kea_generic:
    1165             :         case kealib::kea_greyindex:
    1166          42 :             egdalinterp = GCI_GrayIndex;
    1167          42 :             break;
    1168           2 :         case kealib::kea_paletteindex:
    1169           2 :             egdalinterp = GCI_PaletteIndex;
    1170           2 :             break;
    1171           2 :         case kealib::kea_redband:
    1172           2 :             egdalinterp = GCI_RedBand;
    1173           2 :             break;
    1174           2 :         case kealib::kea_greenband:
    1175           2 :             egdalinterp = GCI_GreenBand;
    1176           2 :             break;
    1177           2 :         case kealib::kea_blueband:
    1178           2 :             egdalinterp = GCI_BlueBand;
    1179           2 :             break;
    1180           2 :         case kealib::kea_alphaband:
    1181           2 :             egdalinterp = GCI_AlphaBand;
    1182           2 :             break;
    1183           2 :         case kealib::kea_hueband:
    1184           2 :             egdalinterp = GCI_HueBand;
    1185           2 :             break;
    1186           2 :         case kealib::kea_saturationband:
    1187           2 :             egdalinterp = GCI_SaturationBand;
    1188           2 :             break;
    1189           2 :         case kealib::kea_lightnessband:
    1190           2 :             egdalinterp = GCI_LightnessBand;
    1191           2 :             break;
    1192           2 :         case kealib::kea_cyanband:
    1193           2 :             egdalinterp = GCI_CyanBand;
    1194           2 :             break;
    1195           2 :         case kealib::kea_magentaband:
    1196           2 :             egdalinterp = GCI_MagentaBand;
    1197           2 :             break;
    1198           2 :         case kealib::kea_yellowband:
    1199           2 :             egdalinterp = GCI_YellowBand;
    1200           2 :             break;
    1201           2 :         case kealib::kea_blackband:
    1202           2 :             egdalinterp = GCI_BlackBand;
    1203           2 :             break;
    1204           2 :         case kealib::kea_ycbcr_yband:
    1205           2 :             egdalinterp = GCI_YCbCr_YBand;
    1206           2 :             break;
    1207           2 :         case kealib::kea_ycbcr_cbband:
    1208           2 :             egdalinterp = GCI_YCbCr_CbBand;
    1209           2 :             break;
    1210           2 :         case kealib::kea_ycbcr_crband:
    1211           2 :             egdalinterp = GCI_YCbCr_CrBand;
    1212           2 :             break;
    1213           0 :         default:
    1214           0 :             egdalinterp = GCI_GrayIndex;
    1215           0 :             break;
    1216             :     }
    1217             : 
    1218          72 :     return egdalinterp;
    1219             : }
    1220             : 
    1221         104 : CPLErr KEARasterBand::SetColorInterpretation(GDALColorInterp egdalinterp)
    1222             : {
    1223             :     kealib::KEABandClrInterp ekeainterp;
    1224         104 :     switch (egdalinterp)
    1225             :     {
    1226          53 :         case GCI_GrayIndex:
    1227          53 :             ekeainterp = kealib::kea_greyindex;
    1228          53 :             break;
    1229           2 :         case GCI_PaletteIndex:
    1230           2 :             ekeainterp = kealib::kea_paletteindex;
    1231           2 :             break;
    1232           2 :         case GCI_RedBand:
    1233           2 :             ekeainterp = kealib::kea_redband;
    1234           2 :             break;
    1235           2 :         case GCI_GreenBand:
    1236           2 :             ekeainterp = kealib::kea_greenband;
    1237           2 :             break;
    1238           2 :         case GCI_BlueBand:
    1239           2 :             ekeainterp = kealib::kea_blueband;
    1240           2 :             break;
    1241           2 :         case GCI_AlphaBand:
    1242           2 :             ekeainterp = kealib::kea_alphaband;
    1243           2 :             break;
    1244           2 :         case GCI_HueBand:
    1245           2 :             ekeainterp = kealib::kea_hueband;
    1246           2 :             break;
    1247           2 :         case GCI_SaturationBand:
    1248           2 :             ekeainterp = kealib::kea_saturationband;
    1249           2 :             break;
    1250           2 :         case GCI_LightnessBand:
    1251           2 :             ekeainterp = kealib::kea_lightnessband;
    1252           2 :             break;
    1253           2 :         case GCI_CyanBand:
    1254           2 :             ekeainterp = kealib::kea_cyanband;
    1255           2 :             break;
    1256           2 :         case GCI_MagentaBand:
    1257           2 :             ekeainterp = kealib::kea_magentaband;
    1258           2 :             break;
    1259           2 :         case GCI_YellowBand:
    1260           2 :             ekeainterp = kealib::kea_yellowband;
    1261           2 :             break;
    1262           2 :         case GCI_BlackBand:
    1263           2 :             ekeainterp = kealib::kea_blackband;
    1264           2 :             break;
    1265           2 :         case GCI_YCbCr_YBand:
    1266           2 :             ekeainterp = kealib::kea_ycbcr_yband;
    1267           2 :             break;
    1268           2 :         case GCI_YCbCr_CbBand:
    1269           2 :             ekeainterp = kealib::kea_ycbcr_cbband;
    1270           2 :             break;
    1271           2 :         case GCI_YCbCr_CrBand:
    1272           2 :             ekeainterp = kealib::kea_ycbcr_crband;
    1273           2 :             break;
    1274          21 :         default:
    1275          21 :             ekeainterp = kealib::kea_greyindex;
    1276          21 :             break;
    1277             :     }
    1278             : 
    1279             :     try
    1280             :     {
    1281         104 :         this->m_pImageIO->setImageBandClrInterp(this->nBand, ekeainterp);
    1282             :     }
    1283           0 :     catch (const kealib::KEAException &)
    1284             :     {
    1285             :         // Do nothing? The docs say CE_Failure only if unsupported by format.
    1286             :     }
    1287         104 :     return CE_None;
    1288             : }
    1289             : 
    1290             : // clean up our overview objects
    1291             : // assumes mutex being held by caller
    1292         700 : void KEARasterBand::deleteOverviewObjects()
    1293             : {
    1294             :     // deletes the objects - not the overviews themselves
    1295             :     int nCount;
    1296         703 :     for (nCount = 0; nCount < m_nOverviews; nCount++)
    1297             :     {
    1298           3 :         delete m_panOverviewBands[nCount];
    1299             :     }
    1300         700 :     CPLFree(m_panOverviewBands);
    1301         700 :     m_panOverviewBands = nullptr;
    1302         700 :     m_nOverviews = 0;
    1303         700 : }
    1304             : 
    1305             : // read in any overviews in the file into our array of objects
    1306         347 : void KEARasterBand::readExistingOverviews()
    1307             : {
    1308         694 :     CPLMutexHolderD(&m_hMutex);
    1309             :     // delete any existing overview bands
    1310         347 :     this->deleteOverviewObjects();
    1311             : 
    1312         347 :     m_nOverviews = this->m_pImageIO->getNumOfOverviews(this->nBand);
    1313         347 :     m_panOverviewBands =
    1314         347 :         (KEAOverview **)CPLMalloc(sizeof(KEAOverview *) * m_nOverviews);
    1315             : 
    1316             :     uint64_t nXSize, nYSize;
    1317         349 :     for (int nCount = 0; nCount < m_nOverviews; nCount++)
    1318             :     {
    1319           2 :         this->m_pImageIO->getOverviewSize(this->nBand, nCount + 1, &nXSize,
    1320             :                                           &nYSize);
    1321           2 :         m_panOverviewBands[nCount] = new KEAOverview(
    1322           2 :             (KEADataset *)this->poDS, this->nBand, GA_ReadOnly,
    1323           2 :             this->m_pImageIO, this->m_pRefCount, nCount + 1, nXSize, nYSize);
    1324             :     }
    1325         347 : }
    1326             : 
    1327             : // number of overviews
    1328          56 : int KEARasterBand::GetOverviewCount()
    1329             : {
    1330          56 :     return m_nOverviews;
    1331             : }
    1332             : 
    1333             : // get a given overview
    1334           6 : GDALRasterBand *KEARasterBand::GetOverview(int nOverview)
    1335             : {
    1336           6 :     if (nOverview < 0 || nOverview >= m_nOverviews)
    1337             :     {
    1338           2 :         return nullptr;
    1339             :     }
    1340             :     else
    1341             :     {
    1342           4 :         return m_panOverviewBands[nOverview];
    1343             :     }
    1344             : }
    1345             : 
    1346           2 : CPLErr KEARasterBand::CreateMaskBand(int)
    1347             : {
    1348           4 :     CPLMutexHolderD(&m_hMutex);
    1349           2 :     if (m_bMaskBandOwned)
    1350           0 :         delete m_pMaskBand;
    1351           2 :     m_pMaskBand = nullptr;
    1352             :     try
    1353             :     {
    1354           2 :         this->m_pImageIO->createMask(this->nBand);
    1355             :     }
    1356           0 :     catch (const kealib::KEAException &e)
    1357             :     {
    1358           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Failed to create mask band: %s",
    1359           0 :                  e.what());
    1360           0 :         return CE_Failure;
    1361             :     }
    1362           2 :     return CE_None;
    1363             : }
    1364             : 
    1365         105 : GDALRasterBand *KEARasterBand::GetMaskBand()
    1366             : {
    1367         105 :     CPLMutexHolderD(&m_hMutex);
    1368         105 :     if (m_pMaskBand == nullptr)
    1369             :     {
    1370             :         try
    1371             :         {
    1372         100 :             if (this->m_pImageIO->maskCreated(this->nBand))
    1373             :             {
    1374           3 :                 m_pMaskBand =
    1375           3 :                     new KEAMaskBand(this, this->m_pImageIO, this->m_pRefCount);
    1376           3 :                 m_bMaskBandOwned = true;
    1377             :             }
    1378             :             else
    1379             :             {
    1380             :                 // use the base class implementation - GDAL will delete
    1381             :                 // fprintf( stderr, "returning base GetMaskBand()\n" );
    1382          97 :                 m_pMaskBand = GDALPamRasterBand::GetMaskBand();
    1383             :             }
    1384             :         }
    1385           0 :         catch (const kealib::KEAException &)
    1386             :         {
    1387             :             // do nothing?
    1388             :         }
    1389             :     }
    1390         210 :     return m_pMaskBand;
    1391             : }
    1392             : 
    1393         100 : int KEARasterBand::GetMaskFlags()
    1394             : {
    1395             :     try
    1396             :     {
    1397         100 :         if (!this->m_pImageIO->maskCreated(this->nBand))
    1398             :         {
    1399             :             // need to return the base class one since we are using
    1400             :             // the base class implementation of GetMaskBand()
    1401             :             // fprintf( stderr, "returning base GetMaskFlags()\n" );
    1402          97 :             return GDALPamRasterBand::GetMaskFlags();
    1403             :         }
    1404             :     }
    1405           0 :     catch (const kealib::KEAException &)
    1406             :     {
    1407             :         // do nothing?
    1408             :     }
    1409             : 
    1410             :     // none of the other flags seem to make sense...
    1411           3 :     return 0;
    1412             : }
    1413             : 
    1414           1 : kealib::KEALayerType KEARasterBand::getLayerType() const
    1415             : {
    1416           1 :     return m_pImageIO->getImageBandLayerType(nBand);
    1417             : }
    1418             : 
    1419           0 : void KEARasterBand::setLayerType(kealib::KEALayerType eLayerType)
    1420             : {
    1421           0 :     m_pImageIO->setImageBandLayerType(nBand, eLayerType);
    1422           0 : }

Generated by: LCOV version 1.14