1 : /******************************************************************************
2 : * $Id: gdalpamrasterband.cpp 17579 2009-08-25 18:31:50Z rouault $
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 : #include "gdal_pam.h"
33 : #include "gdal_rat.h"
34 : #include "cpl_string.h"
35 :
36 : CPL_CVSID("$Id: gdalpamrasterband.cpp 17579 2009-08-25 18:31:50Z rouault $");
37 :
38 : /************************************************************************/
39 : /* GDALPamRasterBand() */
40 : /************************************************************************/
41 :
42 616827 : GDALPamRasterBand::GDALPamRasterBand()
43 :
44 : {
45 616827 : psPam = NULL;
46 616827 : SetMOFlags( GetMOFlags() | GMO_PAM_CLASS );
47 616827 : }
48 :
49 : /************************************************************************/
50 : /* ~GDALPamRasterBand() */
51 : /************************************************************************/
52 :
53 616824 : GDALPamRasterBand::~GDALPamRasterBand()
54 :
55 : {
56 616824 : PamClear();
57 616824 : }
58 :
59 : /************************************************************************/
60 : /* SerializeToXML() */
61 : /************************************************************************/
62 :
63 748 : CPLXMLNode *GDALPamRasterBand::SerializeToXML( const char *pszVRTPath )
64 :
65 : {
66 748 : if( psPam == NULL )
67 11 : return NULL;
68 :
69 : /* -------------------------------------------------------------------- */
70 : /* Setup root node and attributes. */
71 : /* -------------------------------------------------------------------- */
72 737 : CPLString oFmt;
73 :
74 : CPLXMLNode *psTree;
75 :
76 737 : psTree = CPLCreateXMLNode( NULL, CXT_Element, "PAMRasterBand" );
77 :
78 737 : if( GetBand() > 0 )
79 737 : CPLSetXMLValue( psTree, "#band", oFmt.Printf( "%d", GetBand() ) );
80 :
81 : /* -------------------------------------------------------------------- */
82 : /* Serialize information of interest. */
83 : /* -------------------------------------------------------------------- */
84 737 : if( strlen(GetDescription()) > 0 )
85 19 : CPLSetXMLValue( psTree, "Description", GetDescription() );
86 :
87 737 : if( psPam->bNoDataValueSet )
88 : {
89 : CPLSetXMLValue( psTree, "NoDataValue",
90 19 : oFmt.Printf( "%.14E", psPam->dfNoDataValue ) );
91 :
92 : /* hex encode real floating point values */
93 19 : if( psPam->dfNoDataValue != floor(psPam->dfNoDataValue)
94 : || psPam->dfNoDataValue != atof(oFmt) )
95 : {
96 : double dfNoDataLittleEndian;
97 :
98 1 : dfNoDataLittleEndian = psPam->dfNoDataValue;
99 : CPL_LSBPTR64( &dfNoDataLittleEndian );
100 :
101 : char *pszHexEncoding =
102 1 : CPLBinaryToHex( 8, (GByte *) &dfNoDataLittleEndian );
103 1 : CPLSetXMLValue( psTree, "NoDataValue.#le_hex_equiv",pszHexEncoding);
104 1 : CPLFree( pszHexEncoding );
105 : }
106 : }
107 :
108 737 : if( psPam->pszUnitType != NULL )
109 1 : CPLSetXMLValue( psTree, "UnitType", psPam->pszUnitType );
110 :
111 737 : if( psPam->dfOffset != 0.0 )
112 : CPLSetXMLValue( psTree, "Offset",
113 0 : oFmt.Printf( "%.16g", psPam->dfOffset ) );
114 :
115 737 : if( psPam->dfScale != 1.0 )
116 : CPLSetXMLValue( psTree, "Scale",
117 0 : oFmt.Printf( "%.16g", psPam->dfScale ) );
118 :
119 737 : if( psPam->eColorInterp != GCI_Undefined )
120 : CPLSetXMLValue( psTree, "ColorInterp",
121 283 : GDALGetColorInterpretationName( psPam->eColorInterp ));
122 :
123 : /* -------------------------------------------------------------------- */
124 : /* Category names. */
125 : /* -------------------------------------------------------------------- */
126 737 : if( psPam->papszCategoryNames != NULL )
127 : {
128 : CPLXMLNode *psCT_XML = CPLCreateXMLNode( psTree, CXT_Element,
129 0 : "CategoryNames" );
130 :
131 0 : for( int iEntry=0; psPam->papszCategoryNames[iEntry] != NULL; iEntry++)
132 : {
133 : CPLCreateXMLElementAndValue( psCT_XML, "Category",
134 0 : psPam->papszCategoryNames[iEntry] );
135 : }
136 : }
137 :
138 : /* -------------------------------------------------------------------- */
139 : /* Color Table. */
140 : /* -------------------------------------------------------------------- */
141 737 : if( psPam->poColorTable != NULL )
142 : {
143 : CPLXMLNode *psCT_XML = CPLCreateXMLNode( psTree, CXT_Element,
144 0 : "ColorTable" );
145 :
146 0 : for( int iEntry=0; iEntry < psPam->poColorTable->GetColorEntryCount();
147 : iEntry++ )
148 : {
149 : GDALColorEntry sEntry;
150 : CPLXMLNode *psEntry_XML = CPLCreateXMLNode( psCT_XML, CXT_Element,
151 0 : "Entry" );
152 :
153 0 : psPam->poColorTable->GetColorEntryAsRGB( iEntry, &sEntry );
154 :
155 0 : CPLSetXMLValue( psEntry_XML, "#c1", oFmt.Printf("%d",sEntry.c1) );
156 0 : CPLSetXMLValue( psEntry_XML, "#c2", oFmt.Printf("%d",sEntry.c2) );
157 0 : CPLSetXMLValue( psEntry_XML, "#c3", oFmt.Printf("%d",sEntry.c3) );
158 0 : CPLSetXMLValue( psEntry_XML, "#c4", oFmt.Printf("%d",sEntry.c4) );
159 : }
160 : }
161 :
162 : /* -------------------------------------------------------------------- */
163 : /* Min/max. */
164 : /* -------------------------------------------------------------------- */
165 737 : if( psPam->bHaveMinMax )
166 : {
167 : CPLSetXMLValue( psTree, "Minimum",
168 0 : oFmt.Printf( "%.16g", psPam->dfMin ) );
169 : CPLSetXMLValue( psTree, "Maximum",
170 0 : oFmt.Printf( "%.16g", psPam->dfMax ) );
171 : }
172 :
173 : /* -------------------------------------------------------------------- */
174 : /* Statistics */
175 : /* -------------------------------------------------------------------- */
176 737 : if( psPam->bHaveStats )
177 : {
178 : CPLSetXMLValue( psTree, "Mean",
179 0 : oFmt.Printf( "%.16g", psPam->dfMean ) );
180 : CPLSetXMLValue( psTree, "StandardDeviation",
181 0 : oFmt.Printf( "%.16g", psPam->dfStdDev ) );
182 : }
183 :
184 : /* -------------------------------------------------------------------- */
185 : /* Histograms. */
186 : /* -------------------------------------------------------------------- */
187 737 : if( psPam->psSavedHistograms != NULL )
188 4 : CPLAddXMLChild( psTree, CPLCloneXMLTree( psPam->psSavedHistograms ) );
189 :
190 : /* -------------------------------------------------------------------- */
191 : /* Raster Attribute Table */
192 : /* -------------------------------------------------------------------- */
193 737 : if( psPam->poDefaultRAT != NULL )
194 3 : CPLAddXMLChild( psTree, psPam->poDefaultRAT->Serialize() );
195 :
196 : /* -------------------------------------------------------------------- */
197 : /* Metadata. */
198 : /* -------------------------------------------------------------------- */
199 : CPLXMLNode *psMD;
200 :
201 737 : psMD = oMDMD.Serialize();
202 737 : if( psMD != NULL )
203 : {
204 234 : if( psMD->psChild == NULL )
205 45 : CPLDestroyXMLNode( psMD );
206 : else
207 189 : CPLAddXMLChild( psTree, psMD );
208 : }
209 :
210 : /* -------------------------------------------------------------------- */
211 : /* We don't want to return anything if we had no metadata to */
212 : /* attach. */
213 : /* -------------------------------------------------------------------- */
214 737 : if( psTree->psChild == NULL || psTree->psChild->psNext == NULL )
215 : {
216 280 : CPLDestroyXMLNode( psTree );
217 280 : psTree = NULL;
218 : }
219 :
220 737 : return psTree;
221 : }
222 :
223 : /************************************************************************/
224 : /* PamInitialize() */
225 : /************************************************************************/
226 :
227 482201 : void GDALPamRasterBand::PamInitialize()
228 :
229 : {
230 482201 : if( psPam )
231 3977 : return;
232 :
233 478224 : GDALPamDataset *poParentDS = (GDALPamDataset *) GetDataset();
234 :
235 478224 : if( poParentDS == NULL || !(poParentDS->GetMOFlags() & GMO_PAM_CLASS) )
236 0 : return;
237 :
238 478224 : poParentDS->PamInitialize();
239 478224 : if( poParentDS->psPam == NULL )
240 6 : return;
241 :
242 : // Often (always?) initializing our parent will have initialized us.
243 478218 : if( psPam != NULL )
244 294 : return;
245 :
246 : psPam = (GDALRasterBandPamInfo *)
247 477924 : CPLCalloc(sizeof(GDALRasterBandPamInfo),1);
248 :
249 477924 : psPam->dfScale = 1.0;
250 477924 : psPam->poParentDS = poParentDS;
251 477924 : psPam->dfNoDataValue = -1e10;
252 477924 : psPam->poDefaultRAT = NULL;
253 : }
254 :
255 : /************************************************************************/
256 : /* PamClear() */
257 : /************************************************************************/
258 :
259 616824 : void GDALPamRasterBand::PamClear()
260 :
261 : {
262 616824 : if( psPam )
263 : {
264 477921 : if( psPam->poColorTable )
265 0 : delete psPam->poColorTable;
266 477921 : psPam->poColorTable = NULL;
267 :
268 477921 : CPLFree( psPam->pszUnitType );
269 477921 : CSLDestroy( psPam->papszCategoryNames );
270 :
271 477921 : if( psPam->poDefaultRAT != NULL )
272 : {
273 8 : delete psPam->poDefaultRAT;
274 8 : psPam->poDefaultRAT = NULL;
275 : }
276 :
277 477921 : if (psPam->psSavedHistograms != NULL)
278 : {
279 6 : CPLDestroyXMLNode (psPam->psSavedHistograms );
280 6 : psPam->psSavedHistograms = NULL;
281 : }
282 :
283 477921 : CPLFree( psPam );
284 477921 : psPam = NULL;
285 : }
286 616824 : }
287 :
288 : /************************************************************************/
289 : /* XMLInit() */
290 : /************************************************************************/
291 :
292 300 : CPLErr GDALPamRasterBand::XMLInit( CPLXMLNode *psTree, const char *pszVRTPath )
293 :
294 : {
295 300 : PamInitialize();
296 :
297 : /* -------------------------------------------------------------------- */
298 : /* Apply any dataset level metadata. */
299 : /* -------------------------------------------------------------------- */
300 300 : oMDMD.XMLInit( psTree, TRUE );
301 :
302 : /* -------------------------------------------------------------------- */
303 : /* Collect various other items of metadata. */
304 : /* -------------------------------------------------------------------- */
305 300 : SetDescription( CPLGetXMLValue( psTree, "Description", "" ) );
306 :
307 300 : if( CPLGetXMLValue( psTree, "NoDataValue", NULL ) != NULL )
308 : {
309 : const char *pszLEHex =
310 25 : CPLGetXMLValue( psTree, "NoDataValue.le_hex_equiv", NULL );
311 25 : if( pszLEHex != NULL )
312 : {
313 : int nBytes;
314 1 : GByte *pabyBin = CPLHexToBinary( pszLEHex, &nBytes );
315 1 : if( nBytes == 8 )
316 : {
317 : CPL_LSBPTR64( pabyBin );
318 :
319 1 : GDALPamRasterBand::SetNoDataValue( *((double *) pabyBin) );
320 : }
321 : else
322 : {
323 : GDALPamRasterBand::SetNoDataValue(
324 0 : atof(CPLGetXMLValue( psTree, "NoDataValue", "0" )) );
325 : }
326 1 : CPLFree( pabyBin );
327 : }
328 : else
329 : {
330 : GDALPamRasterBand::SetNoDataValue(
331 24 : atof(CPLGetXMLValue( psTree, "NoDataValue", "0" )) );
332 : }
333 : }
334 :
335 : GDALPamRasterBand::SetOffset(
336 300 : atof(CPLGetXMLValue( psTree, "Offset", "0.0" )) );
337 : GDALPamRasterBand::SetScale(
338 300 : atof(CPLGetXMLValue( psTree, "Scale", "1.0" )) );
339 :
340 300 : GDALPamRasterBand::SetUnitType( CPLGetXMLValue( psTree, "UnitType", NULL));
341 :
342 300 : if( CPLGetXMLValue( psTree, "ColorInterp", NULL ) != NULL )
343 : {
344 194 : const char *pszInterp = CPLGetXMLValue( psTree, "ColorInterp", NULL );
345 : GDALPamRasterBand::SetColorInterpretation(
346 194 : GDALGetColorInterpretationByName(pszInterp));
347 : }
348 :
349 : /* -------------------------------------------------------------------- */
350 : /* Category names. */
351 : /* -------------------------------------------------------------------- */
352 300 : if( CPLGetXMLNode( psTree, "CategoryNames" ) != NULL )
353 : {
354 : CPLXMLNode *psEntry;
355 0 : char **papszCategoryNames = NULL;
356 :
357 0 : for( psEntry = CPLGetXMLNode( psTree, "CategoryNames" )->psChild;
358 : psEntry != NULL; psEntry = psEntry->psNext )
359 : {
360 : /* Don't skeep <Category> tag with empty content */
361 0 : if( psEntry->eType != CXT_Element
362 : || !EQUAL(psEntry->pszValue,"Category")
363 : || (psEntry->psChild != NULL && psEntry->psChild->eType != CXT_Text) )
364 0 : continue;
365 :
366 : papszCategoryNames = CSLAddString( papszCategoryNames,
367 0 : (psEntry->psChild) ? psEntry->psChild->pszValue : "" );
368 : }
369 :
370 0 : GDALPamRasterBand::SetCategoryNames( papszCategoryNames );
371 : }
372 :
373 : /* -------------------------------------------------------------------- */
374 : /* Collect a color table. */
375 : /* -------------------------------------------------------------------- */
376 300 : if( CPLGetXMLNode( psTree, "ColorTable" ) != NULL )
377 : {
378 : CPLXMLNode *psEntry;
379 0 : GDALColorTable oTable;
380 0 : int iEntry = 0;
381 :
382 0 : for( psEntry = CPLGetXMLNode( psTree, "ColorTable" )->psChild;
383 : psEntry != NULL; psEntry = psEntry->psNext )
384 : {
385 : GDALColorEntry sCEntry;
386 :
387 0 : sCEntry.c1 = (short) atoi(CPLGetXMLValue( psEntry, "c1", "0" ));
388 0 : sCEntry.c2 = (short) atoi(CPLGetXMLValue( psEntry, "c2", "0" ));
389 0 : sCEntry.c3 = (short) atoi(CPLGetXMLValue( psEntry, "c3", "0" ));
390 0 : sCEntry.c4 = (short) atoi(CPLGetXMLValue( psEntry, "c4", "255" ));
391 :
392 0 : oTable.SetColorEntry( iEntry++, &sCEntry );
393 : }
394 :
395 0 : GDALPamRasterBand::SetColorTable( &oTable );
396 : }
397 :
398 : /* -------------------------------------------------------------------- */
399 : /* Do we have a complete set of stats? */
400 : /* -------------------------------------------------------------------- */
401 300 : if( CPLGetXMLNode( psTree, "Minimum" ) != NULL
402 : && CPLGetXMLNode( psTree, "Maximum" ) != NULL )
403 : {
404 0 : psPam->bHaveMinMax = TRUE;
405 0 : psPam->dfMin = atof(CPLGetXMLValue(psTree, "Minimum","0"));
406 0 : psPam->dfMax = atof(CPLGetXMLValue(psTree, "Maximum","0"));
407 : }
408 :
409 300 : if( CPLGetXMLNode( psTree, "Mean" ) != NULL
410 : && CPLGetXMLNode( psTree, "StandardDeviation" ) != NULL )
411 : {
412 0 : psPam->bHaveStats = TRUE;
413 0 : psPam->dfMean = atof(CPLGetXMLValue(psTree, "Mean","0"));
414 0 : psPam->dfStdDev = atof(CPLGetXMLValue(psTree,"StandardDeviation","0"));
415 : }
416 :
417 : /* -------------------------------------------------------------------- */
418 : /* Histograms */
419 : /* -------------------------------------------------------------------- */
420 300 : CPLXMLNode *psHist = CPLGetXMLNode( psTree, "Histograms" );
421 300 : if( psHist != NULL )
422 : {
423 3 : CPLXMLNode *psNext = psHist->psNext;
424 3 : psHist->psNext = NULL;
425 :
426 3 : psPam->psSavedHistograms = CPLCloneXMLTree( psHist );
427 3 : psHist->psNext = psNext;
428 : }
429 :
430 : /* -------------------------------------------------------------------- */
431 : /* Raster Attribute Table */
432 : /* -------------------------------------------------------------------- */
433 300 : CPLXMLNode *psRAT = CPLGetXMLNode( psTree, "GDALRasterAttributeTable" );
434 300 : if( psRAT != NULL )
435 : {
436 4 : psPam->poDefaultRAT = new GDALRasterAttributeTable();
437 4 : psPam->poDefaultRAT->XMLInit( psRAT, "" );
438 : }
439 :
440 300 : return CE_None;
441 : }
442 :
443 : /************************************************************************/
444 : /* CloneInfo() */
445 : /************************************************************************/
446 :
447 545 : CPLErr GDALPamRasterBand::CloneInfo( GDALRasterBand *poSrcBand,
448 : int nCloneFlags )
449 :
450 : {
451 545 : int bOnlyIfMissing = nCloneFlags & GCIF_ONLY_IF_MISSING;
452 : int bSuccess;
453 545 : int nSavedMOFlags = GetMOFlags();
454 :
455 545 : PamInitialize();
456 :
457 : /* -------------------------------------------------------------------- */
458 : /* Supress NotImplemented error messages - mainly needed if PAM */
459 : /* disabled. */
460 : /* -------------------------------------------------------------------- */
461 545 : SetMOFlags( nSavedMOFlags | GMO_IGNORE_UNIMPLEMENTED );
462 :
463 : /* -------------------------------------------------------------------- */
464 : /* Metadata */
465 : /* -------------------------------------------------------------------- */
466 545 : if( nCloneFlags & GCIF_BAND_METADATA )
467 : {
468 545 : if( poSrcBand->GetMetadata() != NULL )
469 : {
470 198 : if( !bOnlyIfMissing
471 132 : || CSLCount(GetMetadata()) != CSLCount(poSrcBand->GetMetadata()) )
472 : {
473 40 : SetMetadata( poSrcBand->GetMetadata() );
474 : }
475 : }
476 : }
477 :
478 : /* -------------------------------------------------------------------- */
479 : /* NODATA */
480 : /* -------------------------------------------------------------------- */
481 545 : if( nCloneFlags & GCIF_NODATA )
482 : {
483 545 : double dfNoData = poSrcBand->GetNoDataValue( &bSuccess );
484 :
485 545 : if( bSuccess )
486 : {
487 128 : if( !bOnlyIfMissing
488 64 : || GetNoDataValue( &bSuccess ) != dfNoData
489 : || !bSuccess )
490 5 : GDALPamRasterBand::SetNoDataValue( dfNoData );
491 : }
492 : }
493 :
494 : /* -------------------------------------------------------------------- */
495 : /* Offset/scale */
496 : /* -------------------------------------------------------------------- */
497 545 : if( nCloneFlags & GCIF_SCALEOFFSET )
498 : {
499 545 : double dfOffset = poSrcBand->GetOffset( &bSuccess );
500 :
501 545 : if( bSuccess )
502 : {
503 110 : if( !bOnlyIfMissing || GetOffset() != dfOffset )
504 0 : GDALPamRasterBand::SetOffset( dfOffset );
505 : }
506 :
507 545 : double dfScale = poSrcBand->GetScale( &bSuccess );
508 :
509 545 : if( bSuccess )
510 : {
511 110 : if( !bOnlyIfMissing || GetScale() != dfScale )
512 0 : GDALPamRasterBand::SetScale( dfScale );
513 : }
514 : }
515 :
516 : /* -------------------------------------------------------------------- */
517 : /* Unittype. */
518 : /* -------------------------------------------------------------------- */
519 545 : if( nCloneFlags & GCIF_UNITTYPE )
520 : {
521 545 : if( strlen(poSrcBand->GetUnitType()) > 0 )
522 : {
523 30 : if( !bOnlyIfMissing
524 20 : || !EQUAL(GetUnitType(),poSrcBand->GetUnitType()) )
525 : {
526 2 : GDALPamRasterBand::SetUnitType( poSrcBand->GetUnitType() );
527 : }
528 : }
529 : }
530 :
531 : /* -------------------------------------------------------------------- */
532 : /* ColorInterp */
533 : /* -------------------------------------------------------------------- */
534 545 : if( nCloneFlags & GCIF_COLORINTERP )
535 : {
536 545 : if( poSrcBand->GetColorInterpretation() != GCI_Undefined )
537 : {
538 1458 : if( !bOnlyIfMissing
539 486 : || poSrcBand->GetColorInterpretation()
540 486 : != GetColorInterpretation() )
541 : GDALPamRasterBand::SetColorInterpretation(
542 205 : poSrcBand->GetColorInterpretation() );
543 : }
544 : }
545 :
546 : /* -------------------------------------------------------------------- */
547 : /* color table. */
548 : /* -------------------------------------------------------------------- */
549 545 : if( nCloneFlags && GCIF_COLORTABLE )
550 : {
551 545 : if( poSrcBand->GetColorTable() != NULL )
552 : {
553 8 : if( !bOnlyIfMissing || GetColorTable() == NULL )
554 : {
555 : GDALPamRasterBand::SetColorTable(
556 0 : poSrcBand->GetColorTable() );
557 : }
558 : }
559 : }
560 :
561 : /* -------------------------------------------------------------------- */
562 : /* Raster Attribute Table. */
563 : /* -------------------------------------------------------------------- */
564 545 : if( nCloneFlags && GCIF_RAT )
565 : {
566 545 : const GDALRasterAttributeTable *poRAT = poSrcBand->GetDefaultRAT();
567 :
568 545 : if( poRAT != NULL )
569 : {
570 2 : if( !bOnlyIfMissing || GetDefaultRAT() == NULL )
571 : {
572 2 : GDALPamRasterBand::SetDefaultRAT( poRAT );
573 : }
574 : }
575 : }
576 :
577 : /* -------------------------------------------------------------------- */
578 : /* Restore MO flags. */
579 : /* -------------------------------------------------------------------- */
580 545 : SetMOFlags( nSavedMOFlags );
581 :
582 545 : return CE_None;
583 : }
584 :
585 : /************************************************************************/
586 : /* SetMetadata() */
587 : /************************************************************************/
588 :
589 182 : CPLErr GDALPamRasterBand::SetMetadata( char **papszMetadata,
590 : const char *pszDomain )
591 :
592 : {
593 182 : PamInitialize();
594 :
595 182 : if( psPam )
596 182 : psPam->poParentDS->MarkPamDirty();
597 :
598 182 : return GDALRasterBand::SetMetadata( papszMetadata, pszDomain );
599 : }
600 :
601 : /************************************************************************/
602 : /* SetMetadataItem() */
603 : /************************************************************************/
604 :
605 1595 : CPLErr GDALPamRasterBand::SetMetadataItem( const char *pszName,
606 : const char *pszValue,
607 : const char *pszDomain )
608 :
609 : {
610 1595 : PamInitialize();
611 :
612 1595 : if( psPam )
613 1595 : psPam->poParentDS->MarkPamDirty();
614 :
615 1595 : return GDALRasterBand::SetMetadataItem( pszName, pszValue, pszDomain );
616 : }
617 :
618 : /************************************************************************/
619 : /* SetNoDataValue() */
620 : /************************************************************************/
621 :
622 57 : CPLErr GDALPamRasterBand::SetNoDataValue( double dfNewValue )
623 :
624 : {
625 57 : PamInitialize();
626 :
627 57 : if( psPam )
628 : {
629 57 : psPam->bNoDataValueSet = TRUE;
630 57 : psPam->dfNoDataValue = dfNewValue;
631 57 : psPam->poParentDS->MarkPamDirty();
632 57 : return CE_None;
633 : }
634 : else
635 0 : return GDALRasterBand::SetNoDataValue( dfNewValue );
636 : }
637 :
638 : /************************************************************************/
639 : /* GetNoDataValue() */
640 : /************************************************************************/
641 :
642 3445 : double GDALPamRasterBand::GetNoDataValue( int *pbSuccess )
643 :
644 : {
645 3445 : if( psPam != NULL )
646 : {
647 2901 : if( pbSuccess )
648 2871 : *pbSuccess = psPam->bNoDataValueSet;
649 :
650 2901 : return psPam->dfNoDataValue;
651 : }
652 : else
653 544 : return GDALRasterBand::GetNoDataValue( pbSuccess );
654 : }
655 :
656 : /************************************************************************/
657 : /* GetOffset() */
658 : /************************************************************************/
659 :
660 117 : double GDALPamRasterBand::GetOffset( int *pbSuccess )
661 :
662 : {
663 117 : if( psPam )
664 : {
665 92 : if( pbSuccess != NULL )
666 49 : *pbSuccess = TRUE;
667 :
668 92 : return psPam->dfOffset;
669 : }
670 : else
671 25 : return GDALRasterBand::GetOffset( pbSuccess );
672 : }
673 :
674 : /************************************************************************/
675 : /* SetOffset() */
676 : /************************************************************************/
677 :
678 309 : CPLErr GDALPamRasterBand::SetOffset( double dfNewOffset )
679 :
680 : {
681 309 : PamInitialize();
682 :
683 309 : if( psPam != NULL )
684 : {
685 309 : if( psPam->dfOffset != dfNewOffset )
686 : {
687 3 : psPam->dfOffset = dfNewOffset;
688 3 : psPam->poParentDS->MarkPamDirty();
689 : }
690 :
691 309 : return CE_None;
692 : }
693 : else
694 0 : return GDALRasterBand::SetOffset( dfNewOffset );
695 : }
696 :
697 : /************************************************************************/
698 : /* GetScale() */
699 : /************************************************************************/
700 :
701 117 : double GDALPamRasterBand::GetScale( int *pbSuccess )
702 :
703 : {
704 117 : if( psPam )
705 : {
706 92 : if( pbSuccess != NULL )
707 49 : *pbSuccess = TRUE;
708 :
709 92 : return psPam->dfScale;
710 : }
711 : else
712 25 : return GDALRasterBand::GetScale( pbSuccess );
713 : }
714 :
715 : /************************************************************************/
716 : /* SetScale() */
717 : /************************************************************************/
718 :
719 309 : CPLErr GDALPamRasterBand::SetScale( double dfNewScale )
720 :
721 : {
722 309 : PamInitialize();
723 :
724 309 : if( psPam != NULL )
725 : {
726 309 : if( dfNewScale != psPam->dfScale )
727 : {
728 3 : psPam->dfScale = dfNewScale;
729 3 : psPam->poParentDS->MarkPamDirty();
730 : }
731 309 : return CE_None;
732 : }
733 : else
734 0 : return GDALRasterBand::SetScale( dfNewScale );
735 : }
736 :
737 : /************************************************************************/
738 : /* GetUnitType() */
739 : /************************************************************************/
740 :
741 505 : const char *GDALPamRasterBand::GetUnitType()
742 :
743 : {
744 505 : if( psPam != NULL )
745 : {
746 495 : if( psPam->pszUnitType == NULL )
747 495 : return "";
748 : else
749 0 : return psPam->pszUnitType;
750 : }
751 : else
752 10 : return GDALRasterBand::GetUnitType();
753 : }
754 :
755 : /************************************************************************/
756 : /* SetUnitType() */
757 : /************************************************************************/
758 :
759 302 : CPLErr GDALPamRasterBand::SetUnitType( const char *pszNewValue )
760 :
761 : {
762 302 : PamInitialize();
763 :
764 302 : if( psPam )
765 : {
766 302 : CPLFree( psPam->pszUnitType );
767 :
768 302 : if( pszNewValue == NULL )
769 298 : psPam->pszUnitType = NULL;
770 : else
771 4 : psPam->pszUnitType = CPLStrdup(pszNewValue);
772 :
773 302 : return CE_None;
774 : }
775 : else
776 0 : return GDALRasterBand::SetUnitType( pszNewValue );
777 : }
778 :
779 : /************************************************************************/
780 : /* GetCategoryNames() */
781 : /************************************************************************/
782 :
783 374 : char **GDALPamRasterBand::GetCategoryNames()
784 :
785 : {
786 374 : if( psPam )
787 361 : return psPam->papszCategoryNames;
788 : else
789 13 : return GDALRasterBand::GetCategoryNames();
790 : }
791 :
792 : /************************************************************************/
793 : /* SetCategoryNames() */
794 : /************************************************************************/
795 :
796 19 : CPLErr GDALPamRasterBand::SetCategoryNames( char ** papszNewNames )
797 :
798 : {
799 19 : PamInitialize();
800 :
801 19 : if( psPam )
802 : {
803 19 : CSLDestroy( psPam->papszCategoryNames );
804 19 : psPam->papszCategoryNames = CSLDuplicate( papszNewNames );
805 19 : psPam->poParentDS->MarkPamDirty();
806 19 : return CE_None;
807 : }
808 : else
809 0 : return GDALRasterBand::SetCategoryNames( papszNewNames );
810 :
811 : }
812 :
813 :
814 : /************************************************************************/
815 : /* GetColorTable() */
816 : /************************************************************************/
817 :
818 52 : GDALColorTable *GDALPamRasterBand::GetColorTable()
819 :
820 : {
821 52 : if( psPam )
822 32 : return psPam->poColorTable;
823 : else
824 20 : return GDALRasterBand::GetColorTable();
825 : }
826 :
827 : /************************************************************************/
828 : /* SetColorTable() */
829 : /************************************************************************/
830 :
831 0 : CPLErr GDALPamRasterBand::SetColorTable( GDALColorTable *poTableIn )
832 :
833 : {
834 0 : PamInitialize();
835 :
836 0 : if( psPam )
837 : {
838 0 : if( psPam->poColorTable != NULL )
839 : {
840 0 : delete psPam->poColorTable;
841 0 : psPam->poColorTable = NULL;
842 : }
843 :
844 0 : if( poTableIn )
845 : {
846 0 : psPam->poColorTable = poTableIn->Clone();
847 0 : psPam->eColorInterp = GCI_PaletteIndex;
848 : }
849 :
850 0 : psPam->poParentDS->MarkPamDirty();
851 :
852 0 : return CE_None;
853 : }
854 : else
855 0 : return GDALRasterBand::SetColorTable( poTableIn );
856 :
857 : }
858 :
859 : /************************************************************************/
860 : /* SetColorInterpretation() */
861 : /************************************************************************/
862 :
863 480 : CPLErr GDALPamRasterBand::SetColorInterpretation( GDALColorInterp eInterpIn )
864 :
865 : {
866 480 : PamInitialize();
867 :
868 480 : if( psPam )
869 : {
870 477 : psPam->poParentDS->MarkPamDirty();
871 :
872 477 : psPam->eColorInterp = eInterpIn;
873 :
874 477 : return CE_None;
875 : }
876 : else
877 3 : return GDALRasterBand::SetColorInterpretation( eInterpIn );
878 : }
879 :
880 : /************************************************************************/
881 : /* GetColorInterpretation() */
882 : /************************************************************************/
883 :
884 143 : GDALColorInterp GDALPamRasterBand::GetColorInterpretation()
885 :
886 : {
887 143 : if( psPam )
888 122 : return psPam->eColorInterp;
889 : else
890 21 : return GDALRasterBand::GetColorInterpretation();
891 : }
892 :
893 : /************************************************************************/
894 : /* PamParseHistogram() */
895 : /************************************************************************/
896 :
897 : int
898 1 : PamParseHistogram( CPLXMLNode *psHistItem,
899 : double *pdfMin, double *pdfMax,
900 : int *pnBuckets, int **ppanHistogram,
901 : int *pbIncludeOutOfRange, int *pbApproxOK )
902 :
903 : {
904 1 : if( psHistItem == NULL )
905 0 : return FALSE;
906 :
907 1 : *pdfMin = atof(CPLGetXMLValue( psHistItem, "HistMin", "0"));
908 1 : *pdfMax = atof(CPLGetXMLValue( psHistItem, "HistMax", "1"));
909 1 : *pnBuckets = atoi(CPLGetXMLValue( psHistItem, "BucketCount","2"));
910 1 : if (*pnBuckets <= 0)
911 0 : return FALSE;
912 :
913 1 : if( ppanHistogram == NULL )
914 0 : return TRUE;
915 :
916 : // Fetch the histogram and use it.
917 : int iBucket;
918 : const char *pszHistCounts = CPLGetXMLValue( psHistItem,
919 1 : "HistCounts", "" );
920 :
921 1 : *ppanHistogram = (int *) VSICalloc(sizeof(int),*pnBuckets);
922 1 : if (*ppanHistogram == NULL)
923 : {
924 : CPLError(CE_Failure, CPLE_OutOfMemory,
925 0 : "Cannot allocate memory for %d buckets", *pnBuckets);
926 0 : return FALSE;
927 : }
928 :
929 257 : for( iBucket = 0; iBucket < *pnBuckets; iBucket++ )
930 : {
931 256 : (*ppanHistogram)[iBucket] = atoi(pszHistCounts);
932 :
933 : // skip to next number.
934 823 : while( *pszHistCounts != '\0' && *pszHistCounts != '|' )
935 311 : pszHistCounts++;
936 256 : if( *pszHistCounts == '|' )
937 255 : pszHistCounts++;
938 : }
939 :
940 1 : return TRUE;
941 : }
942 :
943 : /************************************************************************/
944 : /* PamFindMatchingHistogram() */
945 : /************************************************************************/
946 : CPLXMLNode *
947 5 : PamFindMatchingHistogram( CPLXMLNode *psSavedHistograms,
948 : double dfMin, double dfMax, int nBuckets,
949 : int bIncludeOutOfRange, int bApproxOK )
950 :
951 : {
952 5 : if( psSavedHistograms == NULL )
953 3 : return NULL;
954 :
955 : CPLXMLNode *psXMLHist;
956 4 : for( psXMLHist = psSavedHistograms->psChild;
957 : psXMLHist != NULL; psXMLHist = psXMLHist->psNext )
958 : {
959 2 : if( psXMLHist->eType != CXT_Element
960 : || !EQUAL(psXMLHist->pszValue,"HistItem") )
961 0 : continue;
962 :
963 : // should try and make min/max test a bit fuzzy.
964 :
965 2 : if( atof(CPLGetXMLValue( psXMLHist, "HistMin", "0")) != dfMin
966 : || atof(CPLGetXMLValue( psXMLHist, "HistMax", "0")) != dfMax
967 : || atoi(CPLGetXMLValue( psXMLHist,
968 : "BucketCount","0")) != nBuckets
969 : || !atoi(CPLGetXMLValue( psXMLHist,
970 : "IncludeOutOfRange","0")) != !bIncludeOutOfRange
971 : || (!bApproxOK && atoi(CPLGetXMLValue( psXMLHist,
972 : "Approximate","0"))) )
973 :
974 2 : continue;
975 :
976 0 : return psXMLHist;
977 : }
978 :
979 2 : return NULL;
980 : }
981 :
982 : /************************************************************************/
983 : /* PamHistogramToXMLTree() */
984 : /************************************************************************/
985 :
986 : CPLXMLNode *
987 5 : PamHistogramToXMLTree( double dfMin, double dfMax,
988 : int nBuckets, int * panHistogram,
989 : int bIncludeOutOfRange, int bApprox )
990 :
991 : {
992 5 : char *pszHistCounts = (char *) CPLMalloc(12 * nBuckets + 10);
993 : int iBucket, iHistOffset;
994 : CPLXMLNode *psXMLHist;
995 5 : CPLString oFmt;
996 :
997 5 : psXMLHist = CPLCreateXMLNode( NULL, CXT_Element, "HistItem" );
998 :
999 : CPLSetXMLValue( psXMLHist, "HistMin",
1000 5 : oFmt.Printf( "%.16g", dfMin ));
1001 : CPLSetXMLValue( psXMLHist, "HistMax",
1002 5 : oFmt.Printf( "%.16g", dfMax ));
1003 : CPLSetXMLValue( psXMLHist, "BucketCount",
1004 5 : oFmt.Printf( "%d", nBuckets ));
1005 : CPLSetXMLValue( psXMLHist, "IncludeOutOfRange",
1006 5 : oFmt.Printf( "%d", bIncludeOutOfRange ));
1007 : CPLSetXMLValue( psXMLHist, "Approximate",
1008 5 : oFmt.Printf( "%d", bApprox ));
1009 :
1010 5 : iHistOffset = 0;
1011 5 : pszHistCounts[0] = '\0';
1012 539 : for( iBucket = 0; iBucket < nBuckets; iBucket++ )
1013 : {
1014 534 : sprintf( pszHistCounts + iHistOffset, "%d", panHistogram[iBucket] );
1015 534 : if( iBucket < nBuckets-1 )
1016 529 : strcat( pszHistCounts + iHistOffset, "|" );
1017 534 : iHistOffset += strlen(pszHistCounts+iHistOffset);
1018 : }
1019 :
1020 5 : CPLSetXMLValue( psXMLHist, "HistCounts", pszHistCounts );
1021 5 : CPLFree( pszHistCounts );
1022 :
1023 5 : return psXMLHist;
1024 : }
1025 :
1026 : /************************************************************************/
1027 : /* GetHistogram() */
1028 : /************************************************************************/
1029 :
1030 4 : CPLErr GDALPamRasterBand::GetHistogram( double dfMin, double dfMax,
1031 : int nBuckets, int * panHistogram,
1032 : int bIncludeOutOfRange, int bApproxOK,
1033 : GDALProgressFunc pfnProgress,
1034 : void *pProgressData )
1035 :
1036 : {
1037 4 : PamInitialize();
1038 :
1039 4 : if( psPam == NULL )
1040 : return GDALRasterBand::GetHistogram( dfMin, dfMax,
1041 : nBuckets, panHistogram,
1042 : bIncludeOutOfRange, bApproxOK,
1043 0 : pfnProgress, pProgressData );
1044 :
1045 : /* -------------------------------------------------------------------- */
1046 : /* Check if we have a matching histogram. */
1047 : /* -------------------------------------------------------------------- */
1048 : CPLXMLNode *psHistItem;
1049 :
1050 : psHistItem = PamFindMatchingHistogram( psPam->psSavedHistograms,
1051 : dfMin, dfMax, nBuckets,
1052 4 : bIncludeOutOfRange, bApproxOK );
1053 4 : if( psHistItem != NULL )
1054 : {
1055 0 : int *panTempHist = NULL;
1056 :
1057 0 : if( PamParseHistogram( psHistItem, &dfMin, &dfMax, &nBuckets,
1058 : &panTempHist,
1059 : &bIncludeOutOfRange, &bApproxOK ) )
1060 : {
1061 0 : memcpy( panHistogram, panTempHist, sizeof(int) * nBuckets );
1062 0 : CPLFree( panTempHist );
1063 0 : return CE_None;
1064 : }
1065 : }
1066 :
1067 : /* -------------------------------------------------------------------- */
1068 : /* We don't have an existing histogram matching the request, so */
1069 : /* generate one manually. */
1070 : /* -------------------------------------------------------------------- */
1071 : CPLErr eErr;
1072 :
1073 : eErr = GDALRasterBand::GetHistogram( dfMin, dfMax,
1074 : nBuckets, panHistogram,
1075 : bIncludeOutOfRange, bApproxOK,
1076 4 : pfnProgress, pProgressData );
1077 :
1078 : /* -------------------------------------------------------------------- */
1079 : /* Save an XML description of this histogram. */
1080 : /* -------------------------------------------------------------------- */
1081 4 : if( eErr == CE_None )
1082 : {
1083 : CPLXMLNode *psXMLHist;
1084 :
1085 : psXMLHist = PamHistogramToXMLTree( dfMin, dfMax, nBuckets,
1086 : panHistogram,
1087 4 : bIncludeOutOfRange, bApproxOK );
1088 4 : if( psXMLHist != NULL )
1089 : {
1090 4 : psPam->poParentDS->MarkPamDirty();
1091 :
1092 4 : if( psPam->psSavedHistograms == NULL )
1093 : psPam->psSavedHistograms = CPLCreateXMLNode( NULL, CXT_Element,
1094 2 : "Histograms" );
1095 :
1096 4 : CPLAddXMLChild( psPam->psSavedHistograms, psXMLHist );
1097 : }
1098 : }
1099 :
1100 4 : return eErr;
1101 : }
1102 :
1103 : /************************************************************************/
1104 : /* SetDefaultHistogram() */
1105 : /************************************************************************/
1106 :
1107 1 : CPLErr GDALPamRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
1108 : int nBuckets, int *panHistogram)
1109 :
1110 : {
1111 : CPLXMLNode *psNode;
1112 :
1113 1 : PamInitialize();
1114 :
1115 1 : if( psPam == NULL )
1116 : return GDALRasterBand::SetDefaultHistogram( dfMin, dfMax,
1117 0 : nBuckets, panHistogram );
1118 :
1119 : /* -------------------------------------------------------------------- */
1120 : /* Do we have a matching histogram we should replace? */
1121 : /* -------------------------------------------------------------------- */
1122 : psNode = PamFindMatchingHistogram( psPam->psSavedHistograms,
1123 : dfMin, dfMax, nBuckets,
1124 1 : TRUE, TRUE );
1125 1 : if( psNode != NULL )
1126 : {
1127 : /* blow this one away */
1128 0 : CPLRemoveXMLChild( psPam->psSavedHistograms, psNode );
1129 0 : CPLDestroyXMLNode( psNode );
1130 : }
1131 :
1132 : /* -------------------------------------------------------------------- */
1133 : /* Translate into a histogram XML tree. */
1134 : /* -------------------------------------------------------------------- */
1135 : CPLXMLNode *psHistItem;
1136 :
1137 : psHistItem = PamHistogramToXMLTree( dfMin, dfMax, nBuckets,
1138 1 : panHistogram, TRUE, FALSE );
1139 :
1140 : /* -------------------------------------------------------------------- */
1141 : /* Insert our new default histogram at the front of the */
1142 : /* histogram list so that it will be the default histogram. */
1143 : /* -------------------------------------------------------------------- */
1144 1 : psPam->poParentDS->MarkPamDirty();
1145 :
1146 1 : if( psPam->psSavedHistograms == NULL )
1147 : psPam->psSavedHistograms = CPLCreateXMLNode( NULL, CXT_Element,
1148 1 : "Histograms" );
1149 :
1150 1 : psHistItem->psNext = psPam->psSavedHistograms->psChild;
1151 1 : psPam->psSavedHistograms->psChild = psHistItem;
1152 :
1153 1 : return CE_None;
1154 : }
1155 :
1156 : /************************************************************************/
1157 : /* GetDefaultHistogram() */
1158 : /************************************************************************/
1159 :
1160 : CPLErr
1161 4 : GDALPamRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax,
1162 : int *pnBuckets, int **ppanHistogram,
1163 : int bForce,
1164 : GDALProgressFunc pfnProgress,
1165 : void *pProgressData )
1166 :
1167 : {
1168 4 : if( psPam && psPam->psSavedHistograms != NULL )
1169 : {
1170 : CPLXMLNode *psXMLHist;
1171 :
1172 2 : for( psXMLHist = psPam->psSavedHistograms->psChild;
1173 : psXMLHist != NULL; psXMLHist = psXMLHist->psNext )
1174 : {
1175 : int bApprox, bIncludeOutOfRange;
1176 :
1177 1 : if( psXMLHist->eType != CXT_Element
1178 : || !EQUAL(psXMLHist->pszValue,"HistItem") )
1179 0 : continue;
1180 :
1181 1 : if( PamParseHistogram( psXMLHist, pdfMin, pdfMax, pnBuckets,
1182 : ppanHistogram, &bIncludeOutOfRange,
1183 : &bApprox ) )
1184 1 : return CE_None;
1185 : else
1186 0 : return CE_Failure;
1187 : }
1188 : }
1189 :
1190 : return GDALRasterBand::GetDefaultHistogram( pdfMin, pdfMax, pnBuckets,
1191 : ppanHistogram, bForce,
1192 3 : pfnProgress, pProgressData );
1193 : }
1194 :
1195 : /************************************************************************/
1196 : /* GetDefaultRAT() */
1197 : /************************************************************************/
1198 :
1199 468 : const GDALRasterAttributeTable *GDALPamRasterBand::GetDefaultRAT()
1200 :
1201 : {
1202 468 : PamInitialize();
1203 :
1204 468 : if( psPam == NULL )
1205 0 : return GDALRasterBand::GetDefaultRAT();
1206 :
1207 468 : return psPam->poDefaultRAT;
1208 : }
1209 :
1210 : /************************************************************************/
1211 : /* SetDefaultRAT() */
1212 : /************************************************************************/
1213 :
1214 4 : CPLErr GDALPamRasterBand::SetDefaultRAT( const GDALRasterAttributeTable *poRAT)
1215 :
1216 : {
1217 4 : PamInitialize();
1218 :
1219 4 : if( psPam == NULL )
1220 0 : return GDALRasterBand::SetDefaultRAT( poRAT );
1221 :
1222 4 : psPam->poParentDS->MarkPamDirty();
1223 :
1224 4 : if( psPam->poDefaultRAT != NULL )
1225 : {
1226 0 : delete psPam->poDefaultRAT;
1227 0 : psPam->poDefaultRAT = NULL;
1228 : }
1229 :
1230 4 : if( poRAT == NULL )
1231 0 : psPam->poDefaultRAT = NULL;
1232 : else
1233 4 : psPam->poDefaultRAT = poRAT->Clone();
1234 :
1235 4 : return CE_None;
1236 : }
1237 :
|