1 /*****************************************************************************
2 *
3 * Project: Intergraph Raster Format support
4 * Purpose: Read/Write Intergraph Raster Format, dataset support
5 * Author: Ivan Lucena, [lucena_ivan at hotmail.com]
6 *
7 ******************************************************************************
8 * Copyright (c) 2007, Ivan Lucena
9 * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
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 "cpl_conv.h"
31 #include "cpl_csv.h"
32 #include "cpl_string.h"
33 #include "gdal_frmts.h"
34 #include "gdal_alg.h"
35 #include "gdal_pam.h"
36 #include "gdal_priv.h"
37 #include "ogr_spatialref.h"
38
39 #include "IntergraphDataset.h"
40 #include "IntergraphBand.h"
41 #include "IngrTypes.h"
42
43 CPL_CVSID("$Id: IntergraphDataset.cpp 452b07d9aa72be1d260abacca8a95367d32abc48 2021-03-08 17:45:34 +0100 Even Rouault $")
44
45 // ----------------------------------------------------------------------------
46 // IntergraphDataset::IntergraphDataset()
47 // ----------------------------------------------------------------------------
48
IntergraphDataset()49 IntergraphDataset::IntergraphDataset() :
50 fp(nullptr),
51 pszFilename(nullptr)
52 {
53 adfGeoTransform[0] = 0.0;
54 adfGeoTransform[1] = 1.0;
55 adfGeoTransform[2] = 0.0;
56 adfGeoTransform[3] = 0.0;
57 adfGeoTransform[4] = 0.0;
58 adfGeoTransform[5] = 1.0;
59
60 hVirtual.poDS = nullptr;
61 hVirtual.poBand = nullptr;
62 hVirtual.pszFileName = nullptr;
63
64 memset(&hHeaderOne, 0, sizeof(hHeaderOne));
65 memset(&hHeaderTwo, 0, sizeof(hHeaderTwo));
66 }
67
68 // ----------------------------------------------------------------------------
69 // IntergraphDataset::~IntergraphDataset()
70 // ----------------------------------------------------------------------------
71
~IntergraphDataset()72 IntergraphDataset::~IntergraphDataset()
73 {
74 FlushCache();
75
76 CPLFree( pszFilename );
77
78 if( fp != nullptr )
79 {
80 VSIFCloseL( fp );
81 }
82 }
83
84 // ----------------------------------------------------------------------------
85 // IntergraphDataset::Open()
86 // ----------------------------------------------------------------------------
87
Open(GDALOpenInfo * poOpenInfo)88 GDALDataset *IntergraphDataset::Open( GDALOpenInfo *poOpenInfo )
89 {
90 if( poOpenInfo->nHeaderBytes < 1024 || poOpenInfo->fpL == nullptr )
91 {
92 return nullptr;
93 }
94
95 // --------------------------------------------------------------------
96 // Assign Header Information
97 // --------------------------------------------------------------------
98
99 INGR_HeaderOne hHeaderOne;
100
101 INGR_HeaderOneDiskToMem( &hHeaderOne, (GByte*) poOpenInfo->pabyHeader);
102
103 // --------------------------------------------------------------------
104 // Check Header Type (HTC) Version
105 // --------------------------------------------------------------------
106
107 if( hHeaderOne.HeaderType.Version != INGR_HEADER_VERSION )
108 {
109 return nullptr;
110 }
111
112 // --------------------------------------------------------------------
113 // Check Header Type (HTC) 2D / 3D Flag
114 // --------------------------------------------------------------------
115
116 if( ( hHeaderOne.HeaderType.Is2Dor3D != INGR_HEADER_2D ) &&
117 ( hHeaderOne.HeaderType.Is2Dor3D != INGR_HEADER_3D ) )
118 {
119 return nullptr;
120 }
121
122 // --------------------------------------------------------------------
123 // Check Header Type (HTC) Type Flag
124 // --------------------------------------------------------------------
125
126 if( hHeaderOne.HeaderType.Type != INGR_HEADER_TYPE )
127 {
128 return nullptr;
129 }
130
131 // --------------------------------------------------------------------
132 // Check Grid File Version (VER)
133 // --------------------------------------------------------------------
134
135 if( hHeaderOne.GridFileVersion != 1 &&
136 hHeaderOne.GridFileVersion != 2 &&
137 hHeaderOne.GridFileVersion != 3 )
138 {
139 return nullptr;
140 }
141
142 // --------------------------------------------------------------------
143 // Check Words To Follow (WTC) Minimum Value
144 // --------------------------------------------------------------------
145
146 if( hHeaderOne.WordsToFollow < 254 )
147 {
148 return nullptr;
149 }
150
151 // --------------------------------------------------------------------
152 // Check Words To Follow (WTC) Integrity
153 // --------------------------------------------------------------------
154
155 float fHeaderBlocks = (float) ( hHeaderOne.WordsToFollow + 2 ) / 256;
156
157 if( ( fHeaderBlocks - (int) fHeaderBlocks ) != 0.0 )
158 {
159 return nullptr;
160 }
161
162 if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("INGR") )
163 return nullptr;
164
165 // --------------------------------------------------------------------
166 // Get Data Type Code (DTC) => Format Type
167 // --------------------------------------------------------------------
168
169 int eFormatUntyped = hHeaderOne.DataTypeCode;
170
171 // --------------------------------------------------------------------
172 // We need to scan around the file, so we open it now.
173 // --------------------------------------------------------------------
174
175 VSILFILE *fp = poOpenInfo->fpL;
176 poOpenInfo->fpL = nullptr;
177
178 // --------------------------------------------------------------------
179 // Get Format Type from the tile directory
180 // --------------------------------------------------------------------
181
182 if( eFormatUntyped == TiledRasterData )
183 {
184 INGR_TileHeader hTileDir;
185
186 int nOffset = 2 + ( 2 * ( hHeaderOne.WordsToFollow + 1 ) );
187
188 GByte abyBuffer[SIZEOF_TDIR];
189
190 if( (VSIFSeekL( fp, nOffset, SEEK_SET ) == -1 ) ||
191 (VSIFReadL( abyBuffer, 1, SIZEOF_TDIR, fp ) == 0) )
192 {
193 VSIFCloseL( fp );
194 CPLError( CE_Failure, CPLE_AppDefined,
195 "Error reading tiles header" );
196 return nullptr;
197 }
198
199 INGR_TileHeaderDiskToMem( &hTileDir, abyBuffer );
200
201 if( !
202 ( hTileDir.ApplicationType == 1 &&
203 hTileDir.SubTypeCode == 7 &&
204 //( hTileDir.WordsToFollow % 4 ) == 0 &&
205 hTileDir.PacketVersion == 1 &&
206 hTileDir.Identifier == 1 ) )
207 {
208 CPLError( CE_Failure, CPLE_AppDefined,
209 "Cannot recognize tiles header info");
210 VSIFCloseL( fp );
211 return nullptr;
212 }
213
214 eFormatUntyped = hTileDir.DataTypeCode;
215 }
216
217 // --------------------------------------------------------------------
218 // Check Scannable Flag
219 // --------------------------------------------------------------------
220 /*
221 if (hHeaderOne.ScannableFlag == HasLineHeader)
222 {
223 CPLError( CE_Failure, CPLE_AppDefined,
224 "Intergraph Raster Scannable Line Header not supported yet" );
225 VSIFCloseL( fp );
226 return NULL;
227 }
228 */
229 // --------------------------------------------------------------------
230 // Check supported Format Type
231 // --------------------------------------------------------------------
232
233 if( eFormatUntyped != ByteInteger &&
234 eFormatUntyped != WordIntegers &&
235 eFormatUntyped != Integers32Bit &&
236 eFormatUntyped != FloatingPoint32Bit &&
237 eFormatUntyped != FloatingPoint64Bit &&
238 eFormatUntyped != RunLengthEncoded &&
239 eFormatUntyped != RunLengthEncodedC &&
240 eFormatUntyped != CCITTGroup4 &&
241 eFormatUntyped != AdaptiveRGB &&
242 eFormatUntyped != Uncompressed24bit &&
243 eFormatUntyped != AdaptiveGrayScale &&
244 eFormatUntyped != ContinuousTone &&
245 eFormatUntyped != JPEGGRAY &&
246 eFormatUntyped != JPEGRGB &&
247 eFormatUntyped != JPEGCMYK )
248 {
249 CPLError( CE_Failure, CPLE_AppDefined,
250 "Intergraph Raster Format %d not supported",
251 eFormatUntyped );
252 VSIFCloseL( fp );
253 return nullptr;
254 }
255
256 // -----------------------------------------------------------------
257 // Create a corresponding GDALDataset
258 // -----------------------------------------------------------------
259
260 IntergraphDataset *poDS = new IntergraphDataset();
261 poDS->eAccess = poOpenInfo->eAccess;
262 poDS->pszFilename = CPLStrdup( poOpenInfo->pszFilename );
263 poDS->fp = fp;
264
265 // --------------------------------------------------------------------
266 // Get X Size from Pixels Per Line (PPL)
267 // --------------------------------------------------------------------
268
269 poDS->nRasterXSize = hHeaderOne.PixelsPerLine;
270
271 // --------------------------------------------------------------------
272 // Get Y Size from Number of Lines (NOL)
273 // --------------------------------------------------------------------
274
275 poDS->nRasterYSize = hHeaderOne.NumberOfLines;
276
277 if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0)
278 {
279 CPLError( CE_Failure, CPLE_AppDefined,
280 "Invalid dimensions : %d x %d",
281 poDS->nRasterXSize, poDS->nRasterYSize);
282 delete poDS;
283 return nullptr;
284 }
285
286 // --------------------------------------------------------------------
287 // Get Geo Transformation from Homogeneous Transformation Matrix (TRN)
288 // --------------------------------------------------------------------
289
290 INGR_GetTransMatrix( &hHeaderOne, poDS->adfGeoTransform );
291
292 // --------------------------------------------------------------------
293 // Set Metadata Information
294 // --------------------------------------------------------------------
295
296 poDS->SetMetadataItem( "VERSION",
297 CPLSPrintf ( "%d", hHeaderOne.GridFileVersion ), "IMAGE_STRUCTURE" );
298 poDS->SetMetadataItem( "RESOLUTION",
299 CPLSPrintf ( "%d", (hHeaderOne.DeviceResolution < 0)?-hHeaderOne.DeviceResolution:1) );
300
301 // --------------------------------------------------------------------
302 // Create Band Information
303 // --------------------------------------------------------------------
304
305 int nBands = 0;
306 int nBandOffset = 0;
307
308 GByte abyBuf[MAX(SIZEOF_HDR1,SIZEOF_HDR2_A)];
309
310 do
311 {
312 VSIFSeekL( poDS->fp, nBandOffset, SEEK_SET );
313
314 if( VSIFReadL( abyBuf, 1, SIZEOF_HDR1, poDS->fp ) != SIZEOF_HDR1 )
315 break;
316
317 INGR_HeaderOneDiskToMem( &poDS->hHeaderOne, abyBuf );
318 if( hHeaderOne.PixelsPerLine != poDS->hHeaderOne.PixelsPerLine ||
319 hHeaderOne.NumberOfLines != poDS->hHeaderOne.NumberOfLines )
320 {
321 CPLError(CE_Failure, CPLE_NotSupported,
322 "Not all bands have same dimensions");
323 delete poDS;
324 return nullptr;
325 }
326
327 if( VSIFReadL( abyBuf, 1, SIZEOF_HDR2_A, poDS->fp ) != SIZEOF_HDR2_A )
328 break;
329
330 INGR_HeaderTwoADiskToMem( &poDS->hHeaderTwo, abyBuf );
331
332 switch( static_cast<INGR_Format>(eFormatUntyped) )
333 {
334 case JPEGRGB:
335 case JPEGCMYK:
336 {
337 IntergraphBitmapBand* poBand = nullptr;
338 nBands++;
339 poDS->SetBand( nBands,
340 poBand = new IntergraphBitmapBand( poDS, nBands, nBandOffset, 1 ));
341 if (poBand->pabyBMPBlock == nullptr)
342 {
343 delete poDS;
344 return nullptr;
345 }
346 nBands++;
347 poDS->SetBand( nBands,
348 poBand = new IntergraphBitmapBand( poDS, nBands, nBandOffset, 2 ));
349 if (poBand->pabyBMPBlock == nullptr)
350 {
351 delete poDS;
352 return nullptr;
353 }
354 nBands++;
355 poDS->SetBand( nBands,
356 poBand = new IntergraphBitmapBand( poDS, nBands, nBandOffset, 3 ));
357 if (poBand->pabyBMPBlock == nullptr)
358 {
359 delete poDS;
360 return nullptr;
361 }
362 break;
363 }
364 case JPEGGRAY:
365 case CCITTGroup4:
366 {
367 IntergraphBitmapBand* poBand = nullptr;
368 nBands++;
369 poDS->SetBand( nBands,
370 poBand = new IntergraphBitmapBand( poDS, nBands, nBandOffset ));
371 if (poBand->pabyBMPBlock == nullptr)
372 {
373 delete poDS;
374 return nullptr;
375 }
376 break;
377 }
378 case RunLengthEncoded:
379 case RunLengthEncodedC:
380 case AdaptiveGrayScale:
381 {
382 IntergraphRLEBand* poBand = nullptr;
383 nBands++;
384 poDS->SetBand( nBands,
385 poBand = new IntergraphRLEBand( poDS, nBands, nBandOffset ));
386 if (poBand->pabyBlockBuf == nullptr || poBand->pabyRLEBlock == nullptr)
387 {
388 delete poDS;
389 return nullptr;
390 }
391 break;
392 }
393 case AdaptiveRGB:
394 case ContinuousTone:
395 {
396 IntergraphRLEBand* poBand = nullptr;
397 nBands++;
398 poDS->SetBand( nBands,
399 poBand = new IntergraphRLEBand( poDS, nBands, nBandOffset, 1 ));
400 if (poBand->pabyBlockBuf == nullptr || poBand->pabyRLEBlock == nullptr)
401 {
402 delete poDS;
403 return nullptr;
404 }
405 nBands++;
406 poDS->SetBand( nBands,
407 poBand = new IntergraphRLEBand( poDS, nBands, nBandOffset, 2 ));
408 if (poBand->pabyBlockBuf == nullptr || poBand->pabyRLEBlock == nullptr)
409 {
410 delete poDS;
411 return nullptr;
412 }
413 nBands++;
414 poDS->SetBand( nBands,
415 poBand = new IntergraphRLEBand( poDS, nBands, nBandOffset, 3 ));
416 if (poBand->pabyBlockBuf == nullptr || poBand->pabyRLEBlock == nullptr)
417 {
418 delete poDS;
419 return nullptr;
420 }
421 break;
422 }
423 case Uncompressed24bit:
424 {
425 IntergraphRGBBand* poBand = nullptr;
426 nBands++;
427 poDS->SetBand( nBands,
428 poBand = new IntergraphRGBBand( poDS, nBands, nBandOffset, 1 ));
429 if (poBand->pabyBlockBuf == nullptr)
430 {
431 delete poDS;
432 return nullptr;
433 }
434 nBands++;
435 poDS->SetBand( nBands,
436 poBand = new IntergraphRGBBand( poDS, nBands, nBandOffset, 2 ));
437 if (poBand->pabyBlockBuf == nullptr)
438 {
439 delete poDS;
440 return nullptr;
441 }
442 nBands++;
443 poDS->SetBand( nBands,
444 poBand = new IntergraphRGBBand( poDS, nBands, nBandOffset, 3 ));
445 if (poBand->pabyBlockBuf == nullptr)
446 {
447 delete poDS;
448 return nullptr;
449 }
450 break;
451 }
452 default:
453 {
454 IntergraphRasterBand* poBand = nullptr;
455 nBands++;
456 poDS->SetBand( nBands,
457 poBand = new IntergraphRasterBand( poDS, nBands, nBandOffset ));
458 if (poBand->pabyBlockBuf == nullptr)
459 {
460 delete poDS;
461 return nullptr;
462 }
463 }
464 }
465
466 // ----------------------------------------------------------------
467 // Get next band offset from Catenated File Pointer (CFP)
468 // ----------------------------------------------------------------
469
470 nBandOffset = poDS->hHeaderTwo.CatenatedFilePointer;
471 }
472 while( nBandOffset != 0 && GDALCheckBandCount(nBands, false) );
473
474 poDS->nBands = nBands;
475
476 // --------------------------------------------------------------------
477 // Initialize any PAM information
478 // --------------------------------------------------------------------
479
480 poDS->SetDescription( poOpenInfo->pszFilename );
481 poDS->TryLoadXML();
482
483 /* --------------------------------------------------------------------*/
484 /* Check for external overviews. */
485 /* --------------------------------------------------------------------*/
486
487 poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
488
489 return poDS;
490 }
491
492 // ----------------------------------------------------------------------------
493 // IntergraphDataset::Create()
494 // ----------------------------------------------------------------------------
495
Create(const char * pszFilename,int nXSize,int nYSize,int nBands,GDALDataType eType,char ** papszOptions)496 GDALDataset *IntergraphDataset::Create( const char *pszFilename,
497 int nXSize,
498 int nYSize,
499 int nBands,
500 GDALDataType eType,
501 char **papszOptions )
502 {
503 if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("INGR") )
504 return nullptr;
505
506 int nDeviceResolution = 1;
507
508 const char *pszValue = CSLFetchNameValue(papszOptions, "RESOLUTION");
509 if( pszValue != nullptr )
510 nDeviceResolution = -atoi( pszValue );
511
512 char *pszExtension = CPLStrlwr(CPLStrdup(CPLGetExtension(pszFilename)));
513 const char *pszCompression = nullptr;
514 if ( EQUAL( pszExtension, "rle" ) )
515 pszCompression = INGR_GetFormatName(RunLengthEncoded);
516 CPLFree(pszExtension);
517
518 if( eType != GDT_Byte &&
519 eType != GDT_Int16 &&
520 eType != GDT_Int32 &&
521 eType != GDT_UInt16 &&
522 eType != GDT_UInt32 &&
523 eType != GDT_Float32&&
524 eType != GDT_Float64 )
525 {
526 CPLError( CE_Failure, CPLE_AppDefined, "Data type not supported (%s)",
527 GDALGetDataTypeName( eType ) );
528 return nullptr;
529 }
530
531 // --------------------------------------------------------------------
532 // Fill headers with minimum information
533 // --------------------------------------------------------------------
534
535 INGR_HeaderOne hHdr1;
536 INGR_HeaderTwoA hHdr2;
537 INGR_ColorTable256 hCTab;
538
539 memset(&hHdr1, 0, sizeof(hHdr1));
540 memset(&hHdr2, 0, sizeof(hHdr2));
541 memset(&hCTab, 0, sizeof(hCTab));
542
543 hHdr1.HeaderType.Version = INGR_HEADER_VERSION;
544 hHdr1.HeaderType.Type = INGR_HEADER_TYPE;
545 hHdr1.HeaderType.Is2Dor3D = INGR_HEADER_2D;
546 hHdr1.DataTypeCode = (uint16_t) INGR_GetFormat( eType, (pszCompression!=nullptr)?pszCompression:"None" );
547 hHdr1.WordsToFollow = ( ( SIZEOF_HDR1 * 3 ) / 2 ) - 2;
548 hHdr1.ApplicationType = GenericRasterImageFile;
549 hHdr1.XViewOrigin = 0.0;
550 hHdr1.YViewOrigin = 0.0;
551 hHdr1.ZViewOrigin = 0.0;
552 hHdr1.XViewExtent = 0.0;
553 hHdr1.YViewExtent = 0.0;
554 hHdr1.ZViewExtent = 0.0;
555 for( int i = 0; i < 15; i++ )
556 hHdr1.TransformationMatrix[i] = 0.0;
557 hHdr1.TransformationMatrix[15] = 1.0;
558 hHdr1.PixelsPerLine = nXSize;
559 hHdr1.NumberOfLines = nYSize;
560 hHdr1.DeviceResolution = static_cast<int16_t>(nDeviceResolution);
561 hHdr1.ScanlineOrientation = UpperLeftHorizontal;
562 hHdr1.ScannableFlag = NoLineHeader;
563 hHdr1.RotationAngle = 0.0;
564 hHdr1.SkewAngle = 0.0;
565 hHdr1.DataTypeModifier = 0;
566 hHdr1.DesignFileName[0] = '\0';
567 hHdr1.DataBaseFileName[0] = '\0';
568 hHdr1.ParentGridFileName[0] = '\0';
569 hHdr1.FileDescription[0] = '\0';
570 hHdr1.Minimum = INGR_SetMinMax( eType, 0.0 );
571 hHdr1.Maximum = INGR_SetMinMax( eType, 0.0 );
572 hHdr1.GridFileVersion = 3;
573 hHdr1.Reserved[0] = 0;
574 hHdr1.Reserved[1] = 0;
575 hHdr1.Reserved[2] = 0;
576 hHdr2.Gain = 0;
577 hHdr2.OffsetThreshold = 0;
578 hHdr2.View1 = 0;
579 hHdr2.View2 = 0;
580 hHdr2.ViewNumber = 0;
581 hHdr2.Reserved2 = 0;
582 hHdr2.Reserved3 = 0;
583 hHdr2.AspectRatio = nXSize / nYSize;
584 hHdr2.CatenatedFilePointer = 0;
585 hHdr2.ColorTableType = NoColorTable;
586 hHdr2.NumberOfCTEntries = 0;
587 hHdr2.Reserved8 = 0;
588 for( int i = 0; i < 110; i++ )
589 hHdr2.Reserved[i] = 0;
590 hHdr2.ApplicationPacketLength = 0;
591 hHdr2.ApplicationPacketPointer = 0;
592
593 // --------------------------------------------------------------------
594 // RGB Composite assumption
595 // --------------------------------------------------------------------
596
597 if( eType == GDT_Byte &&
598 nBands == 3 )
599 {
600 hHdr1.DataTypeCode = Uncompressed24bit;
601 }
602
603 // --------------------------------------------------------------------
604 // Create output file with minimum header info
605 // --------------------------------------------------------------------
606
607 VSILFILE *fp = VSIFOpenL( pszFilename, "wb+" );
608
609 if( fp == nullptr )
610 {
611 CPLError( CE_Failure, CPLE_OpenFailed,
612 "Attempt to create file %s' failed.\n", pszFilename );
613 return nullptr;
614 }
615
616 GByte abyBuf[MAX(SIZEOF_HDR1,SIZEOF_CTAB)];
617
618 INGR_HeaderOneMemToDisk( &hHdr1, abyBuf );
619
620 VSIFWriteL( abyBuf, 1, SIZEOF_HDR1, fp );
621
622 INGR_HeaderTwoAMemToDisk( &hHdr2, abyBuf );
623
624 VSIFWriteL( abyBuf, 1, SIZEOF_HDR2_A, fp );
625
626 unsigned int n = 0;
627
628 for( int i = 0; i < 256; i++ )
629 {
630 STRC2BUF( abyBuf, n, hCTab.Entry[i].v_red );
631 STRC2BUF( abyBuf, n, hCTab.Entry[i].v_green );
632 STRC2BUF( abyBuf, n, hCTab.Entry[i].v_blue );
633 }
634
635 VSIFWriteL( abyBuf, 1, SIZEOF_CTAB, fp );
636
637 VSIFCloseL( fp );
638
639 // --------------------------------------------------------------------
640 // Returns a new IntergraphDataset from the created file
641 // --------------------------------------------------------------------
642
643 return ( IntergraphDataset * ) GDALOpen( pszFilename, GA_Update );
644 }
645
646 // ----------------------------------------------------------------------------
647 // IntergraphDataset::CreateCopy()
648 // ----------------------------------------------------------------------------
649
CreateCopy(const char * pszFilename,GDALDataset * poSrcDS,int,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressData)650 GDALDataset *IntergraphDataset::CreateCopy( const char *pszFilename,
651 GDALDataset *poSrcDS,
652 int /* bStrict */ ,
653 char **papszOptions,
654 GDALProgressFunc pfnProgress,
655 void *pProgressData )
656 {
657 if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("INGR") )
658 return nullptr;
659
660 int nBands = poSrcDS->GetRasterCount();
661 if (nBands == 0)
662 {
663 CPLError( CE_Failure, CPLE_NotSupported,
664 "Intergraph driver does not support source dataset with zero band.\n");
665 return nullptr;
666 }
667
668 if( !pfnProgress( 0.0, nullptr, pProgressData ) )
669 {
670 return nullptr;
671 }
672
673 // --------------------------------------------------------------------
674 // Query GDAL Data Type
675 // --------------------------------------------------------------------
676
677 GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
678
679 // --------------------------------------------------------------------
680 // Copy metadata
681 // --------------------------------------------------------------------
682
683 char **papszCreateOptions = CSLDuplicate( papszOptions );
684 const char *pszValue = CSLFetchNameValue(papszCreateOptions, "RESOLUTION");
685 if( pszValue == nullptr )
686 {
687 const char *value = poSrcDS->GetMetadataItem("RESOLUTION");
688 if (value)
689 {
690 papszCreateOptions = CSLSetNameValue( papszCreateOptions, "RESOLUTION",
691 value );
692 }
693 }
694
695 // --------------------------------------------------------------------
696 // Create IntergraphDataset
697 // --------------------------------------------------------------------
698
699 IntergraphDataset *poDstDS
700 = (IntergraphDataset*) IntergraphDataset::Create( pszFilename,
701 poSrcDS->GetRasterXSize(),
702 poSrcDS->GetRasterYSize(),
703 poSrcDS->GetRasterCount(),
704 eType,
705 papszCreateOptions );
706
707 CSLDestroy( papszCreateOptions );
708
709 if( poDstDS == nullptr )
710 {
711 return nullptr;
712 }
713
714 // --------------------------------------------------------------------
715 // Copy Transformation Matrix to the dataset
716 // --------------------------------------------------------------------
717
718 double adfGeoTransform[6];
719
720 poDstDS->SetSpatialRef( poSrcDS->GetSpatialRef() );
721 poSrcDS->GetGeoTransform( adfGeoTransform );
722 poDstDS->SetGeoTransform( adfGeoTransform );
723
724 // --------------------------------------------------------------------
725 // Copy information to the raster band
726 // --------------------------------------------------------------------
727
728 double dfMin;
729 double dfMax;
730 double dfMean;
731 double dfStdDev = -1;
732
733 for( int i = 1; i <= poDstDS->nBands; i++)
734 {
735 delete poDstDS->GetRasterBand(i);
736 }
737 poDstDS->nBands = 0;
738
739 if( poDstDS->hHeaderOne.DataTypeCode == Uncompressed24bit )
740 {
741 poDstDS->SetBand( 1, new IntergraphRGBBand( poDstDS, 1, 0, 3 ) );
742 poDstDS->SetBand( 2, new IntergraphRGBBand( poDstDS, 2, 0, 2 ) );
743 poDstDS->SetBand( 3, new IntergraphRGBBand( poDstDS, 3, 0, 1 ) );
744 poDstDS->nBands = 3;
745 }
746 else
747 {
748 for( int i = 1; i <= poSrcDS->GetRasterCount(); i++ )
749 {
750 GDALRasterBand* poSrcBand = poSrcDS->GetRasterBand(i);
751 eType = poSrcDS->GetRasterBand(i)->GetRasterDataType();
752
753 GDALRasterBand* poDstBand = new IntergraphRasterBand( poDstDS, i, 0, eType );
754 poDstDS->SetBand( i, poDstBand );
755
756 poDstBand->SetCategoryNames( poSrcBand->GetCategoryNames() );
757 poDstBand->SetColorTable( poSrcBand->GetColorTable() );
758 poSrcBand->GetStatistics( false, true, &dfMin, &dfMax, &dfMean, &dfStdDev );
759 poDstBand->SetStatistics( dfMin, dfMax, dfMean, dfStdDev );
760 }
761 }
762
763 // --------------------------------------------------------------------
764 // Copy image data
765 // --------------------------------------------------------------------
766
767 int nXSize = poDstDS->GetRasterXSize();
768 int nYSize = poDstDS->GetRasterYSize();
769
770 for( int iBand = 1; iBand <= poSrcDS->GetRasterCount(); iBand++ )
771 {
772 GDALRasterBand *poDstBand = poDstDS->GetRasterBand( iBand );
773 GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand );
774
775 // ------------------------------------------------------------
776 // Copy Untiled / Uncompressed
777 // ------------------------------------------------------------
778
779 int nBlockXSize;
780 int nBlockYSize;
781
782 poSrcBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
783
784 // TODO: Is this correct? It appears to overwrite the block sizes.
785 nBlockXSize = nXSize;
786 nBlockYSize = 1;
787
788 void *pData
789 = CPLMalloc( nBlockXSize * nBlockYSize
790 * GDALGetDataTypeSize( eType ) / 8 );
791
792 for( int iYOffset = 0; iYOffset < nYSize; iYOffset += nBlockYSize )
793 {
794 CPLErr eErr = CE_None;
795 for( int iXOffset = 0; iXOffset < nXSize; iXOffset += nBlockXSize )
796 {
797 eErr = poSrcBand->RasterIO( GF_Read,
798 iXOffset, iYOffset,
799 nBlockXSize, nBlockYSize,
800 pData, nBlockXSize, nBlockYSize,
801 eType, 0, 0, nullptr );
802 if( eErr != CE_None )
803 {
804 CPLFree( pData );
805 delete poDstDS;
806 return nullptr;
807 }
808 eErr = poDstBand->RasterIO( GF_Write,
809 iXOffset, iYOffset,
810 nBlockXSize, nBlockYSize,
811 pData, nBlockXSize, nBlockYSize,
812 eType, 0, 0, nullptr );
813 if( eErr != CE_None )
814 {
815 CPLFree( pData );
816 delete poDstDS;
817 return nullptr;
818 }
819 }
820 if( ( eErr == CE_None ) && ( ! pfnProgress(
821 ( iYOffset + 1 ) / ( double ) nYSize, nullptr, pProgressData ) ) )
822 {
823 CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated CreateCopy()" );
824 CPLFree( pData );
825 delete poDstDS;
826 return nullptr;
827 }
828 }
829 CPLFree( pData );
830 }
831
832 // --------------------------------------------------------------------
833 // Finalize
834 // --------------------------------------------------------------------
835
836 poDstDS->FlushCache();
837
838 return poDstDS;
839 }
840
841 // ----------------------------------------------------------------------------
842 // IntergraphDataset::GetGeoTransform()
843 // ----------------------------------------------------------------------------
844
GetGeoTransform(double * padfTransform)845 CPLErr IntergraphDataset::GetGeoTransform( double *padfTransform )
846 {
847 if( GDALPamDataset::GetGeoTransform( padfTransform ) != CE_None )
848 {
849 memcpy( padfTransform, adfGeoTransform, sizeof( double ) * 6 );
850 }
851
852 return CE_None;
853 }
854
855 // ----------------------------------------------------------------------------
856 // IntergraphDataset::SetGeoTransform()
857 // ----------------------------------------------------------------------------
858
SetGeoTransform(double * padfTransform)859 CPLErr IntergraphDataset::SetGeoTransform( double *padfTransform )
860 {
861 if( GDALPamDataset::SetGeoTransform( padfTransform ) != CE_None )
862 {
863 memcpy( adfGeoTransform, padfTransform, sizeof( double ) * 6 );
864 }
865
866 INGR_SetTransMatrix( hHeaderOne.TransformationMatrix, padfTransform );
867
868 return CE_None;
869 }
870
871 // ----------------------------------------------------------------------------
872 // IntergraphDataset::_SetProjection()
873 // ----------------------------------------------------------------------------
874
_SetProjection(const char *)875 CPLErr IntergraphDataset::_SetProjection( const char * /* pszProjString */ )
876 {
877 return CE_None;
878 }
879
880 // ----------------------------------------------------------------------------
881 // GDALRegister_INGR()
882 // ----------------------------------------------------------------------------
883
GDALRegister_INGR()884 void GDALRegister_INGR()
885 {
886 if( GDALGetDriverByName( "INGR" ) != nullptr )
887 return;
888
889 GDALDriver *poDriver = new GDALDriver();
890
891 poDriver->SetDescription( "INGR" );
892 poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
893 poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "Intergraph Raster" );
894 poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
895 "drivers/raster/intergraphraster.html" );
896 poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
897 poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
898 "Byte Int16 Int32 Float32 Float64" );
899
900 poDriver->pfnOpen = IntergraphDataset::Open;
901 poDriver->pfnCreate = IntergraphDataset::Create;
902 poDriver->pfnCreateCopy = IntergraphDataset::CreateCopy;
903
904 GetGDALDriverManager()->RegisterDriver( poDriver );
905 }
906