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