1 /*
2  * $Id: keaband.cpp 28011 2014-11-26 13:47:09Z rouault $
3  *  keaband.cpp
4  *
5  *  Created by Pete Bunting on 01/08/2012.
6  *  Copyright 2012 LibKEA. All rights reserved.
7  *
8  *  This file is part of LibKEA.
9  *
10  *  Permission is hereby granted, free of charge, to any person
11  *  obtaining a copy of this software and associated documentation
12  *  files (the "Software"), to deal in the Software without restriction,
13  *  including without limitation the rights to use, copy, modify,
14  *  merge, publish, distribute, sublicense, and/or sell copies of the
15  *  Software, and to permit persons to whom the Software is furnished
16  *  to do so, subject to the following conditions:
17  *
18  *  The above copyright notice and this permission notice shall be
19  *  included in all copies or substantial portions of the Software.
20  *
21  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23  *  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24  *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
25  *  ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
26  *  CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28  *
29  */
30 
31 #include "keaband.h"
32 #include "keaoverview.h"
33 #include "keamaskband.h"
34 #include "kearat.h"
35 
36 #include "gdal_rat.h"
37 #include "libkea/KEAAttributeTable.h"
38 
39 #include <map>
40 #include <vector>
41 
42 #include <limits.h>
43 
44 // constructor
KEARasterBand(KEADataset * pDataset,int nSrcBand,GDALAccess eAccess,kealib::KEAImageIO * pImageIO,int * pRefCount)45 KEARasterBand::KEARasterBand( KEADataset *pDataset, int nSrcBand, GDALAccess eAccess, kealib::KEAImageIO *pImageIO, int *pRefCount )
46 {
47     this->poDS = pDataset; // our pointer onto the dataset
48     this->nBand = nSrcBand; // this is the band we are
49     this->m_eKEADataType = pImageIO->getImageBandDataType(nSrcBand); // get the data type as KEA enum
50     this->eDataType = KEA_to_GDAL_Type( m_eKEADataType );       // convert to GDAL enum
51     this->nBlockXSize = pImageIO->getImageBlockSize(nSrcBand);  // get the native blocksize
52     this->nBlockYSize = pImageIO->getImageBlockSize(nSrcBand);
53     this->nRasterXSize = this->poDS->GetRasterXSize();          // ask the dataset for the total image size
54     this->nRasterYSize = this->poDS->GetRasterYSize();
55     this->eAccess = eAccess;
56 
57     if( pImageIO->attributeTablePresent(nSrcBand) )
58     {
59         this->m_nAttributeChunkSize = pImageIO->getAttributeTableChunkSize(nSrcBand);
60     }
61     else
62     {
63         this->m_nAttributeChunkSize = -1; // don't report
64     }
65 
66     // grab the imageio class and its refcount
67     this->m_pImageIO = pImageIO;
68     this->m_pnRefCount = pRefCount;
69     // increment the refcount as we now have a reference to imageio
70     (*this->m_pnRefCount)++;
71 
72     // initialise overview variables
73     m_nOverviews = 0;
74     m_panOverviewBands = NULL;
75 
76     // mask band
77     m_pMaskBand = NULL;
78     m_bMaskBandOwned = false;
79 
80     // grab the description here
81     this->sDescription = pImageIO->getImageBandDescription(nSrcBand);
82 
83     this->m_pAttributeTable = NULL;  // no RAT yet
84     this->m_pColorTable = NULL;     // no color table yet
85 
86     // initialise the metadata as a CPLStringList
87     m_papszMetadataList = NULL;
88     this->UpdateMetadataList();
89 }
90 
91 // destructor
~KEARasterBand()92 KEARasterBand::~KEARasterBand()
93 {
94     // destroy RAT if any
95     delete this->m_pAttributeTable;
96     // destroy color table if any
97     delete this->m_pColorTable;
98     // destroy the metadata
99     CSLDestroy(this->m_papszMetadataList);
100     // delete any overview bands
101     this->deleteOverviewObjects();
102 
103     // if GDAL created the mask it will delete it
104     if( m_bMaskBandOwned )
105     {
106         delete m_pMaskBand;
107     }
108 
109     // according to the docs, this is required
110     this->FlushCache();
111 
112     // decrement the recount and delete if needed
113     (*m_pnRefCount)--;
114     if( *m_pnRefCount == 0 )
115     {
116         try
117         {
118             m_pImageIO->close();
119         }
120         catch (kealib::KEAIOException &e)
121         {
122         }
123         delete m_pImageIO;
124         delete m_pnRefCount;
125     }
126 }
127 
128 // internal method that updates the metadata into m_papszMetadataList
UpdateMetadataList()129 void KEARasterBand::UpdateMetadataList()
130 {
131     std::vector< std::pair<std::string, std::string> > data;
132 
133     // get all the metadata and iterate through
134     data = this->m_pImageIO->getImageBandMetaData(this->nBand);
135     for(std::vector< std::pair<std::string, std::string> >::iterator iterMetaData = data.begin(); iterMetaData != data.end(); ++iterMetaData)
136     {
137         // add to our list
138         m_papszMetadataList = CSLSetNameValue(m_papszMetadataList, iterMetaData->first.c_str(), iterMetaData->second.c_str());
139     }
140     // we have a pseudo metadata item that tells if we are thematic
141     // or continuous like the HFA driver
142     if( this->m_pImageIO->getImageBandLayerType(this->nBand) == kealib::kea_continuous )
143     {
144         m_papszMetadataList = CSLSetNameValue(m_papszMetadataList, "LAYER_TYPE", "athematic" );
145     }
146     else
147     {
148         m_papszMetadataList = CSLSetNameValue(m_papszMetadataList, "LAYER_TYPE", "thematic" );
149     }
150     // attribute table chunksize
151     if( this->m_nAttributeChunkSize != -1 )
152     {
153         char szTemp[100];
154         snprintf(szTemp, 100, "%d", this->m_nAttributeChunkSize );
155         m_papszMetadataList = CSLSetNameValue(m_papszMetadataList, "ATTRIBUTETABLE_CHUNKSIZE", szTemp );
156     }
157 }
158 
159 // internal method to create the overviews
CreateOverviews(int nOverviews,int * panOverviewList)160 void KEARasterBand::CreateOverviews(int nOverviews, int *panOverviewList)
161 {
162     // delete any existing overview bands
163     this->deleteOverviewObjects();
164 
165     // allocate space
166     m_panOverviewBands = (KEAOverview**)CPLMalloc(sizeof(KEAOverview*) * nOverviews);
167     m_nOverviews = nOverviews;
168 
169     // loop through and create the overviews
170     int nFactor, nXSize, nYSize;
171     for( int nCount = 0; nCount < m_nOverviews; nCount++ )
172     {
173         nFactor = panOverviewList[nCount];
174         // divide by the factor to get the new size
175         nXSize = this->nRasterXSize / nFactor;
176         nYSize = this->nRasterYSize / nFactor;
177 
178         // tell image io to create a new overview
179         this->m_pImageIO->createOverview(this->nBand, nCount + 1, nXSize, nYSize);
180 
181         // create one of our objects to represent it
182         m_panOverviewBands[nCount] = new KEAOverview((KEADataset*)this->poDS, this->nBand, GA_Update,
183                                         this->m_pImageIO, this->m_pnRefCount, nCount + 1, nXSize, nYSize);
184     }
185 }
186 
187 // virtual method to read a block
IReadBlock(int nBlockXOff,int nBlockYOff,void * pImage)188 CPLErr KEARasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage )
189 {
190     try
191     {
192         // GDAL deals in blocks - if we are at the end of a row
193         // we need to adjust the amount read so we don't go over the edge
194         int nxsize = this->nBlockXSize;
195         int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
196         if( nxtotalsize > this->nRasterXSize )
197         {
198             nxsize -= (nxtotalsize - this->nRasterXSize);
199         }
200         int nysize = this->nBlockYSize;
201         int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
202         if( nytotalsize > this->nRasterYSize )
203         {
204             nysize -= (nytotalsize - this->nRasterYSize);
205         }
206         this->m_pImageIO->readImageBlock2Band( this->nBand, pImage, this->nBlockXSize * nBlockXOff,
207                                             this->nBlockYSize * nBlockYOff,
208                                             nxsize, nysize, this->nBlockXSize, this->nBlockYSize,
209                                             this->m_eKEADataType );
210         return CE_None;
211     }
212     catch (kealib::KEAIOException &e)
213     {
214         CPLError( CE_Failure, CPLE_AppDefined,
215                 "Failed to read file: %s", e.what() );
216         return CE_Failure;
217     }
218 }
219 
220 // virtual method to write a block
IWriteBlock(int nBlockXOff,int nBlockYOff,void * pImage)221 CPLErr KEARasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff, void * pImage )
222 {
223     try
224     {
225         // GDAL deals in blocks - if we are at the end of a row
226         // we need to adjust the amount written so we don't go over the edge
227         int nxsize = this->nBlockXSize;
228         int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
229         if( nxtotalsize > this->nRasterXSize )
230         {
231             nxsize -= (nxtotalsize - this->nRasterXSize);
232         }
233         int nysize = this->nBlockYSize;
234         int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
235         if( nytotalsize > this->nRasterYSize )
236         {
237             nysize -= (nytotalsize - this->nRasterYSize);
238         }
239 
240         this->m_pImageIO->writeImageBlock2Band( this->nBand, pImage, this->nBlockXSize * nBlockXOff,
241                                             this->nBlockYSize * nBlockYOff,
242                                             nxsize, nysize, this->nBlockXSize, this->nBlockYSize,
243                                             this->m_eKEADataType );
244         return CE_None;
245     }
246     catch (kealib::KEAIOException &e)
247     {
248         CPLError( CE_Failure, CPLE_AppDefined,
249                 "Failed to write file: %s", e.what() );
250         return CE_Failure;
251     }
252 }
253 
SetDescription(const char * pszDescription)254 void KEARasterBand::SetDescription(const char *pszDescription)
255 {
256     try
257     {
258         this->m_pImageIO->setImageBandDescription(this->nBand, pszDescription);
259         GDALPamRasterBand::SetDescription(pszDescription);
260     }
261     catch (kealib::KEAIOException &e)
262     {
263         // ignore?
264     }
265 }
266 
267 // set a metadata item
SetMetadataItem(const char * pszName,const char * pszValue,const char * pszDomain)268 CPLErr KEARasterBand::SetMetadataItem(const char *pszName, const char *pszValue, const char *pszDomain)
269 {
270     // only deal with 'default' domain - no geolocation etc
271     if( ( pszDomain != NULL ) && ( *pszDomain != '\0' ) )
272         return CE_Failure;
273     try
274     {
275         // if it is LAYER_TYPE handle it seperately
276         if( EQUAL( pszName, "LAYER_TYPE" ) )
277         {
278             if( EQUAL( pszValue, "athematic" ) )
279             {
280                 this->m_pImageIO->setImageBandLayerType(this->nBand, kealib::kea_continuous );
281             }
282             else
283             {
284                 this->m_pImageIO->setImageBandLayerType(this->nBand, kealib::kea_thematic );
285             }
286         }
287         else
288         {
289             // otherwise set it as normal
290             this->m_pImageIO->setImageBandMetaData(this->nBand, pszName, pszValue );
291         }
292         // CSLSetNameValue will update if already there
293         m_papszMetadataList = CSLSetNameValue( m_papszMetadataList, pszName, pszValue );
294         return CE_None;
295     }
296     catch (kealib::KEAIOException &e)
297     {
298         return CE_Failure;
299     }
300 }
301 
302 // get a single metdata item
GetMetadataItem(const char * pszName,const char * pszDomain)303 const char *KEARasterBand::GetMetadataItem (const char *pszName, const char *pszDomain)
304 {
305     // only deal with 'default' domain - no geolocation etc
306     if( ( pszDomain != NULL ) && ( *pszDomain != '\0' ) )
307         return NULL;
308     // get it out of the CSLStringList so we can be sure it is persistant
309     return CSLFetchNameValue(m_papszMetadataList, pszName);
310 }
311 
312 // get all the metadata as a CSLStringList
GetMetadata(const char * pszDomain)313 char **KEARasterBand::GetMetadata(const char *pszDomain)
314 {
315     // only deal with 'default' domain - no geolocation etc
316     if( ( pszDomain != NULL ) && ( *pszDomain != '\0' ) )
317         return NULL;
318     // conveniently we already have it in this format
319     return m_papszMetadataList;
320 }
321 
322 // set the metdata as a CSLStringList
SetMetadata(char ** papszMetadata,const char * pszDomain)323 CPLErr KEARasterBand::SetMetadata(char **papszMetadata, const char *pszDomain)
324 {
325     // only deal with 'default' domain - no geolocation etc
326     if( ( pszDomain != NULL ) && ( *pszDomain != '\0' ) )
327         return CE_Failure;
328     int nIndex = 0;
329     char *pszName;
330     const char *pszValue;
331     try
332     {
333         // iterate through each one
334         while( papszMetadata[nIndex] != NULL )
335         {
336             pszName = NULL;
337             pszValue = CPLParseNameValue( papszMetadata[nIndex], &pszName );
338             if( pszValue == NULL )
339                 pszValue = "";
340             if( pszName != NULL )
341             {
342                 // it is LAYER_TYPE? if so handle seperately
343                 if( EQUAL( pszName, "LAYER_TYPE" ) )
344                 {
345                     if( EQUAL( pszValue, "athematic" ) )
346                     {
347                         this->m_pImageIO->setImageBandLayerType(this->nBand, kealib::kea_continuous );
348                     }
349                     else
350                     {
351                         this->m_pImageIO->setImageBandLayerType(this->nBand, kealib::kea_thematic );
352                     }
353                 }
354                 else
355                 {
356                     // write it into the image
357                     this->m_pImageIO->setImageBandMetaData(this->nBand, pszName, pszValue );
358                 }
359                 CPLFree(pszName);
360             }
361             nIndex++;
362         }
363     }
364     catch (kealib::KEAIOException &e)
365     {
366         return CE_Failure;
367     }
368     // destroy our list and duplicate the one passed in
369     // and use that as our list from now on
370     CSLDestroy(m_papszMetadataList);
371     m_papszMetadataList = CSLDuplicate(papszMetadata);
372     return CE_None;
373 }
374 
375 // get the no data value
GetNoDataValue(int * pbSuccess)376 double KEARasterBand::GetNoDataValue(int *pbSuccess)
377 {
378     try
379     {
380         double dVal;
381         this->m_pImageIO->getNoDataValue(this->nBand, &dVal, kealib::kea_64float);
382         if( pbSuccess != NULL )
383             *pbSuccess = 1;
384 
385         return dVal;
386     }
387     catch (kealib::KEAIOException &e)
388     {
389         if( pbSuccess != NULL )
390             *pbSuccess = 0;
391         return -1;
392     }
393 }
394 
395 // set the no data value
SetNoDataValue(double dfNoData)396 CPLErr KEARasterBand::SetNoDataValue(double dfNoData)
397 {
398     // need to check for out of range values
399     bool bSet = true;
400     GDALDataType dtype = this->GetRasterDataType();
401     switch( dtype )
402     {
403         case GDT_Byte:
404             bSet = (dfNoData >= 0) && (dfNoData <= UCHAR_MAX);
405             break;
406         case GDT_UInt16:
407             bSet = (dfNoData >= 0) && (dfNoData <= USHRT_MAX);
408             break;
409         case GDT_Int16:
410             bSet = (dfNoData >= SHRT_MIN) && (dfNoData <= SHRT_MAX);
411             break;
412         case GDT_UInt32:
413             bSet = (dfNoData >= 0) && (dfNoData <= UINT_MAX);
414             break;
415         case GDT_Int32:
416             bSet = (dfNoData >= INT_MIN) && (dfNoData <= INT_MAX);
417             break;
418         default:
419             // for other types we can't really tell if outside the range
420             break;
421     }
422 
423     try
424     {
425         if( bSet )
426         {
427             this->m_pImageIO->setNoDataValue(this->nBand, &dfNoData, kealib::kea_64float);
428         }
429         else
430         {
431             this->m_pImageIO->undefineNoDataValue(this->nBand);
432         }
433         return CE_None;
434     }
435     catch (kealib::KEAIOException &e)
436     {
437         return CE_Failure;
438     }
439 }
440 
GetDefaultRAT()441 GDALRasterAttributeTable *KEARasterBand::GetDefaultRAT()
442 {
443     if( this->m_pAttributeTable == NULL )
444     {
445         try
446         {
447             // we assume this is never NULL - creates a new one if none exists
448             kealib::KEAAttributeTable *pKEATable = this->m_pImageIO->getAttributeTable(kealib::kea_att_file, this->nBand);
449             this->m_pAttributeTable = new KEARasterAttributeTable(pKEATable);
450         }
451         catch(kealib::KEAException &e)
452         {
453             CPLError( CE_Failure, CPLE_AppDefined, "Failed to read attributes: %s", e.what() );
454         }
455     }
456     return this->m_pAttributeTable;
457 }
458 
SetDefaultRAT(const GDALRasterAttributeTable * poRAT)459 CPLErr KEARasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT)
460 {
461     if( poRAT == NULL )
462         return CE_Failure;
463 
464     try
465     {
466         KEARasterAttributeTable *pKEATable = (KEARasterAttributeTable*)this->GetDefaultRAT();
467 
468         int numRows = poRAT->GetRowCount();
469         pKEATable->SetRowCount(numRows);
470 
471         for( int nGDALColumnIndex = 0; nGDALColumnIndex < poRAT->GetColumnCount(); nGDALColumnIndex++ )
472         {
473             const char *pszColumnName = poRAT->GetNameOfCol(nGDALColumnIndex);
474             GDALRATFieldType eFieldType = poRAT->GetTypeOfCol(nGDALColumnIndex);
475 
476             // do we have it?
477             bool bExists = false;
478             int nKEAColumnIndex;
479             for( nKEAColumnIndex = 0; nKEAColumnIndex < pKEATable->GetColumnCount(); nKEAColumnIndex++ )
480             {
481                 if( EQUAL(pszColumnName, pKEATable->GetNameOfCol(nKEAColumnIndex) ))
482                 {
483                     bExists = true;
484                     break;
485                 }
486             }
487 
488             if( !bExists )
489             {
490                 if( pKEATable->CreateColumn(pszColumnName, eFieldType,
491                                             poRAT->GetUsageOfCol(nGDALColumnIndex) ) != CE_None )
492                 {
493                     CPLError( CE_Failure, CPLE_AppDefined, "Failed to create column");
494                     return CE_Failure;
495                 }
496                 nKEAColumnIndex = pKEATable->GetColumnCount() - 1;
497             }
498 
499             if( numRows == 0 )
500                 continue;
501 
502             // ok now copy data
503             if( eFieldType == GFT_Integer )
504             {
505                 int *panIntData = (int*)VSIMalloc2(numRows, sizeof(int));
506                 if( panIntData == NULL )
507                 {
508                     CPLError( CE_Failure, CPLE_OutOfMemory,
509                         "Memory Allocation failed in KEARasterAttributeTable::SetDefaultRAT");
510                     return CE_Failure;
511                 }
512 
513                 if( ((GDALRasterAttributeTable*)poRAT)->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows, panIntData ) == CE_None )
514                 {
515                     pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0, numRows, panIntData);
516                 }
517                 CPLFree(panIntData);
518             }
519             else if( eFieldType == GFT_Real )
520             {
521                 double *padfFloatData = (double*)VSIMalloc2(numRows, sizeof(double));
522                 if( padfFloatData == NULL )
523                 {
524                     CPLError( CE_Failure, CPLE_OutOfMemory,
525                         "Memory Allocation failed in KEARasterAttributeTable::SetDefaultRAT");
526                     return CE_Failure;
527                 }
528 
529                 if( ((GDALRasterAttributeTable*)poRAT)->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows, padfFloatData ) == CE_None )
530                 {
531                     pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0, numRows, padfFloatData);
532                 }
533                 CPLFree(padfFloatData);
534             }
535             else
536             {
537                 char **papszStringData = (char**)VSIMalloc2(numRows, sizeof(char*));
538                 if( papszStringData == NULL )
539                 {
540                     CPLError( CE_Failure, CPLE_OutOfMemory,
541                         "Memory Allocation failed in KEARasterAttributeTable::SetDefaultRAT");
542                     return CE_Failure;
543                 }
544 
545                 if( ((GDALRasterAttributeTable*)poRAT)->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows, papszStringData ) == CE_None )
546                 {
547                     pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0, numRows, papszStringData);
548                     for( int n = 0; n < numRows; n++ )
549                         CPLFree(papszStringData[n]);
550                 }
551                 CPLFree(papszStringData);
552 
553             }
554         }
555     }
556     catch(kealib::KEAException &e)
557     {
558         CPLError( CE_Failure, CPLE_AppDefined, "Failed to write attributes: %s", e.what() );
559         return CE_Failure;
560     }
561     return CE_None;
562 }
563 
GetColorTable()564 GDALColorTable *KEARasterBand::GetColorTable()
565 {
566     if( this->m_pColorTable == NULL )
567     {
568         try
569         {
570             GDALRasterAttributeTable *pKEATable = this->GetDefaultRAT();
571             int nRedIdx = -1;
572             int nGreenIdx = -1;
573             int nBlueIdx = -1;
574             int nAlphaIdx = -1;
575 
576             for( int nColIdx = 0; nColIdx < pKEATable->GetColumnCount(); nColIdx++ )
577             {
578                 if( pKEATable->GetTypeOfCol(nColIdx) == GFT_Integer )
579                 {
580                     GDALRATFieldUsage eFieldUsage = pKEATable->GetUsageOfCol(nColIdx);
581                     if( eFieldUsage == GFU_Red )
582                         nRedIdx = nColIdx;
583                     else if( eFieldUsage == GFU_Green )
584                         nGreenIdx = nColIdx;
585                     else if( eFieldUsage == GFU_Blue )
586                         nBlueIdx = nColIdx;
587                     else if( eFieldUsage == GFU_Alpha )
588                         nAlphaIdx = nColIdx;
589                 }
590             }
591 
592             if( ( nRedIdx != -1 ) && ( nGreenIdx != -1 ) && ( nBlueIdx != -1 ) && ( nAlphaIdx != -1 ) )
593             {
594                 // we need to create one - only do RGB palettes
595                 this->m_pColorTable = new GDALColorTable(GPI_RGB);
596 
597                 // OK go through each row and fill in the fields
598                 for( int nRowIndex = 0; nRowIndex < pKEATable->GetRowCount(); nRowIndex++ )
599                 {
600                     // maybe could be more efficient using ValuesIO
601                     GDALColorEntry colorEntry;
602                     colorEntry.c1 = pKEATable->GetValueAsInt(nRowIndex, nRedIdx);
603                     colorEntry.c2 = pKEATable->GetValueAsInt(nRowIndex, nGreenIdx);
604                     colorEntry.c3 = pKEATable->GetValueAsInt(nRowIndex, nBlueIdx);
605                     colorEntry.c4 = pKEATable->GetValueAsInt(nRowIndex, nAlphaIdx);
606                     this->m_pColorTable->SetColorEntry(nRowIndex, &colorEntry);
607                 }
608             }
609         }
610         catch(kealib::KEAException &e)
611         {
612             CPLError( CE_Failure, CPLE_AppDefined, "Failed to read color table: %s", e.what() );
613             delete this->m_pColorTable;
614             this->m_pColorTable = NULL;
615         }
616     }
617     return this->m_pColorTable;
618 }
619 
SetColorTable(GDALColorTable * poCT)620 CPLErr KEARasterBand::SetColorTable(GDALColorTable *poCT)
621 {
622     if( poCT == NULL )
623         return CE_Failure;
624 
625     try
626     {
627         GDALRasterAttributeTable *pKEATable = this->GetDefaultRAT();
628         int nRedIdx = -1;
629         int nGreenIdx = -1;
630         int nBlueIdx = -1;
631         int nAlphaIdx = -1;
632 
633         if( poCT->GetColorEntryCount() > pKEATable->GetRowCount() )
634         {
635             pKEATable->SetRowCount(poCT->GetColorEntryCount());
636         }
637 
638         for( int nColIdx = 0; nColIdx < pKEATable->GetColumnCount(); nColIdx++ )
639         {
640             if( pKEATable->GetTypeOfCol(nColIdx) == GFT_Integer )
641             {
642                 GDALRATFieldUsage eFieldUsage = pKEATable->GetUsageOfCol(nColIdx);
643                 if( eFieldUsage == GFU_Red )
644                     nRedIdx = nColIdx;
645                 else if( eFieldUsage == GFU_Green )
646                     nGreenIdx = nColIdx;
647                 else if( eFieldUsage == GFU_Blue )
648                     nBlueIdx = nColIdx;
649                 else if( eFieldUsage == GFU_Alpha )
650                     nAlphaIdx = nColIdx;
651             }
652         }
653 
654         // create if needed
655         if( nRedIdx == -1 )
656         {
657             if( pKEATable->CreateColumn("Red", GFT_Integer, GFU_Red ) != CE_None )
658             {
659                 CPLError( CE_Failure, CPLE_AppDefined, "Failed to create column" );
660                 return CE_Failure;
661             }
662             nRedIdx = pKEATable->GetColumnCount() - 1;
663         }
664         if( nGreenIdx == -1 )
665         {
666             if( pKEATable->CreateColumn("Green", GFT_Integer, GFU_Green ) != CE_None )
667             {
668                 CPLError( CE_Failure, CPLE_AppDefined, "Failed to create column" );
669                 return CE_Failure;
670             }
671             nGreenIdx = pKEATable->GetColumnCount() - 1;
672         }
673         if( nBlueIdx == -1 )
674         {
675             if( pKEATable->CreateColumn("Blue", GFT_Integer, GFU_Blue ) != CE_None )
676             {
677                 CPLError( CE_Failure, CPLE_AppDefined, "Failed to create column" );
678                 return CE_Failure;
679             }
680             nBlueIdx = pKEATable->GetColumnCount() - 1;
681         }
682         if( nAlphaIdx == -1 )
683         {
684             if( pKEATable->CreateColumn("Alpha", GFT_Integer, GFU_Alpha ) != CE_None )
685             {
686                 CPLError( CE_Failure, CPLE_AppDefined, "Failed to create column" );
687                 return CE_Failure;
688             }
689             nAlphaIdx = pKEATable->GetColumnCount() - 1;
690         }
691 
692         // OK go through each row and fill in the fields
693         for( int nRowIndex = 0; nRowIndex < poCT->GetColorEntryCount(); nRowIndex++ )
694         {
695             // maybe could be more efficient using ValuesIO
696             GDALColorEntry colorEntry;
697             poCT->GetColorEntryAsRGB(nRowIndex, &colorEntry);
698             pKEATable->SetValue(nRowIndex, nRedIdx, colorEntry.c1);
699             pKEATable->SetValue(nRowIndex, nGreenIdx, colorEntry.c2);
700             pKEATable->SetValue(nRowIndex, nBlueIdx, colorEntry.c3);
701             pKEATable->SetValue(nRowIndex, nAlphaIdx, colorEntry.c4);
702         }
703 
704         // out of date
705         delete this->m_pColorTable;
706         this->m_pColorTable = NULL;
707     }
708     catch(kealib::KEAException &e)
709     {
710         CPLError( CE_Failure, CPLE_AppDefined, "Failed to write color table: %s", e.what() );
711         return CE_Failure;
712     }
713     return CE_None;
714 }
715 
GetColorInterpretation()716 GDALColorInterp KEARasterBand::GetColorInterpretation()
717 {
718     kealib::KEABandClrInterp ekeainterp;
719     try
720     {
721         ekeainterp = this->m_pImageIO->getImageBandClrInterp(this->nBand);
722     }
723     catch(kealib::KEAException &e)
724     {
725         return GCI_GrayIndex;
726     }
727 
728     GDALColorInterp egdalinterp;
729     switch(ekeainterp)
730     {
731         case kealib::kea_generic:
732         case kealib::kea_greyindex:
733             egdalinterp = GCI_GrayIndex;
734             break;
735         case kealib::kea_paletteindex:
736             egdalinterp = GCI_PaletteIndex;
737             break;
738         case kealib::kea_redband:
739             egdalinterp = GCI_RedBand;
740             break;
741         case kealib::kea_greenband:
742             egdalinterp = GCI_GreenBand;
743             break;
744         case kealib::kea_blueband:
745             egdalinterp = GCI_BlueBand;
746             break;
747         case kealib::kea_alphaband:
748             egdalinterp = GCI_AlphaBand;
749             break;
750         case kealib::kea_hueband:
751             egdalinterp = GCI_HueBand;
752             break;
753         case kealib::kea_saturationband:
754             egdalinterp = GCI_SaturationBand;
755             break;
756         case kealib::kea_lightnessband:
757             egdalinterp = GCI_LightnessBand;
758             break;
759         case kealib::kea_cyanband:
760             egdalinterp = GCI_CyanBand;
761             break;
762         case kealib::kea_magentaband:
763             egdalinterp = GCI_MagentaBand;
764             break;
765         case kealib::kea_yellowband:
766             egdalinterp = GCI_YellowBand;
767             break;
768         case kealib::kea_blackband:
769             egdalinterp = GCI_BlackBand;
770             break;
771         case kealib::kea_ycbcr_yband:
772             egdalinterp = GCI_YCbCr_YBand;
773             break;
774         case kealib::kea_ycbcr_cbband:
775             egdalinterp = GCI_YCbCr_CbBand;
776             break;
777         case kealib::kea_ycbcr_crband:
778             egdalinterp = GCI_YCbCr_CrBand;
779             break;
780         default:
781             egdalinterp = GCI_GrayIndex;
782             break;
783     }
784 
785     return egdalinterp;
786 }
787 
SetColorInterpretation(GDALColorInterp egdalinterp)788 CPLErr KEARasterBand::SetColorInterpretation(GDALColorInterp egdalinterp)
789 {
790     kealib::KEABandClrInterp ekeainterp;
791     switch(egdalinterp)
792     {
793         case GCI_GrayIndex:
794             ekeainterp = kealib::kea_greyindex;
795             break;
796         case GCI_PaletteIndex:
797             ekeainterp = kealib::kea_paletteindex;
798             break;
799         case GCI_RedBand:
800             ekeainterp = kealib::kea_redband;
801             break;
802         case GCI_GreenBand:
803             ekeainterp = kealib::kea_greenband;
804             break;
805         case GCI_BlueBand:
806             ekeainterp = kealib::kea_blueband;
807             break;
808         case GCI_AlphaBand:
809             ekeainterp = kealib::kea_alphaband;
810             break;
811         case GCI_HueBand:
812             ekeainterp = kealib::kea_hueband;
813             break;
814         case GCI_SaturationBand:
815             ekeainterp = kealib::kea_saturationband;
816             break;
817         case GCI_LightnessBand:
818             ekeainterp = kealib::kea_lightnessband;
819             break;
820         case GCI_CyanBand:
821             ekeainterp = kealib::kea_cyanband;
822             break;
823         case GCI_MagentaBand:
824             ekeainterp = kealib::kea_magentaband;
825             break;
826         case GCI_YellowBand:
827             ekeainterp = kealib::kea_yellowband;
828             break;
829         case GCI_BlackBand:
830             ekeainterp = kealib::kea_blackband;
831             break;
832         case GCI_YCbCr_YBand:
833             ekeainterp = kealib::kea_ycbcr_yband;
834             break;
835         case GCI_YCbCr_CbBand:
836             ekeainterp = kealib::kea_ycbcr_cbband;
837             break;
838         case GCI_YCbCr_CrBand:
839             ekeainterp = kealib::kea_ycbcr_crband;
840             break;
841         default:
842             ekeainterp = kealib::kea_greyindex;
843             break;
844     }
845 
846     try
847     {
848         this->m_pImageIO->setImageBandClrInterp(this->nBand, ekeainterp);
849     }
850     catch(kealib::KEAException &e)
851     {
852         // do nothing? The docs say CE_Failure only if unsupporte by format
853     }
854     return CE_None;
855 }
856 
857 // clean up our overview objects
deleteOverviewObjects()858 void KEARasterBand::deleteOverviewObjects()
859 {
860     // deletes the objects - not the overviews themselves
861     int nCount;
862     for( nCount = 0; nCount < m_nOverviews; nCount++ )
863     {
864         delete m_panOverviewBands[nCount];
865     }
866     CPLFree(m_panOverviewBands);
867     m_panOverviewBands = NULL;
868     m_nOverviews = 0;
869 }
870 
871 // read in any overviews in the file into our array of objects
readExistingOverviews()872 void KEARasterBand::readExistingOverviews()
873 {
874     // delete any existing overview bands
875     this->deleteOverviewObjects();
876 
877     m_nOverviews = this->m_pImageIO->getNumOfOverviews(this->nBand);
878     m_panOverviewBands = (KEAOverview**)CPLMalloc(sizeof(KEAOverview*) * m_nOverviews);
879 
880     uint64_t nXSize, nYSize;
881     for( int nCount = 0; nCount < m_nOverviews; nCount++ )
882     {
883         this->m_pImageIO->getOverviewSize(this->nBand, nCount + 1, &nXSize, &nYSize);
884         m_panOverviewBands[nCount] = new KEAOverview((KEADataset*)this->poDS, this->nBand, GA_ReadOnly,
885                                         this->m_pImageIO, this->m_pnRefCount, nCount + 1, nXSize, nYSize);
886     }
887 }
888 
889 // number of overviews
GetOverviewCount()890 int KEARasterBand::GetOverviewCount()
891 {
892     return m_nOverviews;
893 }
894 
895 // get a given overview
GetOverview(int nOverview)896 GDALRasterBand* KEARasterBand::GetOverview(int nOverview)
897 {
898     if( nOverview < 0 || nOverview >= m_nOverviews )
899     {
900         return NULL;
901     }
902     else
903     {
904         return m_panOverviewBands[nOverview];
905     }
906 }
907 
CreateMaskBand(CPL_UNUSED int nFlags)908 CPLErr KEARasterBand::CreateMaskBand(CPL_UNUSED int nFlags)
909 {
910     if( m_bMaskBandOwned )
911         delete m_pMaskBand;
912     m_pMaskBand = NULL;
913     try
914     {
915         this->m_pImageIO->createMask(this->nBand);
916     }
917     catch(kealib::KEAException &e)
918     {
919         CPLError( CE_Failure, CPLE_AppDefined, "Failed to create mask band: %s", e.what());
920         return CE_Failure;
921     }
922     return CE_None;
923 }
924 
GetMaskBand()925 GDALRasterBand* KEARasterBand::GetMaskBand()
926 {
927     if( m_pMaskBand == NULL )
928     {
929         try
930         {
931             if( this->m_pImageIO->maskCreated(this->nBand) )
932             {
933                 m_pMaskBand = new KEAMaskBand(this, this->m_pImageIO, this->m_pnRefCount);
934                 m_bMaskBandOwned = true;
935             }
936             else
937             {
938                 // use the base class implementation - GDAL will delete
939                 //fprintf( stderr, "returning base GetMaskBand()\n" );
940                 m_pMaskBand = GDALPamRasterBand::GetMaskBand();
941             }
942         }
943         catch(kealib::KEAException &e)
944         {
945             // do nothing?
946         }
947     }
948     return m_pMaskBand;
949 }
950 
GetMaskFlags()951 int KEARasterBand::GetMaskFlags()
952 {
953     try
954     {
955         if( ! this->m_pImageIO->maskCreated(this->nBand) )
956         {
957             // need to return the base class one since we are using
958             // the base class implementation of GetMaskBand()
959             //fprintf( stderr, "returning base GetMaskFlags()\n" );
960             return GDALPamRasterBand::GetMaskFlags();
961         }
962     }
963     catch(kealib::KEAException &e)
964     {
965         // do nothing?
966     }
967 
968     // none of the other flags seem to make sense...
969     return 0;
970 }
971 
972