1 : /******************************************************************************
2 : * $Id: landataset.cpp 23033 2011-09-03 18:46:11Z rouault $
3 : *
4 : * Project: eCognition
5 : * Purpose: Implementation of Erdas .LAN / .GIS format.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2004, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "rawdataset.h"
31 : #include "cpl_string.h"
32 : #include "ogr_spatialref.h"
33 :
34 : CPL_CVSID("$Id: landataset.cpp 23033 2011-09-03 18:46:11Z rouault $");
35 :
36 : CPL_C_START
37 : void GDALRegister_LAN(void);
38 : CPL_C_END
39 :
40 : /**
41 :
42 : Erdas Header format: "HEAD74"
43 :
44 : Offset Size Type Description
45 : ------ ---- ---- -----------
46 : 0 6 char magic cookie / version (ie. HEAD74).
47 : 6 2 Int16 Pixel type, 0=8bit, 1=4bit, 2=16bit
48 : 8 2 Int16 Number of Bands.
49 : 10 6 char Unknown.
50 : 16 4 Int32 Width
51 : 20 4 Int32 Height
52 : 24 4 Int32 X Start (offset in original file?)
53 : 28 4 Int32 Y Start (offset in original file?)
54 : 32 56 char Unknown.
55 : 88 2 Int16 0=LAT, 1=UTM, 2=StatePlane, 3- are projections?
56 : 90 2 Int16 Classes in coverage.
57 : 92 14 char Unknown.
58 : 106 2 Int16 Area Unit (0=none, 1=Acre, 2=Hectare, 3=Other)
59 : 108 4 Float32 Pixel area.
60 : 112 4 Float32 Upper Left corner X (center of pixel?)
61 : 116 4 Float32 Upper Left corner Y (center of pixel?)
62 : 120 4 Float32 Width of a pixel.
63 : 124 4 Float32 Height of a pixel.
64 :
65 : Erdas Header format: "HEADER"
66 :
67 : Offset Size Type Description
68 : ------ ---- ---- -----------
69 : 0 6 char magic cookie / version (ie. HEAD74).
70 : 6 2 Int16 Pixel type, 0=8bit, 1=4bit, 2=16bit
71 : 8 2 Int16 Number of Bands.
72 : 10 6 char Unknown.
73 : 16 4 Float32 Width
74 : 20 4 Float32 Height
75 : 24 4 Int32 X Start (offset in original file?)
76 : 28 4 Int32 Y Start (offset in original file?)
77 : 32 56 char Unknown.
78 : 88 2 Int16 0=LAT, 1=UTM, 2=StatePlane, 3- are projections?
79 : 90 2 Int16 Classes in coverage.
80 : 92 14 char Unknown.
81 : 106 2 Int16 Area Unit (0=none, 1=Acre, 2=Hectare, 3=Other)
82 : 108 4 Float32 Pixel area.
83 : 112 4 Float32 Upper Left corner X (center of pixel?)
84 : 116 4 Float32 Upper Left corner Y (center of pixel?)
85 : 120 4 Float32 Width of a pixel.
86 : 124 4 Float32 Height of a pixel.
87 :
88 : All binary fields are in the same byte order but it may be big endian or
89 : little endian depending on what platform the file was written on. Usually
90 : this can be checked against the number of bands though this test won't work
91 : if there are more than 255 bands.
92 :
93 : There is also some information on .STA and .TRL files at:
94 :
95 : http://www.pcigeomatics.com/cgi-bin/pcihlp/ERDASWR%7CTRAILER+FORMAT
96 :
97 : **/
98 :
99 : #define ERD_HEADER_SIZE 128
100 :
101 : /************************************************************************/
102 : /* ==================================================================== */
103 : /* LAN4BitRasterBand */
104 : /* ==================================================================== */
105 : /************************************************************************/
106 :
107 : class LANDataset;
108 :
109 : class LAN4BitRasterBand : public GDALPamRasterBand
110 : {
111 : GDALColorTable *poCT;
112 : GDALColorInterp eInterp;
113 :
114 : public:
115 : LAN4BitRasterBand( LANDataset *, int );
116 : ~LAN4BitRasterBand();
117 :
118 : virtual GDALColorTable *GetColorTable();
119 : virtual GDALColorInterp GetColorInterpretation();
120 : virtual CPLErr SetColorTable( GDALColorTable * );
121 : virtual CPLErr SetColorInterpretation( GDALColorInterp );
122 :
123 : virtual CPLErr IReadBlock( int, int, void * );
124 : };
125 :
126 : /************************************************************************/
127 : /* ==================================================================== */
128 : /* LANDataset */
129 : /* ==================================================================== */
130 : /************************************************************************/
131 :
132 : class LANDataset : public RawDataset
133 : {
134 : public:
135 : VSILFILE *fpImage; // image data file.
136 :
137 : char pachHeader[ERD_HEADER_SIZE];
138 :
139 : char *pszProjection;
140 :
141 : double adfGeoTransform[6];
142 :
143 : CPLString osSTAFilename;
144 : void CheckForStatistics(void);
145 :
146 : virtual char **GetFileList();
147 :
148 : public:
149 : LANDataset();
150 : ~LANDataset();
151 :
152 : virtual CPLErr GetGeoTransform( double * padfTransform );
153 : virtual CPLErr SetGeoTransform( double * padfTransform );
154 : virtual const char *GetProjectionRef();
155 : virtual CPLErr SetProjection( const char * );
156 :
157 : static GDALDataset *Open( GDALOpenInfo * );
158 : static GDALDataset *Create( const char * pszFilename,
159 : int nXSize, int nYSize, int nBands,
160 : GDALDataType eType, char ** papszOptions );
161 : };
162 :
163 : /************************************************************************/
164 : /* ==================================================================== */
165 : /* LAN4BitRasterBand */
166 : /* ==================================================================== */
167 : /************************************************************************/
168 :
169 : /************************************************************************/
170 : /* LAN4BitRasterBand() */
171 : /************************************************************************/
172 :
173 1 : LAN4BitRasterBand::LAN4BitRasterBand( LANDataset *poDS, int nBandIn )
174 :
175 : {
176 1 : this->poDS = poDS;
177 1 : this->nBand = nBandIn;
178 1 : this->eDataType = GDT_Byte;
179 :
180 1 : nBlockXSize = poDS->GetRasterXSize();;
181 1 : nBlockYSize = 1;
182 :
183 1 : poCT = NULL;
184 1 : eInterp = GCI_Undefined;
185 1 : }
186 :
187 : /************************************************************************/
188 : /* ~LAN4BitRasterBand() */
189 : /************************************************************************/
190 :
191 1 : LAN4BitRasterBand::~LAN4BitRasterBand()
192 :
193 : {
194 1 : if( poCT )
195 0 : delete poCT;
196 1 : }
197 :
198 : /************************************************************************/
199 : /* IReadBlock() */
200 : /************************************************************************/
201 :
202 2 : CPLErr LAN4BitRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
203 : void * pImage )
204 :
205 : {
206 2 : LANDataset *poLAN_DS = (LANDataset *) poDS;
207 2 : CPLAssert( nBlockXOff == 0 );
208 :
209 : /* -------------------------------------------------------------------- */
210 : /* Seek to profile. */
211 : /* -------------------------------------------------------------------- */
212 : int nOffset;
213 :
214 : nOffset =
215 : ERD_HEADER_SIZE
216 : + (nBlockYOff * nRasterXSize * poLAN_DS->GetRasterCount()) / 2
217 2 : + ((nBand - 1) * nRasterXSize) / 2;
218 :
219 2 : if( VSIFSeekL( poLAN_DS->fpImage, nOffset, SEEK_SET ) != 0 )
220 : {
221 : CPLError( CE_Failure, CPLE_FileIO,
222 0 : "LAN Seek failed:%s", VSIStrerror( errno ) );
223 0 : return CE_Failure;
224 : }
225 :
226 : /* -------------------------------------------------------------------- */
227 : /* Read the profile. */
228 : /* -------------------------------------------------------------------- */
229 2 : if( VSIFReadL( pImage, 1, nRasterXSize/2, poLAN_DS->fpImage ) !=
230 : (size_t) nRasterXSize / 2 )
231 : {
232 : CPLError( CE_Failure, CPLE_FileIO,
233 0 : "LAN Read failed:%s", VSIStrerror( errno ) );
234 0 : return CE_Failure;
235 : }
236 :
237 : /* -------------------------------------------------------------------- */
238 : /* Convert 4bit to 8bit. */
239 : /* -------------------------------------------------------------------- */
240 : int i;
241 :
242 6 : for( i = nRasterXSize-1; i >= 0; i-- )
243 : {
244 4 : if( (i & 0x01) != 0 )
245 2 : ((GByte *) pImage)[i] = ((GByte *) pImage)[i/2] & 0x0f;
246 : else
247 2 : ((GByte *) pImage)[i] = (((GByte *) pImage)[i/2] & 0xf0)/16;
248 : }
249 :
250 2 : return CE_None;
251 : }
252 :
253 : /************************************************************************/
254 : /* SetColorTable() */
255 : /************************************************************************/
256 :
257 0 : CPLErr LAN4BitRasterBand::SetColorTable( GDALColorTable *poNewCT )
258 :
259 : {
260 0 : if( poCT )
261 0 : delete poCT;
262 0 : if( poNewCT == NULL )
263 0 : poCT = NULL;
264 : else
265 0 : poCT = poNewCT->Clone();
266 :
267 0 : return CE_None;
268 : }
269 :
270 : /************************************************************************/
271 : /* GetColorTable() */
272 : /************************************************************************/
273 :
274 0 : GDALColorTable *LAN4BitRasterBand::GetColorTable()
275 :
276 : {
277 0 : if( poCT != NULL )
278 0 : return poCT;
279 : else
280 0 : return GDALPamRasterBand::GetColorTable();
281 : }
282 :
283 : /************************************************************************/
284 : /* SetColorInterpretation() */
285 : /************************************************************************/
286 :
287 0 : CPLErr LAN4BitRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
288 :
289 : {
290 0 : eInterp = eNewInterp;
291 :
292 0 : return CE_None;
293 : }
294 :
295 : /************************************************************************/
296 : /* GetColorInterpretation() */
297 : /************************************************************************/
298 :
299 0 : GDALColorInterp LAN4BitRasterBand::GetColorInterpretation()
300 :
301 : {
302 0 : return eInterp;
303 : }
304 :
305 : /************************************************************************/
306 : /* ==================================================================== */
307 : /* LANDataset */
308 : /* ==================================================================== */
309 : /************************************************************************/
310 :
311 : /************************************************************************/
312 : /* LANDataset() */
313 : /************************************************************************/
314 :
315 24 : LANDataset::LANDataset()
316 : {
317 24 : fpImage = NULL;
318 24 : pszProjection = NULL;
319 24 : }
320 :
321 : /************************************************************************/
322 : /* ~LANDataset() */
323 : /************************************************************************/
324 :
325 24 : LANDataset::~LANDataset()
326 :
327 : {
328 24 : FlushCache();
329 :
330 24 : if( fpImage != NULL )
331 24 : VSIFCloseL( fpImage );
332 :
333 24 : CPLFree( pszProjection );
334 24 : }
335 :
336 : /************************************************************************/
337 : /* Open() */
338 : /************************************************************************/
339 :
340 12006 : GDALDataset *LANDataset::Open( GDALOpenInfo * poOpenInfo )
341 :
342 : {
343 : /* -------------------------------------------------------------------- */
344 : /* We assume the user is pointing to the header (.pcb) file. */
345 : /* Does this appear to be a pcb file? */
346 : /* -------------------------------------------------------------------- */
347 12006 : if( poOpenInfo->nHeaderBytes < ERD_HEADER_SIZE )
348 11398 : return NULL;
349 :
350 608 : if( !EQUALN((const char *)poOpenInfo->pabyHeader,"HEADER",6)
351 : && !EQUALN((const char *)poOpenInfo->pabyHeader,"HEAD74",6) )
352 584 : return NULL;
353 :
354 : /* -------------------------------------------------------------------- */
355 : /* Create a corresponding GDALDataset. */
356 : /* -------------------------------------------------------------------- */
357 : LANDataset *poDS;
358 :
359 24 : poDS = new LANDataset();
360 :
361 24 : poDS->eAccess = poOpenInfo->eAccess;
362 :
363 : /* -------------------------------------------------------------------- */
364 : /* Adopt the openinfo file pointer for use with this file. */
365 : /* -------------------------------------------------------------------- */
366 24 : if( poOpenInfo->eAccess == GA_ReadOnly )
367 10 : poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
368 : else
369 14 : poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb+" );
370 :
371 24 : if( poDS->fpImage == NULL )
372 0 : return NULL;
373 :
374 : /* -------------------------------------------------------------------- */
375 : /* Do we need to byte swap the headers to local machine order? */
376 : /* -------------------------------------------------------------------- */
377 24 : int bBigEndian = poOpenInfo->pabyHeader[8] == 0;
378 : int bNeedSwap;
379 :
380 24 : memcpy( poDS->pachHeader, poOpenInfo->pabyHeader, ERD_HEADER_SIZE );
381 :
382 : #ifdef CPL_LSB
383 24 : bNeedSwap = bBigEndian;
384 : #else
385 : bNeedSwap = !bBigEndian;
386 : #endif
387 :
388 24 : if( bNeedSwap )
389 : {
390 2 : CPL_SWAP16PTR( poDS->pachHeader + 6 );
391 2 : CPL_SWAP16PTR( poDS->pachHeader + 8 );
392 :
393 2 : CPL_SWAP32PTR( poDS->pachHeader + 16 );
394 2 : CPL_SWAP32PTR( poDS->pachHeader + 20 );
395 2 : CPL_SWAP32PTR( poDS->pachHeader + 24 );
396 2 : CPL_SWAP32PTR( poDS->pachHeader + 28 );
397 :
398 2 : CPL_SWAP16PTR( poDS->pachHeader + 88 );
399 2 : CPL_SWAP16PTR( poDS->pachHeader + 90 );
400 :
401 2 : CPL_SWAP16PTR( poDS->pachHeader + 106 );
402 2 : CPL_SWAP32PTR( poDS->pachHeader + 108 );
403 2 : CPL_SWAP32PTR( poDS->pachHeader + 112 );
404 2 : CPL_SWAP32PTR( poDS->pachHeader + 116 );
405 2 : CPL_SWAP32PTR( poDS->pachHeader + 120 );
406 2 : CPL_SWAP32PTR( poDS->pachHeader + 124 );
407 : }
408 :
409 : /* -------------------------------------------------------------------- */
410 : /* Capture some information from the file that is of interest. */
411 : /* -------------------------------------------------------------------- */
412 : int nBandCount, nPixelOffset;
413 : GDALDataType eDataType;
414 :
415 24 : if( EQUALN(poDS->pachHeader,"HEADER",7) )
416 : {
417 0 : poDS->nRasterXSize = (int) *((float *) (poDS->pachHeader + 16));
418 0 : poDS->nRasterYSize = (int) *((float *) (poDS->pachHeader + 20));
419 : }
420 : else
421 : {
422 24 : poDS->nRasterXSize = *((GInt32 *) (poDS->pachHeader + 16));
423 24 : poDS->nRasterYSize = *((GInt32 *) (poDS->pachHeader + 20));
424 : }
425 :
426 24 : if( *((GInt16 *) (poDS->pachHeader + 6)) == 0 )
427 : {
428 18 : eDataType = GDT_Byte;
429 18 : nPixelOffset = 1;
430 : }
431 6 : else if( *((GInt16 *) (poDS->pachHeader + 6)) == 1 ) /* 4bit! */
432 : {
433 1 : eDataType = GDT_Byte;
434 1 : nPixelOffset = -1;
435 : }
436 5 : else if( *((GInt16 *) (poDS->pachHeader + 6)) == 2 )
437 : {
438 5 : nPixelOffset = 2;
439 5 : eDataType = GDT_Int16;
440 : }
441 : else
442 : {
443 : CPLError( CE_Failure, CPLE_AppDefined,
444 : "Unsupported pixel type (%d).",
445 0 : *((GInt16 *) (poDS->pachHeader + 6)) );
446 :
447 0 : delete poDS;
448 0 : return NULL;
449 : }
450 :
451 24 : nBandCount = *((GInt16 *) (poDS->pachHeader + 8));
452 :
453 24 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
454 : !GDALCheckBandCount(nBandCount, FALSE))
455 : {
456 2 : delete poDS;
457 2 : return NULL;
458 : }
459 :
460 : /* -------------------------------------------------------------------- */
461 : /* Create band information object. */
462 : /* -------------------------------------------------------------------- */
463 78 : for( int iBand = 1; iBand <= nBandCount; iBand++ )
464 : {
465 56 : if( nPixelOffset == -1 ) /* 4 bit case */
466 : poDS->SetBand( iBand,
467 1 : new LAN4BitRasterBand( poDS, iBand ) );
468 : else
469 : poDS->SetBand(
470 : iBand,
471 : new RawRasterBand( poDS, iBand, poDS->fpImage,
472 : ERD_HEADER_SIZE + (iBand-1)
473 : * nPixelOffset * poDS->nRasterXSize,
474 : nPixelOffset,
475 : poDS->nRasterXSize*nPixelOffset*nBandCount,
476 55 : eDataType, !bNeedSwap, TRUE ));
477 : }
478 :
479 : /* -------------------------------------------------------------------- */
480 : /* Initialize any PAM information. */
481 : /* -------------------------------------------------------------------- */
482 22 : poDS->SetDescription( poOpenInfo->pszFilename );
483 22 : poDS->CheckForStatistics();
484 22 : poDS->TryLoadXML();
485 :
486 : /* -------------------------------------------------------------------- */
487 : /* Check for overviews. */
488 : /* -------------------------------------------------------------------- */
489 22 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
490 :
491 : /* -------------------------------------------------------------------- */
492 : /* Try to interprete georeferencing. */
493 : /* -------------------------------------------------------------------- */
494 22 : poDS->adfGeoTransform[0] = *((float *) (poDS->pachHeader + 112));
495 22 : poDS->adfGeoTransform[1] = *((float *) (poDS->pachHeader + 120));
496 22 : poDS->adfGeoTransform[2] = 0.0;
497 22 : poDS->adfGeoTransform[3] = *((float *) (poDS->pachHeader + 116));
498 22 : poDS->adfGeoTransform[4] = 0.0;
499 22 : poDS->adfGeoTransform[5] = - *((float *) (poDS->pachHeader + 124));
500 :
501 : // adjust for center of pixel vs. top left corner of pixel.
502 22 : poDS->adfGeoTransform[0] -= poDS->adfGeoTransform[1] * 0.5;
503 22 : poDS->adfGeoTransform[3] -= poDS->adfGeoTransform[5] * 0.5;
504 :
505 : /* -------------------------------------------------------------------- */
506 : /* If we didn't get any georeferencing, try for a worldfile. */
507 : /* -------------------------------------------------------------------- */
508 44 : if( poDS->adfGeoTransform[1] == 0.0
509 22 : || poDS->adfGeoTransform[5] == 0.0 )
510 : {
511 0 : if( !GDALReadWorldFile( poOpenInfo->pszFilename, NULL,
512 : poDS->adfGeoTransform ) )
513 : GDALReadWorldFile( poOpenInfo->pszFilename, ".wld",
514 0 : poDS->adfGeoTransform );
515 : }
516 :
517 : /* -------------------------------------------------------------------- */
518 : /* Try to come up with something for the coordinate system. */
519 : /* -------------------------------------------------------------------- */
520 22 : int nCoordSys = *((GInt16 *) (poDS->pachHeader + 88));
521 :
522 22 : if( nCoordSys == 0 )
523 : {
524 22 : poDS->pszProjection = CPLStrdup(SRS_WKT_WGS84);
525 :
526 : }
527 0 : else if( nCoordSys == 1 )
528 : {
529 : poDS->pszProjection =
530 0 : CPLStrdup("LOCAL_CS[\"UTM - Zone Unknown\",UNIT[\"Meter\",1]]");
531 : }
532 0 : else if( nCoordSys == 2 )
533 : {
534 0 : poDS->pszProjection = CPLStrdup("LOCAL_CS[\"State Plane - Zone Unknown\",UNIT[\"US survey foot\",0.3048006096012192]]");
535 : }
536 : else
537 : {
538 : poDS->pszProjection =
539 0 : CPLStrdup("LOCAL_CS[\"Unknown\",UNIT[\"Meter\",1]]");
540 : }
541 :
542 : /* -------------------------------------------------------------------- */
543 : /* Check for a trailer file with a colormap in it. */
544 : /* -------------------------------------------------------------------- */
545 22 : char *pszPath = CPLStrdup(CPLGetPath(poOpenInfo->pszFilename));
546 22 : char *pszBasename = CPLStrdup(CPLGetBasename(poOpenInfo->pszFilename));
547 : const char *pszTRLFilename =
548 22 : CPLFormCIFilename( pszPath, pszBasename, "trl" );
549 : VSILFILE *fpTRL;
550 :
551 22 : fpTRL = VSIFOpenL( pszTRLFilename, "rb" );
552 22 : if( fpTRL != NULL )
553 : {
554 : char szTRLData[896];
555 : int iColor;
556 : GDALColorTable *poCT;
557 :
558 0 : VSIFReadL( szTRLData, 1, 896, fpTRL );
559 0 : VSIFCloseL( fpTRL );
560 :
561 0 : poCT = new GDALColorTable();
562 0 : for( iColor = 0; iColor < 256; iColor++ )
563 : {
564 : GDALColorEntry sEntry;
565 :
566 0 : sEntry.c2 = ((GByte *) szTRLData)[iColor+128];
567 0 : sEntry.c1 = ((GByte *) szTRLData)[iColor+128+256];
568 0 : sEntry.c3 = ((GByte *) szTRLData)[iColor+128+512];
569 0 : sEntry.c4 = 255;
570 0 : poCT->SetColorEntry( iColor, &sEntry );
571 :
572 : // only 16 colors in 4bit files.
573 0 : if( nPixelOffset == -1 && iColor == 15 )
574 0 : break;
575 : }
576 :
577 0 : poDS->GetRasterBand(1)->SetColorTable( poCT );
578 0 : poDS->GetRasterBand(1)->SetColorInterpretation( GCI_PaletteIndex );
579 :
580 0 : delete poCT;
581 : }
582 :
583 22 : CPLFree( pszPath );
584 22 : CPLFree( pszBasename );
585 :
586 22 : return( poDS );
587 : }
588 :
589 : /************************************************************************/
590 : /* GetGeoTransform() */
591 : /************************************************************************/
592 :
593 7 : CPLErr LANDataset::GetGeoTransform( double * padfTransform )
594 :
595 : {
596 7 : if( adfGeoTransform[1] != 0.0 && adfGeoTransform[5] != 0.0 )
597 : {
598 7 : memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
599 7 : return CE_None;
600 : }
601 : else
602 0 : return GDALPamDataset::GetGeoTransform( padfTransform );
603 : }
604 :
605 : /************************************************************************/
606 : /* SetGeoTransform() */
607 : /************************************************************************/
608 :
609 13 : CPLErr LANDataset::SetGeoTransform( double * padfTransform )
610 :
611 : {
612 : unsigned char abyHeader[128];
613 :
614 13 : memcpy( adfGeoTransform, padfTransform, sizeof(double) * 6 );
615 :
616 13 : VSIFSeekL( fpImage, 0, SEEK_SET );
617 13 : VSIFReadL( abyHeader, 128, 1, fpImage );
618 :
619 : // Upper Left X
620 : float f32Val;
621 :
622 13 : f32Val = (float) (adfGeoTransform[0] + 0.5 * adfGeoTransform[1]);
623 13 : memcpy( abyHeader + 112, &f32Val, 4 );
624 :
625 : // Upper Left Y
626 13 : f32Val = (float) (adfGeoTransform[3] + 0.5 * adfGeoTransform[5]);
627 13 : memcpy( abyHeader + 116, &f32Val, 4 );
628 :
629 : // width of pixel
630 13 : f32Val = (float) adfGeoTransform[1];
631 13 : memcpy( abyHeader + 120, &f32Val, 4 );
632 :
633 : // height of pixel
634 13 : f32Val = (float) fabs(adfGeoTransform[5]);
635 13 : memcpy( abyHeader + 124, &f32Val, 4 );
636 :
637 13 : if( VSIFSeekL( fpImage, 0, SEEK_SET ) != 0
638 : || VSIFWriteL( abyHeader, 128, 1, fpImage ) != 1 )
639 : {
640 : CPLError( CE_Failure, CPLE_FileIO,
641 0 : "File IO Error writing header with new geotransform." );
642 0 : return CE_Failure;
643 : }
644 : else
645 13 : return CE_None;
646 : }
647 :
648 : /************************************************************************/
649 : /* GetProjectionRef() */
650 : /* */
651 : /* Use PAM coordinate system if available in preference to the */
652 : /* generally poor value derived from the file itself. */
653 : /************************************************************************/
654 :
655 0 : const char *LANDataset::GetProjectionRef()
656 :
657 : {
658 0 : const char* pszPamPrj = GDALPamDataset::GetProjectionRef();
659 :
660 0 : if( pszProjection != NULL && strlen(pszPamPrj) == 0 )
661 0 : return pszProjection;
662 : else
663 0 : return pszPamPrj;
664 : }
665 :
666 : /************************************************************************/
667 : /* SetProjection() */
668 : /************************************************************************/
669 :
670 13 : CPLErr LANDataset::SetProjection( const char * pszWKT )
671 :
672 : {
673 : unsigned char abyHeader[128];
674 :
675 13 : VSIFSeekL( fpImage, 0, SEEK_SET );
676 13 : VSIFReadL( abyHeader, 128, 1, fpImage );
677 :
678 13 : OGRSpatialReference oSRS( pszWKT );
679 :
680 13 : GUInt16 nProjCode = 0;
681 :
682 13 : if( oSRS.IsGeographic() )
683 13 : nProjCode = 0;
684 :
685 0 : else if( oSRS.GetUTMZone() != 0 )
686 0 : nProjCode = 1;
687 :
688 : // Too bad we have no way of recognising state plane projections.
689 :
690 : else
691 : {
692 0 : const char *pszProjection = oSRS.GetAttrValue("PROJECTION");
693 :
694 0 : if( pszProjection == NULL )
695 : ;
696 0 : else if( EQUAL(pszProjection,
697 : SRS_PT_ALBERS_CONIC_EQUAL_AREA) )
698 0 : nProjCode = 3;
699 0 : else if( EQUAL(pszProjection,
700 : SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP) )
701 0 : nProjCode = 4;
702 0 : else if( EQUAL(pszProjection,
703 : SRS_PT_MERCATOR_1SP) )
704 0 : nProjCode = 5;
705 0 : else if( EQUAL(pszProjection,
706 : SRS_PT_POLAR_STEREOGRAPHIC) )
707 0 : nProjCode = 6;
708 0 : else if( EQUAL(pszProjection,
709 : SRS_PT_POLYCONIC) )
710 0 : nProjCode = 7;
711 0 : else if( EQUAL(pszProjection,
712 : SRS_PT_EQUIDISTANT_CONIC) )
713 0 : nProjCode = 8;
714 0 : else if( EQUAL(pszProjection,
715 : SRS_PT_TRANSVERSE_MERCATOR) )
716 0 : nProjCode = 9;
717 0 : else if( EQUAL(pszProjection,
718 : SRS_PT_STEREOGRAPHIC) )
719 0 : nProjCode = 10;
720 0 : else if( EQUAL(pszProjection,
721 : SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA) )
722 0 : nProjCode = 11;
723 0 : else if( EQUAL(pszProjection,
724 : SRS_PT_AZIMUTHAL_EQUIDISTANT) )
725 0 : nProjCode = 12;
726 0 : else if( EQUAL(pszProjection,
727 : SRS_PT_GNOMONIC) )
728 0 : nProjCode = 13;
729 0 : else if( EQUAL(pszProjection,
730 : SRS_PT_ORTHOGRAPHIC) )
731 0 : nProjCode = 14;
732 : // we don't have GVNP.
733 0 : else if( EQUAL(pszProjection,
734 : SRS_PT_SINUSOIDAL) )
735 0 : nProjCode = 16;
736 0 : else if( EQUAL(pszProjection,
737 : SRS_PT_EQUIRECTANGULAR) )
738 0 : nProjCode = 17;
739 0 : else if( EQUAL(pszProjection,
740 : SRS_PT_MILLER_CYLINDRICAL) )
741 0 : nProjCode = 18;
742 0 : else if( EQUAL(pszProjection,
743 : SRS_PT_VANDERGRINTEN) )
744 0 : nProjCode = 19;
745 0 : else if( EQUAL(pszProjection,
746 : SRS_PT_HOTINE_OBLIQUE_MERCATOR) )
747 0 : nProjCode = 20;
748 : }
749 :
750 13 : memcpy( abyHeader + 88, &nProjCode, 2 );
751 :
752 13 : VSIFSeekL( fpImage, 0, SEEK_SET );
753 13 : VSIFWriteL( abyHeader, 128, 1, fpImage );
754 :
755 13 : return GDALPamDataset::SetProjection( pszWKT );
756 : }
757 :
758 : /************************************************************************/
759 : /* GetFileList() */
760 : /************************************************************************/
761 :
762 0 : char **LANDataset::GetFileList()
763 :
764 : {
765 0 : char **papszFileList = NULL;
766 :
767 : // Main data file, etc.
768 0 : papszFileList = GDALPamDataset::GetFileList();
769 :
770 0 : if( strlen(osSTAFilename) > 0 )
771 0 : papszFileList = CSLAddString( papszFileList, osSTAFilename );
772 :
773 0 : return papszFileList;
774 : }
775 :
776 : /************************************************************************/
777 : /* CheckForStatistics() */
778 : /************************************************************************/
779 :
780 22 : void LANDataset::CheckForStatistics()
781 :
782 : {
783 : /* -------------------------------------------------------------------- */
784 : /* Do we have a statistics file? */
785 : /* -------------------------------------------------------------------- */
786 22 : osSTAFilename = CPLResetExtension(GetDescription(),"sta");
787 :
788 22 : VSILFILE *fpSTA = VSIFOpenL( osSTAFilename, "r" );
789 :
790 44 : if( fpSTA == NULL && VSIIsCaseSensitiveFS(osSTAFilename) )
791 : {
792 22 : osSTAFilename = CPLResetExtension(GetDescription(),"STA");
793 22 : fpSTA = VSIFOpenL( osSTAFilename, "r" );
794 : }
795 :
796 22 : if( fpSTA == NULL )
797 : {
798 22 : osSTAFilename = "";
799 22 : return;
800 : }
801 :
802 : /* -------------------------------------------------------------------- */
803 : /* Read it one band at a time. */
804 : /* -------------------------------------------------------------------- */
805 : GByte abyBandInfo[1152];
806 : int iBand;
807 :
808 0 : for( iBand = 0; iBand < nBands; iBand++ )
809 : {
810 0 : if( VSIFReadL( abyBandInfo, 1152, 1, fpSTA ) != 1 )
811 0 : break;
812 :
813 0 : int nBandNumber = abyBandInfo[7];
814 0 : GDALRasterBand *poBand = GetRasterBand(nBandNumber);
815 0 : if( poBand == NULL )
816 0 : break;
817 :
818 : float fMean, fStdDev;
819 : GInt16 nMin, nMax;
820 :
821 0 : if( poBand->GetRasterDataType() != GDT_Byte )
822 : {
823 0 : memcpy( &nMin, abyBandInfo + 28, 2 );
824 0 : memcpy( &nMax, abyBandInfo + 30, 2 );
825 : CPL_LSBPTR16( &nMin );
826 : CPL_LSBPTR16( &nMax );
827 : }
828 : else
829 : {
830 0 : nMin = abyBandInfo[9];
831 0 : nMax = abyBandInfo[8];
832 : }
833 :
834 0 : memcpy( &fMean, abyBandInfo + 12, 4 );
835 0 : memcpy( &fStdDev, abyBandInfo + 24, 4 );
836 : CPL_LSBPTR32( &fMean );
837 : CPL_LSBPTR32( &fStdDev );
838 :
839 0 : poBand->SetStatistics( nMin, nMax, fMean, fStdDev );
840 : }
841 :
842 0 : VSIFCloseL( fpSTA );
843 : }
844 :
845 : /************************************************************************/
846 : /* Create() */
847 : /************************************************************************/
848 :
849 49 : GDALDataset *LANDataset::Create( const char * pszFilename,
850 : int nXSize, int nYSize, int nBands,
851 : GDALDataType eType,
852 : char ** papszOptions )
853 :
854 : {
855 49 : if( eType != GDT_Byte && eType != GDT_Int16 )
856 : {
857 : CPLError( CE_Failure, CPLE_AppDefined,
858 : "Attempt to create .GIS file with unsupported data type '%s'.",
859 27 : GDALGetDataTypeName( eType ) );
860 27 : return NULL;
861 : }
862 :
863 : /* -------------------------------------------------------------------- */
864 : /* Try to create the file. */
865 : /* -------------------------------------------------------------------- */
866 : VSILFILE *fp;
867 :
868 22 : fp = VSIFOpenL( pszFilename, "wb" );
869 :
870 22 : if( fp == NULL )
871 : {
872 : CPLError( CE_Failure, CPLE_OpenFailed,
873 : "Attempt to create file `%s' failed.\n",
874 8 : pszFilename );
875 8 : return NULL;
876 : }
877 :
878 : /* -------------------------------------------------------------------- */
879 : /* Write out the header. */
880 : /* -------------------------------------------------------------------- */
881 : unsigned char abyHeader[128];
882 : GInt16 n16Val;
883 : GInt32 n32Val;
884 :
885 14 : memset( abyHeader, 0, sizeof(abyHeader) );
886 :
887 14 : memcpy( abyHeader + 0, "HEAD74", 6 );
888 :
889 : // Pixel type
890 14 : if( eType == GDT_Byte ) // do we want 4bit?
891 11 : n16Val = 0;
892 : else
893 3 : n16Val = 2;
894 14 : memcpy( abyHeader + 6, &n16Val, 2 );
895 :
896 : // Number of Bands.
897 14 : n16Val = (GInt16) nBands;
898 14 : memcpy( abyHeader + 8, &n16Val, 2 );
899 :
900 : // Unknown (6)
901 :
902 : // Width
903 14 : n32Val = nXSize;
904 14 : memcpy( abyHeader + 16, &n32Val, 4 );
905 :
906 : // Height
907 14 : n32Val = nYSize;
908 14 : memcpy( abyHeader + 20, &n32Val, 4 );
909 :
910 : // X Start (4)
911 : // Y Start (4)
912 :
913 : // Unknown (56)
914 :
915 : // Coordinate System
916 14 : n16Val = 0;
917 14 : memcpy( abyHeader + 88, &n16Val, 2 );
918 :
919 : // Classes in coverage
920 14 : n16Val = 0;
921 14 : memcpy( abyHeader + 90, &n16Val, 2 );
922 :
923 : // Unknown (14)
924 :
925 : // Area Unit
926 14 : n16Val = 0;
927 14 : memcpy( abyHeader + 106, &n16Val, 2 );
928 :
929 : // Pixel Area
930 : float f32Val;
931 :
932 14 : f32Val = 0.0f;
933 14 : memcpy( abyHeader + 108, &f32Val, 4 );
934 :
935 : // Upper Left X
936 14 : f32Val = 0.5f;
937 14 : memcpy( abyHeader + 112, &f32Val, 4 );
938 :
939 : // Upper Left Y
940 14 : f32Val = (float) (nYSize - 0.5);
941 14 : memcpy( abyHeader + 116, &f32Val, 4 );
942 :
943 : // width of pixel
944 14 : f32Val = 1.0f;
945 14 : memcpy( abyHeader + 120, &f32Val, 4 );
946 :
947 : // height of pixel
948 14 : f32Val = 1.0f;
949 14 : memcpy( abyHeader + 124, &f32Val, 4 );
950 :
951 14 : VSIFWriteL( abyHeader, sizeof(abyHeader), 1, fp );
952 :
953 : /* -------------------------------------------------------------------- */
954 : /* Extend the file to the target size. */
955 : /* -------------------------------------------------------------------- */
956 : vsi_l_offset nImageBytes;
957 :
958 14 : if( eType != GDT_Byte )
959 3 : nImageBytes = nXSize * (vsi_l_offset) nYSize * 2;
960 : else
961 11 : nImageBytes = nXSize * (vsi_l_offset) nYSize;
962 :
963 14 : memset( abyHeader, 0, sizeof(abyHeader) );
964 :
965 823 : while( nImageBytes > 0 )
966 : {
967 795 : vsi_l_offset nWriteThisTime = MIN(nImageBytes,sizeof(abyHeader));
968 :
969 795 : if( VSIFWriteL( abyHeader, 1, (size_t)nWriteThisTime, fp )
970 : != nWriteThisTime )
971 : {
972 0 : VSIFCloseL( fp );
973 : CPLError( CE_Failure, CPLE_FileIO,
974 0 : "Failed to write whole Istar file." );
975 0 : return NULL;
976 : }
977 795 : nImageBytes -= nWriteThisTime;
978 : }
979 :
980 14 : VSIFCloseL( fp );
981 :
982 14 : return (GDALDataset *) GDALOpen( pszFilename, GA_Update );
983 : }
984 :
985 : /************************************************************************/
986 : /* GDALRegister_LAN() */
987 : /************************************************************************/
988 :
989 582 : void GDALRegister_LAN()
990 :
991 : {
992 : GDALDriver *poDriver;
993 :
994 582 : if( GDALGetDriverByName( "LAN" ) == NULL )
995 : {
996 561 : poDriver = new GDALDriver();
997 :
998 561 : poDriver->SetDescription( "LAN" );
999 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1000 561 : "Erdas .LAN/.GIS" );
1001 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1002 561 : "frmt_various.html#LAN" );
1003 561 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1004 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1005 561 : "Byte Int16" );
1006 :
1007 561 : poDriver->pfnOpen = LANDataset::Open;
1008 561 : poDriver->pfnCreate = LANDataset::Create;
1009 :
1010 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
1011 : }
1012 582 : }
1013 :
|