1 : /******************************************************************************
2 : * $Id: pcidskdataset.cpp 17097 2009-05-21 19:59:35Z warmerdam $
3 : *
4 : * Project: PCIDSK Database File
5 : * Purpose: Read/write PCIDSK Database File used by the PCI software, using
6 : * the external PCIDSK library.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "pcidsk.h"
32 : #include "pcidsk_pct.h"
33 : #include "gdal_pam.h"
34 : #include "cpl_string.h"
35 : #include "ogr_spatialref.h"
36 :
37 : CPL_CVSID("$Id: pcidskdataset.cpp 17097 2009-05-21 19:59:35Z warmerdam $");
38 :
39 : using namespace PCIDSK;
40 :
41 : const PCIDSK::PCIDSKInterfaces *PCIDSK2GetInterfaces(void);
42 :
43 : /************************************************************************/
44 : /* PCIDSK2Dataset */
45 : /************************************************************************/
46 :
47 : class PCIDSK2Dataset : public GDALPamDataset
48 : {
49 : friend class PCIDSK2Band;
50 :
51 : CPLString osSRS;
52 : CPLString osLastMDValue;
53 : char **papszLastMDListValue;
54 :
55 : PCIDSKFile *poFile;
56 :
57 : static GDALDataType PCIDSKTypeToGDAL( eChanType eType );
58 :
59 : public:
60 : PCIDSK2Dataset();
61 : ~PCIDSK2Dataset();
62 :
63 : static int Identify( GDALOpenInfo * );
64 : static GDALDataset *Open( GDALOpenInfo * );
65 : static GDALDataset *Create( const char * pszFilename,
66 : int nXSize, int nYSize, int nBands,
67 : GDALDataType eType,
68 : char **papszParmList );
69 :
70 : CPLErr GetGeoTransform( double * padfTransform );
71 : CPLErr SetGeoTransform( double * );
72 : const char *GetProjectionRef();
73 : CPLErr SetProjection( const char * );
74 :
75 : CPLErr SetMetadata( char **, const char * );
76 : char **GetMetadata( const char* );
77 : CPLErr SetMetadataItem(const char*,const char*,const char*);
78 : const char *GetMetadataItem( const char*, const char*);
79 :
80 : virtual void FlushCache(void);
81 :
82 : virtual CPLErr IBuildOverviews( const char *, int, int *,
83 : int, int *, GDALProgressFunc, void * );
84 : };
85 :
86 : /************************************************************************/
87 : /* PCIDSK2Band */
88 : /************************************************************************/
89 :
90 : class PCIDSK2Band : public GDALPamRasterBand
91 : {
92 : friend class PCIDSK2Dataset;
93 :
94 : PCIDSKChannel *poChannel;
95 : PCIDSKFile *poFile;
96 :
97 : void RefreshOverviewList();
98 : std::vector<PCIDSK2Band*> apoOverviews;
99 :
100 : CPLString osLastMDValue;
101 : char **papszLastMDListValue;
102 :
103 : bool CheckForColorTable();
104 : GDALColorTable *poColorTable;
105 : bool bCheckedForColorTable;
106 : int nPCTSegNumber;
107 :
108 : void Initialize();
109 :
110 : public:
111 : PCIDSK2Band( PCIDSK2Dataset *, PCIDSKFile *, int );
112 : PCIDSK2Band( PCIDSKChannel * );
113 : ~PCIDSK2Band();
114 :
115 : virtual CPLErr IReadBlock( int, int, void * );
116 : virtual CPLErr IWriteBlock( int, int, void * );
117 :
118 : virtual int GetOverviewCount();
119 : virtual GDALRasterBand *GetOverview(int);
120 :
121 : virtual GDALColorInterp GetColorInterpretation();
122 : virtual GDALColorTable *GetColorTable();
123 : virtual CPLErr SetColorTable( GDALColorTable * );
124 :
125 : CPLErr SetMetadata( char **, const char * );
126 : char **GetMetadata( const char* );
127 : CPLErr SetMetadataItem(const char*,const char*,const char*);
128 : const char *GetMetadataItem( const char*, const char*);
129 :
130 : };
131 :
132 : /************************************************************************/
133 : /* ==================================================================== */
134 : /* PCIDSK2Band */
135 : /* ==================================================================== */
136 : /************************************************************************/
137 :
138 : /************************************************************************/
139 : /* PCIDSK2Band() */
140 : /* */
141 : /* This constructor is used for main file channels. */
142 : /************************************************************************/
143 :
144 : PCIDSK2Band::PCIDSK2Band( PCIDSK2Dataset *poDS,
145 : PCIDSKFile *poFile,
146 154 : int nBand )
147 :
148 : {
149 154 : Initialize();
150 :
151 154 : this->poDS = poDS;
152 154 : this->poFile = poFile;
153 154 : this->nBand = nBand;
154 :
155 154 : poChannel = poFile->GetChannel( nBand );
156 :
157 154 : nBlockXSize = (int) poChannel->GetBlockWidth();
158 154 : nBlockYSize = (int) poChannel->GetBlockHeight();
159 :
160 154 : eDataType = PCIDSK2Dataset::PCIDSKTypeToGDAL( poChannel->GetType() );
161 :
162 154 : SetDescription( poChannel->GetDescription().c_str() );
163 :
164 : /* -------------------------------------------------------------------- */
165 : /* Do we have overviews? */
166 : /* -------------------------------------------------------------------- */
167 154 : RefreshOverviewList();
168 154 : }
169 :
170 : /************************************************************************/
171 : /* PCIDSK2Band() */
172 : /* */
173 : /* This constructor is used for overviews and bitmap segments */
174 : /* as bands. */
175 : /************************************************************************/
176 :
177 3 : PCIDSK2Band::PCIDSK2Band( PCIDSKChannel *poChannel )
178 :
179 : {
180 3 : Initialize();
181 :
182 3 : this->poChannel = poChannel;
183 :
184 3 : nBand = 1;
185 :
186 3 : nBlockXSize = (int) poChannel->GetBlockWidth();
187 3 : nBlockYSize = (int) poChannel->GetBlockHeight();
188 :
189 3 : nRasterXSize = (int) poChannel->GetWidth();
190 3 : nRasterYSize = (int) poChannel->GetHeight();
191 :
192 3 : eDataType = PCIDSK2Dataset::PCIDSKTypeToGDAL( poChannel->GetType() );
193 :
194 3 : if( poChannel->GetType() == CHN_BIT )
195 : {
196 0 : SetMetadataItem( "NBITS", "1", "IMAGE_STRUCTURE" );
197 0 : SetDescription( poChannel->GetDescription().c_str() );
198 : }
199 3 : }
200 :
201 : /************************************************************************/
202 : /* Initialize() */
203 : /************************************************************************/
204 :
205 157 : void PCIDSK2Band::Initialize()
206 :
207 : {
208 157 : papszLastMDListValue = NULL;
209 :
210 157 : poChannel = NULL;
211 157 : poFile = NULL;
212 157 : poDS = NULL;
213 :
214 157 : bCheckedForColorTable = false;
215 157 : poColorTable = NULL;
216 157 : nPCTSegNumber = -1;
217 157 : }
218 :
219 : /************************************************************************/
220 : /* ~PCIDSK2Band() */
221 : /************************************************************************/
222 :
223 157 : PCIDSK2Band::~PCIDSK2Band()
224 :
225 : {
226 317 : while( apoOverviews.size() > 0 )
227 : {
228 3 : delete apoOverviews[apoOverviews.size()-1];
229 3 : apoOverviews.pop_back();
230 : }
231 157 : CSLDestroy( papszLastMDListValue );
232 :
233 157 : delete poColorTable;
234 157 : }
235 :
236 : /************************************************************************/
237 : /* CheckForColorTable() */
238 : /************************************************************************/
239 :
240 30 : bool PCIDSK2Band::CheckForColorTable()
241 :
242 : {
243 30 : if( bCheckedForColorTable || poFile == NULL )
244 7 : return true;
245 :
246 23 : bCheckedForColorTable = true;
247 :
248 : try
249 : {
250 23 : std::string osDefaultPCT = poChannel->GetMetadataValue("DEFAULT_PCT_REF");
251 23 : PCIDSKSegment *poPCTSeg = NULL;
252 :
253 : // If there is no metadata, assume a single PCT in a file with only
254 : // one raster band must be intended for it.
255 46 : if( osDefaultPCT.size() == 0
256 : && poDS != NULL
257 : && poDS->GetRasterCount() == 1 )
258 : {
259 13 : poPCTSeg = poFile->GetSegment( SEG_PCT, "" );
260 13 : if( poPCTSeg != NULL
261 : && poFile->GetSegment( SEG_PCT, "",
262 : poPCTSeg->GetSegmentNumber() ) != NULL )
263 0 : poPCTSeg = NULL;
264 : }
265 : // Parse default PCT ref assuming an in file reference.
266 10 : else if( osDefaultPCT.size() != 0
267 : && strstr(osDefaultPCT.c_str(),"PCT:") != NULL )
268 : {
269 : poPCTSeg = poFile->GetSegment(
270 1 : atoi(strstr(osDefaultPCT.c_str(),"PCT:") + 4) );
271 : }
272 :
273 23 : if( poPCTSeg != NULL )
274 : {
275 1 : PCIDSK_PCT *poPCT = dynamic_cast<PCIDSK_PCT*>( poPCTSeg );
276 1 : poColorTable = new GDALColorTable();
277 : int i;
278 : unsigned char abyPCT[768];
279 :
280 2 : nPCTSegNumber = poPCTSeg->GetSegmentNumber();
281 :
282 1 : poPCT->ReadPCT( abyPCT );
283 :
284 257 : for( i = 0; i < 256; i++ )
285 : {
286 : GDALColorEntry sEntry;
287 :
288 256 : sEntry.c1 = abyPCT[256 * 0 + i];
289 256 : sEntry.c2 = abyPCT[256 * 1 + i];
290 256 : sEntry.c3 = abyPCT[256 * 2 + i];
291 256 : sEntry.c4 = 255;
292 256 : poColorTable->SetColorEntry( i, &sEntry );
293 : }
294 23 : }
295 : }
296 0 : catch( PCIDSKException ex )
297 : {
298 : CPLError( CE_Failure, CPLE_AppDefined,
299 0 : "%s", ex.what() );
300 0 : return false;
301 : }
302 :
303 23 : return true;
304 : }
305 :
306 : /************************************************************************/
307 : /* GetColorTable() */
308 : /************************************************************************/
309 :
310 5 : GDALColorTable *PCIDSK2Band::GetColorTable()
311 :
312 : {
313 5 : CheckForColorTable();
314 :
315 5 : if( poColorTable )
316 2 : return poColorTable;
317 : else
318 3 : return GDALPamRasterBand::GetColorTable();
319 :
320 : }
321 :
322 : /************************************************************************/
323 : /* SetColorTable() */
324 : /************************************************************************/
325 :
326 2 : CPLErr PCIDSK2Band::SetColorTable( GDALColorTable *poCT )
327 :
328 : {
329 2 : if( !CheckForColorTable() )
330 0 : return CE_Failure;
331 :
332 : // no color tables on overviews.
333 2 : if( poFile == NULL )
334 0 : return CE_Failure;
335 :
336 : try
337 : {
338 : /* -------------------------------------------------------------------- */
339 : /* Are we trying to delete the color table? */
340 : /* -------------------------------------------------------------------- */
341 2 : if( poCT == NULL )
342 : {
343 1 : delete poColorTable;
344 1 : poColorTable = NULL;
345 :
346 1 : if( nPCTSegNumber != -1 )
347 1 : poFile->DeleteSegment( nPCTSegNumber );
348 1 : poChannel->SetMetadataValue( "DEFAULT_PCT_REF", "" );
349 1 : nPCTSegNumber = -1;
350 :
351 1 : return CE_None;
352 : }
353 :
354 : /* -------------------------------------------------------------------- */
355 : /* Do we need to create the segment? If so, also set the */
356 : /* default pct metadata. */
357 : /* -------------------------------------------------------------------- */
358 1 : if( nPCTSegNumber == -1 )
359 : {
360 : nPCTSegNumber = poFile->CreateSegment( "PCTTable",
361 : "Default Pseudo-Color Table",
362 1 : SEG_PCT, 0 );
363 :
364 1 : CPLString osRef;
365 :
366 1 : osRef.Printf( "gdb:/{PCT:%d}", nPCTSegNumber );
367 1 : poChannel->SetMetadataValue( "DEFAULT_PCT_REF", osRef );
368 : }
369 :
370 : /* -------------------------------------------------------------------- */
371 : /* Write out the PCT. */
372 : /* -------------------------------------------------------------------- */
373 : unsigned char abyPCT[768];
374 1 : int i, nColorCount = MIN(256,poCT->GetColorEntryCount());
375 :
376 1 : memset( abyPCT, 0, 768 );
377 :
378 4 : for( i = 0; i < nColorCount; i++ )
379 : {
380 : GDALColorEntry sEntry;
381 :
382 3 : poCT->GetColorEntryAsRGB( i, &sEntry );
383 3 : abyPCT[256 * 0 + i] = sEntry.c1;
384 3 : abyPCT[256 * 1 + i] = sEntry.c2;
385 3 : abyPCT[256 * 2 + i] = sEntry.c3;
386 : }
387 :
388 : PCIDSK_PCT *poPCT = dynamic_cast<PCIDSK_PCT*>(
389 1 : poFile->GetSegment( nPCTSegNumber ) );
390 :
391 1 : poPCT->WritePCT( abyPCT );
392 :
393 1 : delete poColorTable;
394 1 : poColorTable = poCT->Clone();
395 : }
396 :
397 : /* -------------------------------------------------------------------- */
398 : /* Trap exceptions. */
399 : /* -------------------------------------------------------------------- */
400 0 : catch( PCIDSKException ex )
401 : {
402 : CPLError( CE_Failure, CPLE_AppDefined,
403 0 : "%s", ex.what() );
404 0 : return CE_Failure;
405 : }
406 :
407 1 : return CE_None;
408 : }
409 :
410 : /************************************************************************/
411 : /* GetColorInterpretation() */
412 : /************************************************************************/
413 :
414 23 : GDALColorInterp PCIDSK2Band::GetColorInterpretation()
415 :
416 : {
417 23 : CheckForColorTable();
418 :
419 23 : if( poColorTable != NULL )
420 1 : return GCI_PaletteIndex;
421 : else
422 22 : return GDALPamRasterBand::GetColorInterpretation();
423 : }
424 :
425 : /************************************************************************/
426 : /* RefreshOverviewList() */
427 : /************************************************************************/
428 :
429 154 : void PCIDSK2Band::RefreshOverviewList()
430 :
431 : {
432 : /* -------------------------------------------------------------------- */
433 : /* Clear existing overviews. */
434 : /* -------------------------------------------------------------------- */
435 308 : while( apoOverviews.size() > 0 )
436 : {
437 0 : delete apoOverviews[apoOverviews.size()-1];
438 0 : apoOverviews.pop_back();
439 : }
440 :
441 : /* -------------------------------------------------------------------- */
442 : /* Fetch overviews. */
443 : /* -------------------------------------------------------------------- */
444 314 : for( int iOver = 0; iOver < poChannel->GetOverviewCount(); iOver++ )
445 : {
446 : apoOverviews.push_back(
447 3 : new PCIDSK2Band( poChannel->GetOverview(iOver) ) );
448 : }
449 154 : }
450 :
451 : /************************************************************************/
452 : /* IReadBlock() */
453 : /************************************************************************/
454 :
455 82 : CPLErr PCIDSK2Band::IReadBlock( int iBlockX, int iBlockY, void *pData )
456 :
457 : {
458 : try
459 : {
460 : poChannel->ReadBlock( iBlockX + iBlockY * nBlocksPerRow,
461 82 : pData );
462 :
463 : // Do we need to upsample 1bit to 8bit?
464 82 : if( poChannel->GetType() == CHN_BIT )
465 : {
466 0 : GByte *pabyData = (GByte *) pData;
467 :
468 0 : for( int ii = nBlockXSize * nBlockYSize - 1; ii >= 0; ii-- )
469 : {
470 0 : if( (pabyData[ii>>3] & (0x80 >> (ii & 0x7))) )
471 0 : pabyData[ii] = 1;
472 : else
473 0 : pabyData[ii] = 0;
474 : }
475 : }
476 :
477 82 : return CE_None;
478 : }
479 0 : catch( PCIDSKException ex )
480 : {
481 : CPLError( CE_Failure, CPLE_AppDefined,
482 0 : "%s", ex.what() );
483 0 : return CE_Failure;
484 : }
485 : }
486 :
487 : /************************************************************************/
488 : /* IWriteBlock() */
489 : /************************************************************************/
490 :
491 317 : CPLErr PCIDSK2Band::IWriteBlock( int iBlockX, int iBlockY, void *pData )
492 :
493 : {
494 : try
495 : {
496 : poChannel->WriteBlock( iBlockX + iBlockY * nBlocksPerRow,
497 317 : pData );
498 317 : return CE_None;
499 : }
500 0 : catch( PCIDSKException ex )
501 : {
502 : CPLError( CE_Failure, CPLE_AppDefined,
503 0 : "%s", ex.what() );
504 0 : return CE_Failure;
505 : }
506 : }
507 :
508 : /************************************************************************/
509 : /* GetOverviewCount() */
510 : /************************************************************************/
511 :
512 1 : int PCIDSK2Band::GetOverviewCount()
513 :
514 : {
515 1 : if( apoOverviews.size() > 0 )
516 1 : return (int) apoOverviews.size();
517 : else
518 0 : return GDALPamRasterBand::GetOverviewCount();
519 : }
520 :
521 : /************************************************************************/
522 : /* GetOverview() */
523 : /************************************************************************/
524 :
525 1 : GDALRasterBand *PCIDSK2Band::GetOverview(int iOverview)
526 :
527 : {
528 1 : if( iOverview < 0 || iOverview >= (int) apoOverviews.size() )
529 0 : return GDALPamRasterBand::GetOverview( iOverview );
530 : else
531 1 : return apoOverviews[iOverview];
532 : }
533 :
534 : /************************************************************************/
535 : /* SetMetadata() */
536 : /************************************************************************/
537 :
538 : CPLErr PCIDSK2Band::SetMetadata( char **papszMD,
539 1 : const char *pszDomain )
540 :
541 : {
542 : /* -------------------------------------------------------------------- */
543 : /* PCIDSK only supports metadata in the default domain. */
544 : /* -------------------------------------------------------------------- */
545 1 : if( pszDomain != NULL && strlen(pszDomain) > 0 )
546 0 : return GDALPamRasterBand::SetMetadata( papszMD, pszDomain );
547 :
548 : /* -------------------------------------------------------------------- */
549 : /* Set each item individually. */
550 : /* -------------------------------------------------------------------- */
551 1 : CSLDestroy( papszLastMDListValue );
552 1 : papszLastMDListValue = NULL;
553 :
554 : try
555 : {
556 : int iItem;
557 :
558 3 : for( iItem = 0; papszMD && papszMD[iItem]; iItem++ )
559 : {
560 : const char *pszItemValue;
561 2 : char *pszItemName = NULL;
562 :
563 2 : pszItemValue = CPLParseNameValue( papszMD[iItem], &pszItemName);
564 2 : poChannel->SetMetadataValue( pszItemName, pszItemValue );
565 2 : CPLFree( pszItemName );
566 : }
567 1 : return CE_None;
568 : }
569 0 : catch( PCIDSKException ex )
570 : {
571 : CPLError( CE_Failure, CPLE_AppDefined,
572 0 : "%s", ex.what() );
573 0 : return CE_Failure;
574 : }
575 : }
576 :
577 : /************************************************************************/
578 : /* SetMetadataItem() */
579 : /************************************************************************/
580 :
581 : CPLErr PCIDSK2Band::SetMetadataItem( const char *pszName,
582 : const char *pszValue,
583 2 : const char *pszDomain )
584 :
585 : {
586 : /* -------------------------------------------------------------------- */
587 : /* PCIDSK only supports metadata in the default domain. */
588 : /* -------------------------------------------------------------------- */
589 2 : if( pszDomain != NULL && strlen(pszDomain) > 0 )
590 1 : return GDALPamRasterBand::SetMetadataItem(pszName,pszValue,pszDomain);
591 :
592 : /* -------------------------------------------------------------------- */
593 : /* Set on the file. */
594 : /* -------------------------------------------------------------------- */
595 1 : CSLDestroy( papszLastMDListValue );
596 1 : papszLastMDListValue = NULL;
597 :
598 : try
599 : {
600 1 : poChannel->SetMetadataValue( pszName, pszValue );
601 1 : return CE_None;
602 : }
603 0 : catch( PCIDSKException ex )
604 : {
605 : CPLError( CE_Failure, CPLE_AppDefined,
606 0 : "%s", ex.what() );
607 0 : return CE_Failure;
608 : }
609 : }
610 :
611 : /************************************************************************/
612 : /* GetMetadataItem() */
613 : /************************************************************************/
614 :
615 : const char *PCIDSK2Band::GetMetadataItem( const char *pszName,
616 11 : const char *pszDomain )
617 :
618 : {
619 : /* -------------------------------------------------------------------- */
620 : /* PCIDSK only supports metadata in the default domain. */
621 : /* -------------------------------------------------------------------- */
622 11 : if( pszDomain != NULL && strlen(pszDomain) > 0 )
623 11 : return GDALPamRasterBand::GetMetadataItem( pszName, pszDomain );
624 :
625 : /* -------------------------------------------------------------------- */
626 : /* Try and fetch. */
627 : /* -------------------------------------------------------------------- */
628 : try
629 : {
630 0 : osLastMDValue = poChannel->GetMetadataValue( pszName );
631 :
632 0 : if( osLastMDValue == "" )
633 0 : return NULL;
634 : else
635 0 : return osLastMDValue.c_str();
636 : }
637 0 : catch( PCIDSKException ex )
638 : {
639 : CPLError( CE_Failure, CPLE_AppDefined,
640 0 : "%s", ex.what() );
641 0 : return NULL;
642 : }
643 : }
644 :
645 : /************************************************************************/
646 : /* GetMetadata() */
647 : /************************************************************************/
648 :
649 3 : char **PCIDSK2Band::GetMetadata( const char *pszDomain )
650 :
651 : {
652 : /* -------------------------------------------------------------------- */
653 : /* PCIDSK only supports metadata in the default domain. */
654 : /* -------------------------------------------------------------------- */
655 3 : if( pszDomain != NULL && strlen(pszDomain) > 0 )
656 1 : return GDALPamRasterBand::GetMetadata( pszDomain );
657 :
658 : /* -------------------------------------------------------------------- */
659 : /* If we have a cached result, just use that. */
660 : /* -------------------------------------------------------------------- */
661 2 : if( papszLastMDListValue != NULL )
662 0 : return papszLastMDListValue;
663 :
664 : /* -------------------------------------------------------------------- */
665 : /* Fetch and build the list. */
666 : /* -------------------------------------------------------------------- */
667 : try
668 : {
669 2 : std::vector<std::string> aosKeys = poChannel->GetMetadataKeys();
670 : unsigned int i;
671 :
672 6 : for( i = 0; i < aosKeys.size(); i++ )
673 : {
674 4 : if( aosKeys[i].c_str()[0] == '_' )
675 1 : continue;
676 :
677 : papszLastMDListValue =
678 : CSLSetNameValue( papszLastMDListValue,
679 : aosKeys[i].c_str(),
680 3 : poChannel->GetMetadataValue(aosKeys[i]).c_str() );
681 2 : }
682 : }
683 0 : catch( PCIDSKException ex )
684 : {
685 : CPLError( CE_Failure, CPLE_AppDefined,
686 0 : "%s", ex.what() );
687 0 : return NULL;
688 : }
689 :
690 2 : return papszLastMDListValue;
691 : }
692 :
693 : /************************************************************************/
694 : /* ==================================================================== */
695 : /* PCIDSK2Dataset */
696 : /* ==================================================================== */
697 : /************************************************************************/
698 :
699 : /************************************************************************/
700 : /* PCIDSK2Dataset() */
701 : /************************************************************************/
702 :
703 80 : PCIDSK2Dataset::PCIDSK2Dataset()
704 : {
705 80 : poFile = NULL;
706 80 : papszLastMDListValue = NULL;
707 80 : }
708 :
709 : /************************************************************************/
710 : /* ~PCIDSK2Dataset() */
711 : /************************************************************************/
712 :
713 80 : PCIDSK2Dataset::~PCIDSK2Dataset()
714 : {
715 80 : FlushCache();
716 :
717 : try {
718 80 : delete poFile;
719 80 : poFile = NULL;
720 : }
721 :
722 : /* -------------------------------------------------------------------- */
723 : /* Trap exceptions. */
724 : /* -------------------------------------------------------------------- */
725 0 : catch( PCIDSKException ex )
726 : {
727 : CPLError( CE_Failure, CPLE_AppDefined,
728 0 : "%s", ex.what() );
729 : }
730 0 : catch( ... )
731 : {
732 : CPLError( CE_Failure, CPLE_AppDefined,
733 0 : "PCIDSK SDK Failure in Close(), unexpected exception." );
734 : }
735 :
736 80 : CSLDestroy( papszLastMDListValue );
737 80 : }
738 :
739 : /************************************************************************/
740 : /* FlushCache() */
741 : /************************************************************************/
742 :
743 80 : void PCIDSK2Dataset::FlushCache()
744 :
745 : {
746 80 : GDALPamDataset::FlushCache();
747 :
748 80 : if( poFile )
749 : {
750 : try {
751 80 : poFile->Synchronize();
752 : }
753 0 : catch( PCIDSKException ex )
754 : {
755 : CPLError( CE_Failure, CPLE_AppDefined,
756 0 : "%s", ex.what() );
757 : }
758 : }
759 80 : }
760 :
761 :
762 : /************************************************************************/
763 : /* SetMetadata() */
764 : /************************************************************************/
765 :
766 : CPLErr PCIDSK2Dataset::SetMetadata( char **papszMD,
767 17 : const char *pszDomain )
768 :
769 : {
770 : /* -------------------------------------------------------------------- */
771 : /* PCIDSK only supports metadata in the default domain. */
772 : /* -------------------------------------------------------------------- */
773 17 : if( pszDomain != NULL && strlen(pszDomain) > 0 )
774 0 : return GDALPamDataset::SetMetadata( papszMD, pszDomain );
775 :
776 : /* -------------------------------------------------------------------- */
777 : /* Set each item individually. */
778 : /* -------------------------------------------------------------------- */
779 17 : CSLDestroy( papszLastMDListValue );
780 17 : papszLastMDListValue = NULL;
781 :
782 : try
783 : {
784 : int iItem;
785 :
786 35 : for( iItem = 0; papszMD && papszMD[iItem]; iItem++ )
787 : {
788 : const char *pszItemValue;
789 18 : char *pszItemName = NULL;
790 :
791 18 : pszItemValue = CPLParseNameValue( papszMD[iItem], &pszItemName);
792 18 : poFile->SetMetadataValue( pszItemName, pszItemValue );
793 18 : CPLFree( pszItemName );
794 : }
795 17 : return CE_None;
796 : }
797 0 : catch( PCIDSKException ex )
798 : {
799 : CPLError( CE_Failure, CPLE_AppDefined,
800 0 : "%s", ex.what() );
801 0 : return CE_Failure;
802 : }
803 : }
804 :
805 : /************************************************************************/
806 : /* SetMetadataItem() */
807 : /************************************************************************/
808 :
809 : CPLErr PCIDSK2Dataset::SetMetadataItem( const char *pszName,
810 : const char *pszValue,
811 82 : const char *pszDomain )
812 :
813 : {
814 : /* -------------------------------------------------------------------- */
815 : /* PCIDSK only supports metadata in the default domain. */
816 : /* -------------------------------------------------------------------- */
817 82 : if( pszDomain != NULL && strlen(pszDomain) > 0 )
818 81 : return GDALPamDataset::SetMetadataItem( pszName, pszValue, pszDomain );
819 :
820 : /* -------------------------------------------------------------------- */
821 : /* Set on the file. */
822 : /* -------------------------------------------------------------------- */
823 1 : CSLDestroy( papszLastMDListValue );
824 1 : papszLastMDListValue = NULL;
825 :
826 : try
827 : {
828 1 : poFile->SetMetadataValue( pszName, pszValue );
829 1 : return CE_None;
830 : }
831 0 : catch( PCIDSKException ex )
832 : {
833 : CPLError( CE_Failure, CPLE_AppDefined,
834 0 : "%s", ex.what() );
835 0 : return CE_Failure;
836 : }
837 : }
838 :
839 : /************************************************************************/
840 : /* GetMetadataItem() */
841 : /************************************************************************/
842 :
843 : const char *PCIDSK2Dataset::GetMetadataItem( const char *pszName,
844 38 : const char *pszDomain )
845 :
846 : {
847 : /* -------------------------------------------------------------------- */
848 : /* PCIDSK only supports metadata in the default domain. */
849 : /* -------------------------------------------------------------------- */
850 38 : if( pszDomain != NULL && strlen(pszDomain) > 0 )
851 37 : return GDALPamDataset::GetMetadataItem( pszName, pszDomain );
852 :
853 : /* -------------------------------------------------------------------- */
854 : /* Try and fetch. */
855 : /* -------------------------------------------------------------------- */
856 : try
857 : {
858 1 : osLastMDValue = poFile->GetMetadataValue( pszName );
859 :
860 2 : if( osLastMDValue == "" )
861 1 : return NULL;
862 : else
863 0 : return osLastMDValue.c_str();
864 : }
865 0 : catch( PCIDSKException ex )
866 : {
867 : CPLError( CE_Failure, CPLE_AppDefined,
868 0 : "%s", ex.what() );
869 0 : return NULL;
870 : }
871 : }
872 :
873 : /************************************************************************/
874 : /* GetMetadata() */
875 : /************************************************************************/
876 :
877 5 : char **PCIDSK2Dataset::GetMetadata( const char *pszDomain )
878 :
879 : {
880 : /* -------------------------------------------------------------------- */
881 : /* PCIDSK only supports metadata in the default domain. */
882 : /* -------------------------------------------------------------------- */
883 5 : if( pszDomain != NULL && strlen(pszDomain) > 0 )
884 2 : return GDALPamDataset::GetMetadata( pszDomain );
885 :
886 : /* -------------------------------------------------------------------- */
887 : /* If we have a cached result, just use that. */
888 : /* -------------------------------------------------------------------- */
889 3 : if( papszLastMDListValue != NULL )
890 1 : return papszLastMDListValue;
891 :
892 : /* -------------------------------------------------------------------- */
893 : /* Fetch and build the list. */
894 : /* -------------------------------------------------------------------- */
895 : try
896 : {
897 2 : std::vector<std::string> aosKeys = poFile->GetMetadataKeys();
898 : unsigned int i;
899 :
900 6 : for( i = 0; i < aosKeys.size(); i++ )
901 : {
902 4 : if( aosKeys[i].c_str()[0] == '_' )
903 0 : continue;
904 :
905 : papszLastMDListValue =
906 : CSLSetNameValue( papszLastMDListValue,
907 : aosKeys[i].c_str(),
908 4 : poFile->GetMetadataValue(aosKeys[i]).c_str() );
909 2 : }
910 : }
911 0 : catch( PCIDSKException ex )
912 : {
913 : CPLError( CE_Failure, CPLE_AppDefined,
914 0 : "%s", ex.what() );
915 0 : return NULL;
916 : }
917 :
918 2 : return papszLastMDListValue;
919 : }
920 :
921 : /************************************************************************/
922 : /* SetGeoTransform() */
923 : /************************************************************************/
924 :
925 42 : CPLErr PCIDSK2Dataset::SetGeoTransform( double * padfTransform )
926 : {
927 42 : PCIDSKGeoref *poGeoref = NULL;
928 : try
929 : {
930 42 : PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
931 42 : poGeoref = dynamic_cast<PCIDSKGeoref*>( poGeoSeg );
932 : }
933 0 : catch( PCIDSKException ex )
934 : {
935 : // I should really check whether this is an expected issue.
936 : }
937 :
938 42 : if( poGeoref == NULL )
939 0 : return GDALPamDataset::SetGeoTransform( padfTransform );
940 : else
941 : {
942 : try
943 : {
944 : poGeoref->WriteSimple( poGeoref->GetGeosys(),
945 : padfTransform[0],
946 : padfTransform[1],
947 : padfTransform[2],
948 : padfTransform[3],
949 : padfTransform[4],
950 42 : padfTransform[5] );
951 : }
952 0 : catch( PCIDSKException ex )
953 : {
954 : CPLError( CE_Failure, CPLE_AppDefined,
955 0 : "%s", ex.what() );
956 0 : return CE_Failure;
957 : }
958 :
959 42 : return CE_None;
960 : }
961 : }
962 :
963 : /************************************************************************/
964 : /* GetGeoTransform() */
965 : /************************************************************************/
966 :
967 3 : CPLErr PCIDSK2Dataset::GetGeoTransform( double * padfTransform )
968 : {
969 3 : PCIDSKGeoref *poGeoref = NULL;
970 : try
971 : {
972 3 : PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
973 3 : poGeoref = dynamic_cast<PCIDSKGeoref*>( poGeoSeg );
974 : }
975 0 : catch( PCIDSKException ex )
976 : {
977 : // I should really check whether this is an expected issue.
978 : }
979 :
980 3 : if( poGeoref != NULL )
981 : {
982 : try
983 : {
984 : poGeoref->GetTransform( padfTransform[0],
985 : padfTransform[1],
986 : padfTransform[2],
987 : padfTransform[3],
988 : padfTransform[4],
989 3 : padfTransform[5] );
990 : }
991 0 : catch( PCIDSKException ex )
992 : {
993 : CPLError( CE_Failure, CPLE_AppDefined,
994 0 : "%s", ex.what() );
995 0 : return CE_Failure;
996 : }
997 :
998 : // If we got anything non-default return it.
999 3 : if( padfTransform[0] != 0.0
1000 : || padfTransform[1] != 1.0
1001 : || padfTransform[2] != 0.0
1002 : || padfTransform[3] != 0.0
1003 : || padfTransform[4] != 0.0
1004 : || padfTransform[5] != 1.0 )
1005 3 : return CE_None;
1006 : }
1007 :
1008 : /* -------------------------------------------------------------------- */
1009 : /* Check for worldfile if we have no other georeferencing. */
1010 : /* -------------------------------------------------------------------- */
1011 0 : if( GDALReadWorldFile( GetDescription(), "pxw",
1012 : padfTransform ) )
1013 0 : return CE_None;
1014 : else
1015 0 : return GDALPamDataset::GetGeoTransform( padfTransform );
1016 : }
1017 :
1018 : /************************************************************************/
1019 : /* SetProjection() */
1020 : /************************************************************************/
1021 :
1022 42 : CPLErr PCIDSK2Dataset::SetProjection( const char *pszWKT )
1023 :
1024 : {
1025 42 : osSRS = "";
1026 :
1027 42 : PCIDSKGeoref *poGeoref = NULL;
1028 :
1029 : try
1030 : {
1031 84 : PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
1032 42 : poGeoref = dynamic_cast<PCIDSKGeoref*>( poGeoSeg );
1033 : }
1034 0 : catch( PCIDSKException ex )
1035 : {
1036 : // I should really check whether this is an expected issue.
1037 : }
1038 :
1039 42 : if( poGeoref == NULL )
1040 : {
1041 0 : return GDALPamDataset::SetProjection( pszWKT );
1042 : }
1043 : else
1044 : {
1045 42 : char *pszGeosys = NULL;
1046 42 : char *pszUnits = NULL;
1047 42 : double *padfPrjParams = NULL;
1048 :
1049 42 : OGRSpatialReference oSRS;
1050 42 : char *pszWKTWork = (char *) pszWKT;
1051 :
1052 42 : if( oSRS.importFromWkt( &pszWKTWork ) == OGRERR_NONE
1053 : && oSRS.exportToPCI( &pszGeosys, &pszUnits,
1054 : &padfPrjParams ) == OGRERR_NONE )
1055 : {
1056 : try
1057 : {
1058 : double adfGT[6];
1059 42 : std::vector<double> adfPCIParameters;
1060 : unsigned int i;
1061 :
1062 : poGeoref->GetTransform( adfGT[0], adfGT[1], adfGT[2],
1063 42 : adfGT[3], adfGT[4], adfGT[5] );
1064 :
1065 : poGeoref->WriteSimple( pszGeosys,
1066 : adfGT[0], adfGT[1], adfGT[2],
1067 42 : adfGT[3], adfGT[4], adfGT[5] );
1068 :
1069 756 : for( i = 0; i < 17; i++ )
1070 714 : adfPCIParameters.push_back( padfPrjParams[i] );
1071 :
1072 42 : if( EQUALN(pszUnits,"FOOT",4) )
1073 : adfPCIParameters.push_back(
1074 0 : (double)(int) PCIDSK::UNIT_US_FOOT );
1075 42 : else if( EQUALN(pszUnits,"INTL FOOT",9) )
1076 : adfPCIParameters.push_back(
1077 0 : (double)(int) PCIDSK::UNIT_INTL_FOOT );
1078 42 : else if( EQUALN(pszUnits,"DEGREE",6) )
1079 : adfPCIParameters.push_back(
1080 41 : (double)(int) PCIDSK::UNIT_DEGREE );
1081 : else
1082 : adfPCIParameters.push_back(
1083 1 : (double)(int) PCIDSK::UNIT_METER );
1084 :
1085 42 : poGeoref->WriteParameters( adfPCIParameters );
1086 : }
1087 0 : catch( PCIDSKException ex )
1088 : {
1089 : CPLError( CE_Failure, CPLE_AppDefined,
1090 0 : "%s", ex.what() );
1091 42 : return CE_Failure;
1092 : }
1093 :
1094 42 : CPLFree( pszGeosys );
1095 42 : CPLFree( pszUnits );
1096 42 : CPLFree( padfPrjParams );
1097 :
1098 42 : return CE_None;
1099 : }
1100 : else
1101 0 : return GDALPamDataset::SetProjection( pszWKT );
1102 : }
1103 : }
1104 :
1105 : /************************************************************************/
1106 : /* GetProjectionRef() */
1107 : /************************************************************************/
1108 :
1109 5 : const char *PCIDSK2Dataset::GetProjectionRef()
1110 : {
1111 5 : if( osSRS != "" )
1112 3 : return osSRS.c_str();
1113 :
1114 2 : PCIDSKGeoref *poGeoref = NULL;
1115 :
1116 : try
1117 : {
1118 2 : PCIDSKSegment *poGeoSeg = poFile->GetSegment(1);
1119 2 : poGeoref = dynamic_cast<PCIDSKGeoref*>( poGeoSeg );
1120 : }
1121 0 : catch( PCIDSKException ex )
1122 : {
1123 : // I should really check whether this is an expected issue.
1124 : }
1125 :
1126 2 : if( poGeoref == NULL )
1127 : {
1128 0 : osSRS = GDALPamDataset::GetProjectionRef();
1129 : }
1130 : else
1131 : {
1132 2 : CPLString osGeosys;
1133 2 : const char *pszUnits = NULL;
1134 2 : OGRSpatialReference oSRS;
1135 2 : char *pszWKT = NULL;
1136 2 : std::vector<double> adfParameters;
1137 :
1138 2 : adfParameters.resize(18);
1139 : try
1140 : {
1141 2 : if( poGeoref )
1142 : {
1143 2 : osGeosys = poGeoref->GetGeosys();
1144 2 : adfParameters = poGeoref->GetParameters();
1145 2 : if( ((UnitCode)(int)adfParameters[16])
1146 : == PCIDSK::UNIT_DEGREE )
1147 0 : pszUnits = "DEGREE";
1148 2 : else if( ((UnitCode)(int)adfParameters[16])
1149 : == PCIDSK::UNIT_METER )
1150 0 : pszUnits = "METER";
1151 2 : else if( ((UnitCode)(int)adfParameters[16])
1152 : == PCIDSK::UNIT_US_FOOT )
1153 0 : pszUnits = "FOOT";
1154 2 : else if( ((UnitCode)(int)adfParameters[16])
1155 : == PCIDSK::UNIT_INTL_FOOT )
1156 0 : pszUnits = "INTL FOOT";
1157 : }
1158 : }
1159 0 : catch( PCIDSKException ex )
1160 : {
1161 : CPLError( CE_Failure, CPLE_AppDefined,
1162 0 : "%s", ex.what() );
1163 : }
1164 :
1165 2 : if( oSRS.importFromPCI( osGeosys, pszUnits,
1166 : &(adfParameters[0]) ) == OGRERR_NONE )
1167 : {
1168 2 : oSRS.exportToWkt( &pszWKT );
1169 2 : osSRS = pszWKT;
1170 2 : CPLFree( pszWKT );
1171 : }
1172 : else
1173 : {
1174 0 : osSRS = GDALPamDataset::GetProjectionRef();
1175 2 : }
1176 : }
1177 :
1178 2 : return osSRS.c_str();
1179 : }
1180 :
1181 : /************************************************************************/
1182 : /* IBuildOverviews() */
1183 : /************************************************************************/
1184 :
1185 : CPLErr PCIDSK2Dataset::IBuildOverviews( const char *pszResampling,
1186 : int nOverviews, int *panOverviewList,
1187 : int nListBands, int *panBandList,
1188 : GDALProgressFunc pfnProgress,
1189 0 : void *pProgressData )
1190 :
1191 : {
1192 0 : if( nListBands == 0 )
1193 0 : return CE_None;
1194 :
1195 : /* -------------------------------------------------------------------- */
1196 : /* Currently no support for clearing overviews. */
1197 : /* -------------------------------------------------------------------- */
1198 0 : if( nOverviews == 0 )
1199 : {
1200 : CPLError( CE_Failure, CPLE_AppDefined,
1201 0 : "PCIDSK2 driver does not currently support clearing existing overviews. " );
1202 0 : return CE_Failure;
1203 : }
1204 :
1205 : /* -------------------------------------------------------------------- */
1206 : /* Establish which of the overview levels we already have, and */
1207 : /* which are new. We assume that band 1 of the file is */
1208 : /* representative. */
1209 : /* -------------------------------------------------------------------- */
1210 0 : int i, nNewOverviews, *panNewOverviewList = NULL;
1211 0 : PCIDSK2Band *poBand = (PCIDSK2Band*) GetRasterBand( panBandList[0] );
1212 :
1213 0 : nNewOverviews = 0;
1214 0 : panNewOverviewList = (int *) CPLCalloc(sizeof(int),nOverviews);
1215 0 : for( i = 0; i < nOverviews && poBand != NULL; i++ )
1216 : {
1217 : int j;
1218 :
1219 0 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
1220 : {
1221 : int nOvFactor;
1222 0 : GDALRasterBand * poOverview = poBand->GetOverview( j );
1223 :
1224 : nOvFactor = (int)
1225 0 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
1226 :
1227 0 : if( nOvFactor == panOverviewList[i]
1228 : || nOvFactor == GDALOvLevelAdjust( panOverviewList[i],
1229 : poBand->GetXSize() ) )
1230 0 : panOverviewList[i] *= -1;
1231 : }
1232 :
1233 0 : if( panOverviewList[i] > 0 )
1234 0 : panNewOverviewList[nNewOverviews++] = panOverviewList[i];
1235 : else
1236 0 : panOverviewList[i] *= -1;
1237 : }
1238 :
1239 : /* -------------------------------------------------------------------- */
1240 : /* Create the overviews that are missing. */
1241 : /* -------------------------------------------------------------------- */
1242 0 : for( i = 0; i < nNewOverviews; i++ )
1243 : {
1244 : try
1245 : {
1246 : // conveniently our resampling values mostly match PCIDSK.
1247 : poFile->CreateOverviews( nListBands, panBandList,
1248 0 : panNewOverviewList[i], pszResampling );
1249 : }
1250 0 : catch( PCIDSKException ex )
1251 : {
1252 : CPLError( CE_Failure, CPLE_AppDefined,
1253 0 : "%s", ex.what() );
1254 0 : return CE_Failure;
1255 : }
1256 : }
1257 :
1258 :
1259 : int iBand;
1260 0 : for( iBand = 0; iBand < nListBands; iBand++ )
1261 : {
1262 0 : poBand = (PCIDSK2Band *) GetRasterBand( panBandList[iBand] );
1263 0 : ((PCIDSK2Band *) poBand)->RefreshOverviewList();
1264 : }
1265 :
1266 : /* -------------------------------------------------------------------- */
1267 : /* Actually generate the overview imagery. */
1268 : /* -------------------------------------------------------------------- */
1269 : GDALRasterBand **papoOverviewBands;
1270 0 : CPLErr eErr = CE_None;
1271 0 : std::vector<int> anRegenLevels;
1272 :
1273 : papoOverviewBands = (GDALRasterBand **)
1274 0 : CPLCalloc(sizeof(void*),nOverviews);
1275 :
1276 0 : for( iBand = 0; iBand < nListBands && eErr == CE_None; iBand++ )
1277 : {
1278 0 : nNewOverviews = 0;
1279 :
1280 0 : poBand = (PCIDSK2Band*) GetRasterBand( panBandList[iBand] );
1281 :
1282 0 : for( i = 0; i < nOverviews && poBand != NULL; i++ )
1283 : {
1284 : int j;
1285 :
1286 0 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
1287 : {
1288 : int nOvFactor;
1289 0 : GDALRasterBand * poOverview = poBand->GetOverview( j );
1290 :
1291 : nOvFactor = (int)
1292 0 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
1293 :
1294 0 : if( nOvFactor == panOverviewList[i]
1295 : || nOvFactor == GDALOvLevelAdjust( panOverviewList[i],
1296 : poBand->GetXSize() ) )
1297 : {
1298 0 : papoOverviewBands[nNewOverviews++] = poOverview;
1299 0 : anRegenLevels.push_back( j );
1300 0 : break;
1301 : }
1302 : }
1303 : }
1304 :
1305 0 : if( nNewOverviews > 0 )
1306 : {
1307 : eErr = GDALRegenerateOverviews( (GDALRasterBandH) poBand,
1308 : nNewOverviews,
1309 : (GDALRasterBandH*)papoOverviewBands,
1310 : pszResampling,
1311 0 : pfnProgress, pProgressData );
1312 :
1313 : // Mark the regenerated overviews as valid.
1314 0 : for( i = 0; i < (int) anRegenLevels.size(); i++ )
1315 : poBand->poChannel->SetOverviewValidity( anRegenLevels[i],
1316 0 : true );
1317 : }
1318 : }
1319 :
1320 0 : return eErr;
1321 : }
1322 :
1323 : /************************************************************************/
1324 : /* PCIDSKTypeToGDAL() */
1325 : /************************************************************************/
1326 :
1327 157 : GDALDataType PCIDSK2Dataset::PCIDSKTypeToGDAL( eChanType eType )
1328 : {
1329 157 : switch( eType )
1330 : {
1331 : case CHN_8U:
1332 103 : return GDT_Byte;
1333 :
1334 : case CHN_16U:
1335 18 : return GDT_UInt16;
1336 :
1337 : case CHN_16S:
1338 9 : return GDT_Int16;
1339 :
1340 : case CHN_32R:
1341 9 : return GDT_Float32;
1342 :
1343 : case CHN_BIT:
1344 0 : return GDT_Byte;
1345 :
1346 : case CHN_C16U:
1347 0 : return GDT_CInt16;
1348 :
1349 : case CHN_C16S:
1350 9 : return GDT_CInt16;
1351 :
1352 : case CHN_C32R:
1353 9 : return GDT_CFloat32;
1354 :
1355 : default:
1356 0 : return GDT_Unknown;
1357 : }
1358 : }
1359 :
1360 : /************************************************************************/
1361 : /* Identify() */
1362 : /************************************************************************/
1363 :
1364 10943 : int PCIDSK2Dataset::Identify( GDALOpenInfo * poOpenInfo )
1365 : {
1366 10943 : if( poOpenInfo->nHeaderBytes < 512
1367 : || !EQUALN((const char *) poOpenInfo->pabyHeader, "PCIDSK ", 8) )
1368 10863 : return FALSE;
1369 : else
1370 80 : return TRUE;
1371 : }
1372 :
1373 : /************************************************************************/
1374 : /* Open() */
1375 : /************************************************************************/
1376 :
1377 2698 : GDALDataset *PCIDSK2Dataset::Open( GDALOpenInfo * poOpenInfo )
1378 : {
1379 2698 : if( !Identify( poOpenInfo ) )
1380 2618 : return NULL;
1381 :
1382 : /* -------------------------------------------------------------------- */
1383 : /* Try opening the file. */
1384 : /* -------------------------------------------------------------------- */
1385 : try {
1386 : PCIDSKFile *poFile =
1387 : PCIDSK::Open( poOpenInfo->pszFilename,
1388 : poOpenInfo->eAccess == GA_ReadOnly ? "r" : "r+",
1389 80 : PCIDSK2GetInterfaces() );
1390 80 : if( poFile == NULL )
1391 : {
1392 : CPLError( CE_Failure, CPLE_OpenFailed,
1393 : "Failed to re-open %s within PCIDSK driver.\n",
1394 0 : poOpenInfo->pszFilename );
1395 0 : return NULL;
1396 : }
1397 :
1398 : /* -------------------------------------------------------------------- */
1399 : /* Create a corresponding GDALDataset. */
1400 : /* -------------------------------------------------------------------- */
1401 80 : PCIDSK2Dataset *poDS = NULL;
1402 :
1403 80 : poDS = new PCIDSK2Dataset();
1404 :
1405 80 : poDS->poFile = poFile;
1406 80 : poDS->eAccess = poOpenInfo->eAccess;
1407 160 : poDS->nRasterXSize = poFile->GetWidth();
1408 80 : poDS->nRasterYSize = poFile->GetHeight();
1409 :
1410 : /* -------------------------------------------------------------------- */
1411 : /* Are we specifically PIXEL or BAND interleaving? */
1412 : /* */
1413 : /* We don't set anything for FILE since it is harder to know if */
1414 : /* this is tiled or what the on disk interleaving is. */
1415 : /* -------------------------------------------------------------------- */
1416 80 : if( EQUAL(poFile->GetInterleaving().c_str(),"PIXEL") )
1417 : poDS->SetMetadataItem( "IMAGE_STRUCTURE", "PIXEL",
1418 0 : "IMAGE_STRUCTURE" );
1419 80 : else if( EQUAL(poFile->GetInterleaving().c_str(),"BAND") )
1420 : poDS->SetMetadataItem( "IMAGE_STRUCTURE", "BAND",
1421 80 : "IMAGE_STRUCTURE" );
1422 :
1423 : /* -------------------------------------------------------------------- */
1424 : /* Create band objects. */
1425 : /* -------------------------------------------------------------------- */
1426 : int iBand;
1427 :
1428 234 : for( iBand = 0; iBand < poFile->GetChannels(); iBand++ )
1429 : {
1430 154 : poDS->SetBand( iBand+1, new PCIDSK2Band( poDS, poFile, iBand+1 ));
1431 : }
1432 :
1433 : /* -------------------------------------------------------------------- */
1434 : /* Create band objects for bitmap segments. */
1435 : /* -------------------------------------------------------------------- */
1436 80 : int nLastBitmapSegment = 0;
1437 : PCIDSKSegment *poBitSeg;
1438 :
1439 160 : while( (poBitSeg = poFile->GetSegment( SEG_BIT, "",
1440 : nLastBitmapSegment)) != NULL )
1441 : {
1442 : PCIDSKChannel *poChannel =
1443 0 : dynamic_cast<PCIDSKChannel*>( poBitSeg );
1444 :
1445 : poDS->SetBand( poDS->GetRasterCount()+1,
1446 0 : new PCIDSK2Band( poChannel ) );
1447 :
1448 0 : nLastBitmapSegment = poBitSeg->GetSegmentNumber();
1449 : }
1450 :
1451 : /* -------------------------------------------------------------------- */
1452 : /* Initialize any PAM information. */
1453 : /* -------------------------------------------------------------------- */
1454 80 : poDS->SetDescription( poOpenInfo->pszFilename );
1455 80 : poDS->TryLoadXML();
1456 :
1457 : /* -------------------------------------------------------------------- */
1458 : /* Open overviews. */
1459 : /* -------------------------------------------------------------------- */
1460 80 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
1461 :
1462 80 : return( poDS );
1463 : }
1464 :
1465 : /* -------------------------------------------------------------------- */
1466 : /* Trap exceptions. */
1467 : /* -------------------------------------------------------------------- */
1468 0 : catch( PCIDSKException ex )
1469 : {
1470 : CPLError( CE_Failure, CPLE_AppDefined,
1471 0 : "%s", ex.what() );
1472 : }
1473 0 : catch( ... )
1474 : {
1475 : CPLError( CE_Failure, CPLE_AppDefined,
1476 0 : "PCIDSK SDK Failure in Open(), unexpected exception." );
1477 : }
1478 :
1479 0 : return NULL;
1480 : }
1481 :
1482 : /************************************************************************/
1483 : /* Create() */
1484 : /************************************************************************/
1485 :
1486 : GDALDataset *PCIDSK2Dataset::Create( const char * pszFilename,
1487 : int nXSize, int nYSize, int nBands,
1488 : GDALDataType eType,
1489 44 : char **papszParmList )
1490 :
1491 : {
1492 : PCIDSKFile *poFile;
1493 :
1494 : /* -------------------------------------------------------------------- */
1495 : /* Prepare channel type list. */
1496 : /* -------------------------------------------------------------------- */
1497 44 : std::vector<eChanType> aeChanTypes;
1498 :
1499 44 : if( eType == GDT_Float32 )
1500 3 : aeChanTypes.resize( MAX(1,nBands), CHN_32R );
1501 41 : else if( eType == GDT_Int16 )
1502 3 : aeChanTypes.resize( MAX(1,nBands), CHN_16S );
1503 38 : else if( eType == GDT_UInt16 )
1504 4 : aeChanTypes.resize( MAX(1,nBands), CHN_16U );
1505 34 : else if( eType == GDT_CInt16 )
1506 3 : aeChanTypes.resize( MAX(1, nBands), CHN_C16S );
1507 31 : else if( eType == GDT_CFloat32 )
1508 3 : aeChanTypes.resize( MAX(1, nBands), CHN_C32R );
1509 : else
1510 28 : aeChanTypes.resize( MAX(1,nBands), CHN_8U );
1511 :
1512 : /* -------------------------------------------------------------------- */
1513 : /* Reformat options. Currently no support for jpeg compression */
1514 : /* quality. */
1515 : /* -------------------------------------------------------------------- */
1516 44 : CPLString osOptions;
1517 : const char *pszValue;
1518 :
1519 44 : pszValue = CSLFetchNameValue( papszParmList, "INTERLEAVING" );
1520 44 : if( pszValue == NULL )
1521 44 : pszValue = "BAND";
1522 :
1523 44 : osOptions = pszValue;
1524 :
1525 44 : if( osOptions == "TILED" )
1526 : {
1527 0 : pszValue = CSLFetchNameValue( papszParmList, "TILESIZE" );
1528 0 : if( pszValue != NULL )
1529 0 : osOptions += pszValue;
1530 :
1531 0 : pszValue = CSLFetchNameValue( papszParmList, "COMPRESSION" );
1532 0 : if( pszValue != NULL )
1533 : {
1534 0 : osOptions += " ";
1535 0 : osOptions += pszValue;
1536 : }
1537 : }
1538 :
1539 : /* -------------------------------------------------------------------- */
1540 : /* Try creation. */
1541 : /* -------------------------------------------------------------------- */
1542 : try {
1543 : poFile = PCIDSK::Create( pszFilename, nXSize, nYSize, nBands,
1544 : &(aeChanTypes[0]), osOptions,
1545 44 : PCIDSK2GetInterfaces() );
1546 44 : delete poFile;
1547 :
1548 : // TODO: should we ensure this driver gets used?
1549 :
1550 44 : return (GDALDataset *) GDALOpen( pszFilename, GA_Update );
1551 : }
1552 : /* -------------------------------------------------------------------- */
1553 : /* Trap exceptions. */
1554 : /* -------------------------------------------------------------------- */
1555 0 : catch( PCIDSKException ex )
1556 : {
1557 : CPLError( CE_Failure, CPLE_AppDefined,
1558 0 : "%s", ex.what() );
1559 0 : return NULL;
1560 : }
1561 0 : catch( ... )
1562 : {
1563 : CPLError( CE_Failure, CPLE_AppDefined,
1564 0 : "PCIDSK::Create() failed, unexpected exception." );
1565 0 : return NULL;
1566 0 : }
1567 : }
1568 :
1569 : /************************************************************************/
1570 : /* GDALRegister_PCIDSK() */
1571 : /************************************************************************/
1572 :
1573 409 : void GDALRegister_PCIDSK()
1574 :
1575 : {
1576 : GDALDriver *poDriver;
1577 :
1578 409 : if( GDALGetDriverByName( "PCIDSK" ) == NULL )
1579 : {
1580 392 : poDriver = new GDALDriver();
1581 :
1582 392 : poDriver->SetDescription( "PCIDSK" );
1583 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1584 392 : "PCIDSK Database File" );
1585 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1586 392 : "frmt_pcidsk.html" );
1587 392 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1588 392 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "pix" );
1589 392 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte UInt16 Int16 Float32 CInt16 CFloat32" );
1590 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
1591 : "<CreationOptionList>"
1592 : " <Option name='INTERLEAVING' type='string-select' default='BAND' description='raster data organization'>"
1593 : " <Value>PIXEL</Value>"
1594 : " <Value>BAND</Value>"
1595 : " <Value>FILE</Value>"
1596 : " <Value>TILED</Value>"
1597 : " </Option>"
1598 : " <Option name='COMPRESSION' type='string-select' default='NONE' description='compression - (INTERLEAVING=TILED only)'>"
1599 : " <Value>NONE</Value>"
1600 : " <Value>RLE</Value>"
1601 : " <Value>JPEG</Value>"
1602 : " </Option>"
1603 : " <Option name='TILESIZE' type='int' default='127' description='Tile Size (INTERLEAVING=TILED only)'/>"
1604 392 : "</CreationOptionList>" );
1605 :
1606 392 : poDriver->pfnIdentify = PCIDSK2Dataset::Identify;
1607 392 : poDriver->pfnOpen = PCIDSK2Dataset::Open;
1608 392 : poDriver->pfnCreate = PCIDSK2Dataset::Create;
1609 :
1610 392 : GetGDALDriverManager()->RegisterDriver( poDriver );
1611 : }
1612 409 : }
1613 :
1614 :
|