root/tags/gdal_1_3_2/gcore/gdalpamrasterband.cpp

Revision 9592, 42.3 kB (checked in by fwarmerdam, 3 years ago)

fixed a flaw in yesterdays fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /******************************************************************************
2  * $Id$
3  *
4  * Project:  GDAL Core
5  * Purpose:  Implementation of GDALPamRasterBand, a raster band base class
6  *           that knows how to persistently store auxilary metadata in an
7  *           external xml file.
8  * Author:   Frank Warmerdam, warmerdam@pobox.com
9  *
10  ******************************************************************************
11  * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a
14  * copy of this software and associated documentation files (the "Software"),
15  * to deal in the Software without restriction, including without limitation
16  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17  * and/or sell copies of the Software, and to permit persons to whom the
18  * Software is furnished to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included
21  * in all copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29  * DEALINGS IN THE SOFTWARE.
30  ******************************************************************************
31  *
32  * $Log$
33  * Revision 1.17  2006/04/13 19:03:26  fwarmerdam
34  * fixed a flaw in yesterdays fix
35  *
36  * Revision 1.16  2006/04/13 03:16:01  fwarmerdam
37  * keep track if an object is PAM enabled, bug 1135
38  *
39  * Revision 1.15  2006/02/08 06:03:40  fwarmerdam
40  * expose some PAM histo stuff for VRT, fixed InitFromXML() hist bug
41  *
42  * Revision 1.14  2005/10/13 01:19:58  fwarmerdam
43  * moved GDALMultiDomainMetadata into GDALMajorObject
44  *
45  * Revision 1.13  2005/09/24 19:02:15  fwarmerdam
46  * added RasterAttributeTable support
47  *
48  * Revision 1.12  2005/09/23 20:55:19  fwarmerdam
49  * avoid unimplemented errors if PAM disabled
50  *
51  * Revision 1.11  2005/09/15 18:45:16  fwarmerdam
52  * Fixed reentrancy issue with PamInitialize.
53  *
54  * Revision 1.10  2005/09/11 18:04:24  fwarmerdam
55  * clearup multidomain metadata
56  *
57  * Revision 1.9  2005/08/31 03:34:23  fwarmerdam
58  * use CPLString.Printf instead of CSPrintf()
59  *
60  * Revision 1.8  2005/06/08 14:04:58  fwarmerdam
61  * fixed last fix in handling of histograms
62  *
63  * Revision 1.7  2005/05/22 08:13:40  fwarmerdam
64  * added multidomain metadata support
65  *
66  * Revision 1.6  2005/05/17 18:30:51  fwarmerdam
67  * initialize nodatavalue to -1e10, fix copying
68  *
69  * Revision 1.5  2005/05/17 15:13:28  fwarmerdam
70  * ensure pam info initialize on any set operation
71  *
72  * Revision 1.4  2005/05/13 18:56:52  fwarmerdam
73  * fixed SetDefaultHistogram
74  *
75  * Revision 1.3  2005/05/13 18:18:46  fwarmerdam
76  * reworked histogram support, SetHistogram prototype
77  *
78  * Revision 1.2  2005/05/11 14:04:08  fwarmerdam
79  * added getdefaulthistogram
80  *
81  * Revision 1.1  2005/04/27 16:27:44  fwarmerdam
82  * New
83  *
84  */
85
86 #include "gdal_pam.h"
87 #include "gdal_rat.h"
88 #include "cpl_string.h"
89
90 CPL_CVSID("$Id$");
91
92 /************************************************************************/
93 /*                         GDALPamRasterBand()                          */
94 /************************************************************************/
95
96 GDALPamRasterBand::GDALPamRasterBand()
97
98 {
99     psPam = NULL;
100     SetMOFlags( GetMOFlags() | GMO_PAM_CLASS );
101 }
102
103 /************************************************************************/
104 /*                         ~GDALPamRasterBand()                         */
105 /************************************************************************/
106
107 GDALPamRasterBand::~GDALPamRasterBand()
108
109 {
110     PamClear();
111 }
112
113 /************************************************************************/
114 /*                           SerializeToXML()                           */
115 /************************************************************************/
116
117 CPLXMLNode *GDALPamRasterBand::SerializeToXML( const char *pszVRTPath )
118
119 {
120     if( psPam == NULL )
121         return NULL;
122
123 /* -------------------------------------------------------------------- */
124 /*      Setup root node and attributes.                                 */
125 /* -------------------------------------------------------------------- */
126     CPLString oFmt;
127
128     CPLXMLNode *psTree;
129
130     psTree = CPLCreateXMLNode( NULL, CXT_Element, "PAMRasterBand" );
131
132     if( GetBand() > 0 )
133         CPLSetXMLValue( psTree, "#band", oFmt.Printf( "%d", GetBand() ) );
134
135 /* -------------------------------------------------------------------- */
136 /*      Serialize information of interest.                              */
137 /* -------------------------------------------------------------------- */
138     if( strlen(GetDescription()) > 0 )
139         CPLSetXMLValue( psTree, "Description", GetDescription() );
140
141     if( psPam->bNoDataValueSet )
142         CPLSetXMLValue( psTree, "NoDataValue",
143                         oFmt.Printf( "%.14E", psPam->dfNoDataValue ) );
144
145     if( psPam->pszUnitType != NULL )
146         CPLSetXMLValue( psTree, "UnitType", psPam->pszUnitType );
147
148     if( psPam->dfOffset != 0.0 )
149         CPLSetXMLValue( psTree, "Offset",
150                         oFmt.Printf( "%.16g", psPam->dfOffset ) );
151
152     if( psPam->dfScale != 1.0 )
153         CPLSetXMLValue( psTree, "Scale",
154                         oFmt.Printf( "%.16g", psPam->dfScale ) );
155
156     if( psPam->eColorInterp != GCI_Undefined )
157         CPLSetXMLValue( psTree, "ColorInterp",
158                         GDALGetColorInterpretationName( psPam->eColorInterp ));
159
160 /* -------------------------------------------------------------------- */
161 /*      Category names.                                                 */
162 /* -------------------------------------------------------------------- */
163     if( psPam->papszCategoryNames != NULL )
164     {
165         CPLXMLNode *psCT_XML = CPLCreateXMLNode( psTree, CXT_Element,
166                                                  "CategoryNames" );
167
168         for( int iEntry=0; psPam->papszCategoryNames[iEntry] != NULL; iEntry++)
169         {
170             CPLCreateXMLElementAndValue( psCT_XML, "Category",
171                                          psPam->papszCategoryNames[iEntry] );
172         }
173     }
174
175 /* -------------------------------------------------------------------- */
176 /*      Color Table.                                                    */
177 /* -------------------------------------------------------------------- */
178     if( psPam->poColorTable != NULL )
179     {
180         CPLXMLNode *psCT_XML = CPLCreateXMLNode( psTree, CXT_Element,
181                                                  "ColorTable" );
182
183         for( int iEntry=0; iEntry < psPam->poColorTable->GetColorEntryCount();
184              iEntry++ )
185         {
186             GDALColorEntry sEntry;
187             CPLXMLNode *psEntry_XML = CPLCreateXMLNode( psCT_XML, CXT_Element,
188                                                         "Entry" );
189
190             psPam->poColorTable->GetColorEntryAsRGB( iEntry, &sEntry );
191            
192             CPLSetXMLValue( psEntry_XML, "#c1", oFmt.Printf("%d",sEntry.c1) );
193             CPLSetXMLValue( psEntry_XML, "#c2", oFmt.Printf("%d",sEntry.c2) );
194             CPLSetXMLValue( psEntry_XML, "#c3", oFmt.Printf("%d",sEntry.c3) );
195             CPLSetXMLValue( psEntry_XML, "#c4", oFmt.Printf("%d",sEntry.c4) );
196         }
197     }
198
199 /* -------------------------------------------------------------------- */
200 /*      Min/max.                                                        */
201 /* -------------------------------------------------------------------- */
202     if( psPam->bHaveMinMax )
203     {
204         CPLSetXMLValue( psTree, "Minimum",
205                         oFmt.Printf( "%.16g", psPam->dfMin ) );
206         CPLSetXMLValue( psTree, "Maximum",
207                         oFmt.Printf( "%.16g", psPam->dfMax ) );
208     }
209
210 /* -------------------------------------------------------------------- */
211 /*      Statistics                                                      */
212 /* -------------------------------------------------------------------- */
213     if( psPam->bHaveStats )
214     {
215         CPLSetXMLValue( psTree, "Mean",
216                         oFmt.Printf( "%.16g", psPam->dfMean ) );
217         CPLSetXMLValue( psTree, "StandardDeviation",
218                         oFmt.Printf( "%.16g", psPam->dfStdDev ) );
219     }
220
221 /* -------------------------------------------------------------------- */
222 /*      Histograms.                                                     */
223 /* -------------------------------------------------------------------- */
224     if( psPam->psSavedHistograms != NULL )
225         CPLAddXMLChild( psTree, CPLCloneXMLTree( psPam->psSavedHistograms ) );
226
227 /* -------------------------------------------------------------------- */
228 /*      Raster Attribute Table                                          */
229 /* -------------------------------------------------------------------- */
230     if( psPam->poDefaultRAT != NULL )
231         CPLAddXMLChild( psTree, psPam->poDefaultRAT->Serialize() );
232
233 /* -------------------------------------------------------------------- */
234 /*      Metadata.                                                       */
235 /* -------------------------------------------------------------------- */
236     CPLXMLNode *psMD;
237
238     psMD = oMDMD.Serialize();
239     if( psMD != NULL )
240         CPLAddXMLChild( psTree, psMD );
241
242 /* -------------------------------------------------------------------- */
243 /*      We don't want to return anything if we had no metadata to       */
244 /*      attach.                                                         */
245 /* -------------------------------------------------------------------- */
246     if( psTree->psChild == NULL || psTree->psChild->psNext == NULL )
247     {
248         CPLDestroyXMLNode( psTree );
249         psTree = NULL;
250     }
251
252     return psTree;
253 }
254
255 /************************************************************************/
256 /*                           PamInitialize()                            */
257 /************************************************************************/
258
259 void GDALPamRasterBand::PamInitialize()
260
261 {
262     if( psPam )
263         return;
264
265     GDALPamDataset *poParentDS = (GDALPamDataset *) GetDataset();
266
267     if( poParentDS == NULL || !(poParentDS->GetMOFlags() | GMO_PAM_CLASS) )
268         return;
269
270     poParentDS->PamInitialize();
271     if( poParentDS->psPam == NULL )
272         return;
273
274     // Often (always?) initializing our parent will have initialized us.
275     if( psPam != NULL )
276         return;
277
278     psPam = (GDALRasterBandPamInfo *)
279         CPLCalloc(sizeof(GDALRasterBandPamInfo),1);
280
281     psPam->dfScale = 1.0;
282     psPam->poParentDS = poParentDS;
283     psPam->dfNoDataValue = -1e10;
284     psPam->poDefaultRAT = NULL;
285 }
286
287 /************************************************************************/
288 /*                              PamClear()                              */
289 /************************************************************************/
290
291 void GDALPamRasterBand::PamClear()
292
293 {
294     if( psPam )
295     {
296         if( psPam->poColorTable )
297             delete psPam->poColorTable;
298         psPam->poColorTable = NULL;
299        
300         CPLFree( psPam->pszUnitType );
301         CSLDestroy( psPam->papszCategoryNames );
302
303         if( psPam->poDefaultRAT != NULL )
304         {
305             delete psPam->poDefaultRAT;
306             psPam->poDefaultRAT = NULL;
307         }
308
309         CPLFree( psPam );
310         psPam = NULL;
311     }
312 }
313
314 /************************************************************************/
315 /*                              XMLInit()                               */
316 /************************************************************************/
317
318 CPLErr GDALPamRasterBand::XMLInit( CPLXMLNode *psTree, const char *pszVRTPath )
319
320 {
321     PamInitialize();
322
323 /* -------------------------------------------------------------------- */
324 /*      Apply any dataset level metadata.                               */
325 /* -------------------------------------------------------------------- */
326     oMDMD.XMLInit( psTree, TRUE );
327
328 /* -------------------------------------------------------------------- */
329 /*      Collect various other items of metadata.                        */
330 /* -------------------------------------------------------------------- */
331     SetDescription( CPLGetXMLValue( psTree, "Description", "" ) );
332    
333     if( CPLGetXMLValue( psTree, "NoDataValue", NULL ) != NULL )
334     {
335         GDALPamRasterBand::SetNoDataValue(
336             atof(CPLGetXMLValue( psTree, "NoDataValue", "0" )) );
337     }
338
339     GDALPamRasterBand::SetOffset(
340         atof(CPLGetXMLValue( psTree, "Offset", "0.0" )) );
341     GDALPamRasterBand::SetScale(
342         atof(CPLGetXMLValue( psTree, "Scale", "1.0" )) );
343
344     GDALPamRasterBand::SetUnitType( CPLGetXMLValue( psTree, "UnitType", NULL));
345
346     if( CPLGetXMLValue( psTree, "ColorInterp", NULL ) != NULL )
347     {
348         const char *pszInterp = CPLGetXMLValue( psTree, "ColorInterp", NULL );
349         int        iInterp;
350        
351         for( iInterp = 0; iInterp < 13; iInterp++ )
352         {
353             const char *pszCandidate
354                 = GDALGetColorInterpretationName( (GDALColorInterp) iInterp );
355
356             if( pszCandidate != NULL && EQUAL(pszCandidate,pszInterp) )
357             {
358                 GDALPamRasterBand::SetColorInterpretation( (GDALColorInterp) iInterp );
359                 break;
360             }
361         }
362     }
363
364 /* -------------------------------------------------------------------- */
365 /*      Category names.                                                 */
366 /* -------------------------------------------------------------------- */
367     if( CPLGetXMLNode( psTree, "CategoryNames" ) != NULL )
368     {
369         CPLXMLNode *psEntry;
370         char **papszCategoryNames = NULL;
371
372         for( psEntry = CPLGetXMLNode( psTree, "CategoryNames" )->psChild;
373              psEntry != NULL; psEntry = psEntry->psNext )
374         {
375             if( psEntry->eType != CXT_Element
376                 || !EQUAL(psEntry->pszValue,"Category")
377                 || psEntry->psChild == NULL
378                 || psEntry->psChild->eType != CXT_Text )
379                 continue;
380            
381             papszCategoryNames = CSLAddString( papszCategoryNames,
382                                                psEntry->psChild->pszValue );
383         }
384        
385         GDALPamRasterBand::SetCategoryNames( papszCategoryNames );
386     }
387
388 /* -------------------------------------------------------------------- */
389 /*      Collect a color table.                                          */
390 /* -------------------------------------------------------------------- */
391     if( CPLGetXMLNode( psTree, "ColorTable" ) != NULL )
392     {
393         CPLXMLNode *psEntry;
394         GDALColorTable oTable;
395         int        iEntry = 0;
396
397         for( psEntry = CPLGetXMLNode( psTree, "ColorTable" )->psChild;
398              psEntry != NULL; psEntry = psEntry->psNext )
399         {
400             GDALColorEntry sCEntry;
401
402             sCEntry.c1 = (short) atoi(CPLGetXMLValue( psEntry, "c1", "0" ));
403             sCEntry.c2 = (short) atoi(CPLGetXMLValue( psEntry, "c2", "0" ));
404             sCEntry.c3 = (short) atoi(CPLGetXMLValue( psEntry, "c3", "0" ));
405             sCEntry.c4 = (short) atoi(CPLGetXMLValue( psEntry, "c4", "255" ));
406
407             oTable.SetColorEntry( iEntry++, &sCEntry );
408         }
409        
410         GDALPamRasterBand::SetColorTable( &oTable );
411     }
412
413 /* -------------------------------------------------------------------- */
414 /*      Do we have a complete set of stats?                             */
415 /* -------------------------------------------------------------------- */
416     if( CPLGetXMLNode( psTree, "Minimum" ) != NULL
417         && CPLGetXMLNode( psTree, "Maximum" ) != NULL )
418     {
419         psPam->bHaveMinMax = TRUE;
420         psPam->dfMin = atof(CPLGetXMLValue(psTree, "Minimum","0"));
421         psPam->dfMax = atof(CPLGetXMLValue(psTree, "Maximum","0"));
422     }
423
424     if( CPLGetXMLNode( psTree, "Mean" ) != NULL
425         && CPLGetXMLNode( psTree, "StandardDeviation" ) != NULL )
426     {
427         psPam->bHaveStats = TRUE;
428         psPam->dfMean = atof(CPLGetXMLValue(psTree, "Mean","0"));
429         psPam->dfStdDev = atof(CPLGetXMLValue(psTree,"StandardDeviation","0"));
430     }
431
432 /* -------------------------------------------------------------------- */
433 /*      Histograms                                                      */
434 /* -------------------------------------------------------------------- */
435     CPLXMLNode *psHist = CPLGetXMLNode( psTree, "Histograms" );
436     if( psHist != NULL )
437     {
438         CPLXMLNode *psNext = psHist->psNext;
439         psHist->psNext = NULL;
440
441         psPam->psSavedHistograms = CPLCloneXMLTree( psHist );
442         psHist->psNext = psNext;
443     }
444
445 /* -------------------------------------------------------------------- */
446 /*      Raster Attribute Table                                          */
447 /* -------------------------------------------------------------------- */
448     CPLXMLNode *psRAT = CPLGetXMLNode( psTree, "GDALRasterAttributeTable" );
449     if( psRAT != NULL )
450     {
451         psPam->poDefaultRAT = new GDALRasterAttributeTable();
452         psPam->poDefaultRAT->XMLInit( psRAT, "" );
453     }
454
455     return CE_None;
456 }
457
458 /************************************************************************/
459 /*                             CloneInfo()                              */
460 /************************************************************************/
461
462 CPLErr GDALPamRasterBand::CloneInfo( GDALRasterBand *poSrcBand,
463                                      int nCloneFlags )
464
465 {
466     int bOnlyIfMissing = nCloneFlags & GCIF_ONLY_IF_MISSING;
467     int bSuccess;
468     int nSavedMOFlags = GetMOFlags();
469
470     PamInitialize();
471
472 /* -------------------------------------------------------------------- */
473 /*      Supress NotImplemented error messages - mainly needed if PAM    */
474 /*      disabled.                                                       */
475 /* -------------------------------------------------------------------- */
476     SetMOFlags( nSavedMOFlags | GMO_IGNORE_UNIMPLEMENTED );
477
478 /* -------------------------------------------------------------------- */
479 /*      Metadata                                                        */
480 /* -------------------------------------------------------------------- */
481     if( nCloneFlags & GCIF_BAND_METADATA )
482     {
483         if( poSrcBand->GetMetadata() != NULL )
484         {
485             if( !bOnlyIfMissing
486              || CSLCount(GetMetadata()) != CSLCount(poSrcBand->GetMetadata()) )
487             {
488                 SetMetadata( poSrcBand->GetMetadata() );
489             }
490         }
491     }
492
493 /* -------------------------------------------------------------------- */
494 /*      NODATA                                                          */
495 /* -------------------------------------------------------------------- */
496     if( nCloneFlags & GCIF_NODATA )
497     {
498         double dfNoData = poSrcBand->GetNoDataValue( &bSuccess );
499        
500         if( bSuccess )
501         {
502             if( !bOnlyIfMissing
503                 || GetNoDataValue( &bSuccess ) != dfNoData
504                 || !bSuccess )
505                 GDALPamRasterBand::SetNoDataValue( dfNoData );
506         }
507     }
508
509 /* -------------------------------------------------------------------- */
510 /*      Offset/scale                                                    */
511 /* -------------------------------------------------------------------- */
512     if( nCloneFlags & GCIF_SCALEOFFSET )
513     {
514         double dfOffset = poSrcBand->GetOffset( &bSuccess );
515        
516         if( bSuccess )
517         {
518             if( !bOnlyIfMissing || GetOffset() != dfOffset )
519                 GDALPamRasterBand::SetOffset( dfOffset );
520         }
521
522         double dfScale = poSrcBand->GetScale( &bSuccess );
523        
524         if( bSuccess )
525         {
526             if( !bOnlyIfMissing || GetScale() != dfScale )
527                 GDALPamRasterBand::SetScale( dfScale );
528         }
529     }
530
531 /* -------------------------------------------------------------------- */
532 /*      Unittype.                                                       */
533 /* -------------------------------------------------------------------- */
534     if( nCloneFlags & GCIF_UNITTYPE )
535     {
536         if( strlen(poSrcBand->GetUnitType()) > 0 )
537         {
538             if( !bOnlyIfMissing
539                 || !EQUAL(GetUnitType(),poSrcBand->GetUnitType()) )
540             {
541                 GDALPamRasterBand::SetUnitType( poSrcBand->GetUnitType() );
542             }
543         }
544     }
545
546 /* -------------------------------------------------------------------- */
547 /*      ColorInterp                                                     */
548 /* -------------------------------------------------------------------- */
549     if( nCloneFlags & GCIF_COLORINTERP )
550     {
551         if( poSrcBand->GetColorInterpretation() != GCI_Undefined )
552         {
553             if( !bOnlyIfMissing
554                 || poSrcBand->GetColorInterpretation()
555                 != GetColorInterpretation() )
556                 GDALPamRasterBand::SetColorInterpretation(
557                     poSrcBand->GetColorInterpretation() );
558         }
559     }
560
561 /* -------------------------------------------------------------------- */
562 /*      color table.                                                    */
563 /* -------------------------------------------------------------------- */
564     if( nCloneFlags && GCIF_COLORTABLE )
565     {
566         if( poSrcBand->GetColorTable() != NULL )
567         {
568             if( !bOnlyIfMissing || GetColorTable() != NULL )
569             {
570                 GDALPamRasterBand::SetColorTable(
571                     poSrcBand->GetColorTable() );
572             }
573         }
574     }
575
576 /* -------------------------------------------------------------------- */
577 /*      Raster Attribute Table.                                         */
578 /* -------------------------------------------------------------------- */
579     if( nCloneFlags && GCIF_RAT )
580     {
581         const GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
582
583         if( poRAT != NULL )
584         {
585             if( !bOnlyIfMissing || GetDefaultRAT() == NULL )
586             {
587                 GDALPamRasterBand::SetDefaultRAT( poRAT );
588             }
589         }
590     }
591
592 /* -------------------------------------------------------------------- */
593 /*      Restore MO flags.                                               */
594 /* -------------------------------------------------------------------- */
595     SetMOFlags( nSavedMOFlags );
596
597     return CE_None;
598 }
599
600 /************************************************************************/
601 /*                            SetMetadata()                             */
602 /************************************************************************/
603
604 CPLErr GDALPamRasterBand::SetMetadata( char **papszMetadata,
605                                     const char *pszDomain )
606
607 {
608     PamInitialize();
609
610     if( psPam )
611         psPam->poParentDS->MarkPamDirty();
612
613     return GDALRasterBand::SetMetadata( papszMetadata, pszDomain );
614 }
615
616 /************************************************************************/
617 /*                          SetMetadataItem()                           */
618 /************************************************************************/
619
620 CPLErr GDALPamRasterBand::SetMetadataItem( const char *pszName,
621                                         const char *pszValue,
622                                         const char *pszDomain )
623
624 {
625     PamInitialize();
626
627     if( psPam )
628         psPam->poParentDS->MarkPamDirty();
629
630     return GDALRasterBand::SetMetadataItem( pszName, pszValue, pszDomain );
631 }
632
633 /************************************************************************/
634 /*                           SetNoDataValue()                           */
635 /************************************************************************/
636
637 CPLErr GDALPamRasterBand::SetNoDataValue( double dfNewValue )
638
639 {
640     PamInitialize();
641
642     if( psPam )
643     {
644         psPam->bNoDataValueSet = TRUE;
645         psPam->dfNoDataValue = dfNewValue;
646         psPam->poParentDS->MarkPamDirty();
647         return CE_None;
648     }
649     else
650         return GDALRasterBand::SetNoDataValue( dfNewValue );
651 }
652
653 /************************************************************************/
654 /*                           GetNoDataValue()                           */
655 /************************************************************************/
656
657 double GDALPamRasterBand::GetNoDataValue( int *pbSuccess )
658
659 {
660     if( psPam != NULL )
661     {
662         if( pbSuccess )
663             *pbSuccess = psPam->bNoDataValueSet;
664
665         return psPam->dfNoDataValue;
666     }
667     else
668         return GDALRasterBand::GetNoDataValue( pbSuccess );
669 }
670
671 /************************************************************************/
672 /*                             GetOffset()                              */
673 /************************************************************************/
674
675 double GDALPamRasterBand::GetOffset( int *pbSuccess )
676
677 {
678     if( psPam )
679     {
680         if( pbSuccess != NULL )
681             *pbSuccess = TRUE;
682        
683         return psPam->dfOffset;
684     }
685     else
686         return GDALRasterBand::GetOffset( pbSuccess );
687 }
688
689 /************************************************************************/
690 /*                             SetOffset()                              */
691 /************************************************************************/
692
693 CPLErr GDALPamRasterBand::SetOffset( double dfNewOffset )
694
695 {
696     PamInitialize();
697
698     if( psPam != NULL )
699     {
700         psPam->dfOffset = dfNewOffset;
701         psPam->poParentDS->MarkPamDirty();
702
703         return CE_None;
704     }
705     else
706         return GDALRasterBand::SetOffset( dfNewOffset );
707 }
708
709 /************************************************************************/
710 /*                              GetScale()                              */
711 /************************************************************************/
712
713 double GDALPamRasterBand::GetScale( int *pbSuccess )
714
715 {
716     if( psPam )
717     {
718         if( pbSuccess != NULL )
719             *pbSuccess = TRUE;
720        
721         return psPam->dfScale;
722     }
723     else
724         return GDALRasterBand::GetScale( pbSuccess );
725 }
726
727 /************************************************************************/
728 /*                              SetScale()                              */
729 /************************************************************************/
730
731 CPLErr GDALPamRasterBand::SetScale( double dfNewScale )
732
733 {
734     PamInitialize();
735
736     if( psPam != NULL )
737     {
738         psPam->dfScale = dfNewScale;
739         psPam->poParentDS->MarkPamDirty();
740         return CE_None;
741     }
742     else
743         return GDALRasterBand::SetScale( dfNewScale );
744 }
745
746 /************************************************************************/
747 /*                            GetUnitType()                             */
748 /************************************************************************/
749
750 const char *GDALPamRasterBand::GetUnitType()
751
752 {
753     if( psPam != NULL )
754     {
755         if( psPam->pszUnitType == NULL )
756             return "";
757         else
758             return psPam->pszUnitType;
759     }
760     else
761         return GDALRasterBand::GetUnitType();
762 }
763
764 /************************************************************************/
765 /*                            SetUnitType()                             */
766 /************************************************************************/
767
768 CPLErr GDALPamRasterBand::SetUnitType( const char *pszNewValue )
769
770 {
771     PamInitialize();
772
773     if( psPam )
774     {
775         CPLFree( psPam->pszUnitType );
776        
777         if( pszNewValue == NULL )
778             psPam->pszUnitType = NULL;
779         else
780             psPam->pszUnitType = CPLStrdup(pszNewValue);
781
782         return CE_None;
783     }
784     else
785         return GDALRasterBand::SetUnitType( pszNewValue );
786 }
787
788 /************************************************************************/
789 /*                          GetCategoryNames()                          */
790 /************************************************************************/
791
792 char **GDALPamRasterBand::GetCategoryNames()
793
794 {
795     if( psPam )
796         return psPam->papszCategoryNames;
797     else
798         return GDALRasterBand::GetCategoryNames();
799 }
800
801 /************************************************************************/
802 /*                          SetCategoryNames()                          */
803 /************************************************************************/
804
805 CPLErr GDALPamRasterBand::SetCategoryNames( char ** papszNewNames )
806
807 {
808     PamInitialize();
809
810     if( psPam )
811     {
812         CSLDestroy( psPam->papszCategoryNames );
813         psPam->papszCategoryNames = CSLDuplicate( papszNewNames );
814         psPam->poParentDS->MarkPamDirty();
815         return CE_None;
816     }
817     else
818         return GDALRasterBand::SetCategoryNames( papszNewNames );
819
820 }
821
822
823 /************************************************************************/
824 /*                           GetColorTable()                            */
825 /************************************************************************/
826
827 GDALColorTable *GDALPamRasterBand::GetColorTable()
828
829 {
830     if( psPam )
831         return psPam->poColorTable;
832     else
833         return GDALRasterBand::GetColorTable();
834 }
835
836 /************************************************************************/
837 /*                           SetColorTable()                            */
838 /************************************************************************/
839
840 CPLErr GDALPamRasterBand::SetColorTable( GDALColorTable *poTableIn )
841
842 {
843     PamInitialize();
844
845     if( psPam )
846     {
847         if( psPam->poColorTable != NULL )
848         {
849             delete psPam->poColorTable;
850             psPam->poColorTable = NULL;
851         }
852        
853         if( poTableIn )
854         {
855             psPam->poColorTable = poTableIn->Clone();
856             psPam->eColorInterp = GCI_PaletteIndex;
857         }
858
859         psPam->poParentDS->MarkPamDirty();
860
861         return CE_None;
862     }
863     else
864         return GDALRasterBand::SetColorTable( poTableIn );
865
866 }
867
868 /************************************************************************/
869 /*                       SetColorInterpretation()                       */
870 /************************************************************************/
871
872 CPLErr GDALPamRasterBand::SetColorInterpretation( GDALColorInterp eInterpIn )
873
874 {
875     PamInitialize();
876
877     if( psPam )
878     {
879         psPam->poParentDS->MarkPamDirty();
880        
881         psPam->eColorInterp = eInterpIn;
882
883         return CE_None;
884     }
885     else
886         return GDALRasterBand::SetColorInterpretation( eInterpIn );
887 }
888
889 /************************************************************************/
890 /*                       GetColorInterpretation()                       */
891 /************************************************************************/
892
893 GDALColorInterp GDALPamRasterBand::GetColorInterpretation()
894
895 {
896     if( psPam )
897         return psPam->eColorInterp;
898     else
899         return GDALRasterBand::GetColorInterpretation();
900 }
901
902 /************************************************************************/
903 /*                         PamParseHistogram()                          */
904 /************************************************************************/
905
906 int 
907 PamParseHistogram( CPLXMLNode *psHistItem,
908                    double *pdfMin, double *pdfMax,
909                    int *pnBuckets, int **ppanHistogram,
910                    int *pbIncludeOutOfRange, int *pbApproxOK )
911 </