ultimatepp/bazaar/plugin/gdal/frmts/ingr/IntergraphBand.cpp
cxl 23ff1e7e82 .gdal moved to bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@9273 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2015-12-07 13:36:24 +00:00

1269 lines
42 KiB
C++

/*****************************************************************************
* $Id: IntergraphBand.cpp 28053 2014-12-04 09:31:07Z rouault $
*
* Project: Intergraph Raster Format support
* Purpose: Read/Write Intergraph Raster Format, band support
* Author: Ivan Lucena, [lucena_ivan at hotmail.com]
*
******************************************************************************
* Copyright (c) 2007, Ivan Lucena
* Copyright (c) 2007-2013, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files ( the "Software" ),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#include "gdal_priv.h"
#include "cpl_conv.h"
#include "cpl_string.h"
#include "cpl_csv.h"
#include "ogr_spatialref.h"
#include "gdal_pam.h"
#include "gdal_alg.h"
#include "math.h"
#include "IntergraphDataset.h"
#include "IntergraphBand.h"
#include "IngrTypes.h"
// ----------------------------------------------------------------------------
// IntergraphRasterBand::IntergraphRasterBand()
// ----------------------------------------------------------------------------
IntergraphRasterBand::IntergraphRasterBand( IntergraphDataset *poDS,
int nBand,
int nBandOffset,
GDALDataType eType )
{
this->poColorTable = new GDALColorTable();
this->poDS = poDS;
this->nBand = nBand != 0 ? nBand : poDS->nBands;
this->nTiles = 0;
this->eDataType = eType;
this->pabyBlockBuf = NULL;
this->pahTiles = NULL;
this->nRGBIndex = 0;
this->nBandStart = nBandOffset;
this->bTiled = FALSE;
// --------------------------------------------------------------------
// Get Header Info
// --------------------------------------------------------------------
memcpy(&hHeaderOne, &poDS->hHeaderOne, sizeof(hHeaderOne));
memcpy(&hHeaderTwo, &poDS->hHeaderTwo, sizeof(hHeaderTwo));
// --------------------------------------------------------------------
// Get the image start from Words to Follow (WTF)
// --------------------------------------------------------------------
nDataOffset = nBandOffset + 2 + ( 2 * ( hHeaderOne.WordsToFollow + 1 ) );
// --------------------------------------------------------------------
// Get Color Tabel from Color Table Type (CTV)
// --------------------------------------------------------------------
uint32 nEntries = hHeaderTwo.NumberOfCTEntries;
if( nEntries > 0 )
{
switch ( hHeaderTwo.ColorTableType )
{
case EnvironVColorTable:
INGR_GetEnvironVColors( poDS->fp, nBandOffset, nEntries, poColorTable );
if (poColorTable->GetColorEntryCount() == 0)
return;
break;
case IGDSColorTable:
INGR_GetIGDSColors( poDS->fp, nBandOffset, nEntries, poColorTable );
if (poColorTable->GetColorEntryCount() == 0)
return;
break;
default:
CPLDebug( "INGR", "Wrong Color table type (%d), number of colors (%d)",
hHeaderTwo.ColorTableType, nEntries );
}
}
// --------------------------------------------------------------------
// Set Dimension
// --------------------------------------------------------------------
nRasterXSize = hHeaderOne.PixelsPerLine;
nRasterYSize = hHeaderOne.NumberOfLines;
nBlockXSize = nRasterXSize;
nBlockYSize = 1;
// --------------------------------------------------------------------
// Get tile directory
// --------------------------------------------------------------------
this->eFormat = (INGR_Format) hHeaderOne.DataTypeCode;
this->bTiled = (hHeaderOne.DataTypeCode == TiledRasterData);
if( bTiled )
{
nTiles = INGR_GetTileDirectory( poDS->fp,
nDataOffset,
nRasterXSize,
nRasterYSize,
&hTileDir,
&pahTiles );
if (nTiles == 0)
return;
eFormat = (INGR_Format) hTileDir.DataTypeCode;
// ----------------------------------------------------------------
// Set blocks dimensions based on tiles
// ----------------------------------------------------------------
nBlockXSize = hTileDir.TileSize;
nBlockYSize = hTileDir.TileSize;
}
if (nBlockXSize <= 0 || nBlockYSize <= 0)
{
pabyBlockBuf = NULL;
CPLError(CE_Failure, CPLE_AppDefined, "Invalid block dimensions");
return;
}
// --------------------------------------------------------------------
// Incomplete tiles have Block Offset greater than:
// --------------------------------------------------------------------
nFullBlocksX = ( nRasterXSize / nBlockXSize );
nFullBlocksY = ( nRasterYSize / nBlockYSize );
// --------------------------------------------------------------------
// Get the Data Type from Format
// --------------------------------------------------------------------
this->eDataType = INGR_GetDataType( (uint16) eFormat );
// --------------------------------------------------------------------
// Allocate buffer for a Block of data
// --------------------------------------------------------------------
nBlockBufSize = nBlockXSize * nBlockYSize *
GDALGetDataTypeSize( eDataType ) / 8;
if (eFormat == RunLengthEncoded)
{
pabyBlockBuf = (GByte*) VSIMalloc3( nBlockXSize*4+2, nBlockYSize,
GDALGetDataTypeSize( eDataType ) / 8);
}
else
{
pabyBlockBuf = (GByte*) VSIMalloc3( nBlockXSize, nBlockYSize,
GDALGetDataTypeSize( eDataType ) / 8);
}
if (pabyBlockBuf == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate %d bytes", nBlockBufSize);
return;
}
// --------------------------------------------------------------------
// More Metadata Information
// --------------------------------------------------------------------
SetMetadataItem( "FORMAT", INGR_GetFormatName( (uint16) eFormat ),
"IMAGE_STRUCTURE" );
if( bTiled )
{
SetMetadataItem( "TILESSIZE", CPLSPrintf ("%d", hTileDir.TileSize),
"IMAGE_STRUCTURE" );
}
else
{
SetMetadataItem( "TILED", "NO", "IMAGE_STRUCTURE" );
}
SetMetadataItem( "ORIENTATION",
INGR_GetOrientation( hHeaderOne.ScanlineOrientation ),
"IMAGE_STRUCTURE" );
if( eFormat == PackedBinary ||
eFormat == RunLengthEncoded ||
eFormat == CCITTGroup4 )
{
SetMetadataItem( "NBITS", "1", "IMAGE_STRUCTURE" );
}
this->nRLEOffset = 0;
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::~IntergraphRasterBand()
// ----------------------------------------------------------------------------
IntergraphRasterBand::~IntergraphRasterBand()
{
if( pabyBlockBuf )
{
CPLFree( pabyBlockBuf );
}
if( pahTiles )
{
CPLFree( pahTiles );
}
if( poColorTable )
{
delete poColorTable;
}
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::GetMinimum()
// ----------------------------------------------------------------------------
double IntergraphRasterBand::GetMinimum( int *pbSuccess )
{
double dMinimum = INGR_GetMinMax( eDataType, hHeaderOne.Minimum );
double dMaximum = INGR_GetMinMax( eDataType, hHeaderOne.Maximum );
if( pbSuccess )
{
*pbSuccess = dMinimum == dMaximum ? FALSE : TRUE;
}
return dMinimum;
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::GetMaximum()
// ----------------------------------------------------------------------------
double IntergraphRasterBand::GetMaximum( int *pbSuccess )
{
double dMinimum = INGR_GetMinMax( eDataType, hHeaderOne.Minimum );
double dMaximum = INGR_GetMinMax( eDataType, hHeaderOne.Maximum );
if( pbSuccess )
{
*pbSuccess = dMinimum == dMaximum ? FALSE : TRUE;
}
return dMaximum;
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::GetColorInterpretation()
// ----------------------------------------------------------------------------
GDALColorInterp IntergraphRasterBand::GetColorInterpretation()
{
if( eFormat == AdaptiveRGB ||
eFormat == Uncompressed24bit ||
eFormat == ContinuousTone )
{
switch( nRGBIndex )
{
case 1:
return GCI_RedBand;
case 2:
return GCI_GreenBand;
case 3:
return GCI_BlueBand;
}
return GCI_GrayIndex;
}
else
{
if( poColorTable->GetColorEntryCount() > 0 )
{
return GCI_PaletteIndex;
}
else
{
return GCI_GrayIndex;
}
}
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::GetColorTable()
// ----------------------------------------------------------------------------
GDALColorTable *IntergraphRasterBand::GetColorTable()
{
if( poColorTable->GetColorEntryCount() == 0 )
{
return NULL;
}
else
{
return poColorTable;
}
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::SetColorTable()
// ----------------------------------------------------------------------------
CPLErr IntergraphRasterBand::SetColorTable( GDALColorTable *poColorTable )
{
if( poColorTable == NULL )
{
return CE_None;
}
delete this->poColorTable;
this->poColorTable = poColorTable->Clone();
return CE_None;
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::SetStatistics()
// ----------------------------------------------------------------------------
CPLErr IntergraphRasterBand::SetStatistics( double dfMin,
double dfMax,
double dfMean,
double dfStdDev )
{
hHeaderOne.Minimum = INGR_SetMinMax( eDataType, dfMin );
hHeaderOne.Maximum = INGR_SetMinMax( eDataType, dfMax );
return GDALRasterBand::SetStatistics( dfMin, dfMax, dfMean, dfStdDev );
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::IReadBlock()
// ----------------------------------------------------------------------------
CPLErr IntergraphRasterBand::IReadBlock( int nBlockXOff,
int nBlockYOff,
void *pImage )
{
// --------------------------------------------------------------------
// Load Block Buffer
// --------------------------------------------------------------------
if (HandleUninstantiatedTile( nBlockXOff, nBlockYOff, pImage ))
return CE_None;
uint32 nBytesRead = LoadBlockBuf( nBlockXOff, nBlockYOff, nBlockBufSize, pabyBlockBuf );
if( nBytesRead == 0 )
{
memset( pImage, 0, nBlockXSize * nBlockYSize *
GDALGetDataTypeSize( eDataType ) / 8 );
CPLError( CE_Failure, CPLE_FileIO,
"Can't read (%s) tile with X offset %d and Y offset %d.\n",
((IntergraphDataset*)poDS)->pszFilename, nBlockXOff, nBlockYOff );
return CE_Failure;
}
// --------------------------------------------------------------------
// Reshape blocks if needed
// --------------------------------------------------------------------
if( nBlockXOff == nFullBlocksX ||
nBlockYOff == nFullBlocksY )
{
ReshapeBlock( nBlockXOff, nBlockYOff, nBlockBufSize, pabyBlockBuf );
}
// --------------------------------------------------------------------
// Copy block buffer to image
// --------------------------------------------------------------------
memcpy( pImage, pabyBlockBuf, nBlockXSize * nBlockYSize *
GDALGetDataTypeSize( eDataType ) / 8 );
#ifdef CPL_MSB
if( eDataType == GDT_Int16 || eDataType == GDT_UInt16)
GDALSwapWords( pImage, 2, nBlockXSize * nBlockYSize, 2 );
else if( eDataType == GDT_Int32 || eDataType == GDT_UInt32 || eDataType == GDT_Float32 )
GDALSwapWords( pImage, 4, nBlockXSize * nBlockYSize, 4 );
else if (eDataType == GDT_Float64 )
GDALSwapWords( pImage, 8, nBlockXSize * nBlockYSize, 8 );
#endif
return CE_None;
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::HandleUninstantiatedTile()
// ----------------------------------------------------------------------------
int IntergraphRasterBand::HandleUninstantiatedTile(int nBlockXOff,
int nBlockYOff,
void* pImage)
{
if( bTiled && pahTiles[nBlockXOff + nBlockYOff * nBlocksPerRow].Start == 0 )
{
// ------------------------------------------------------------
// Uninstantieted tile, unique value
// ------------------------------------------------------------
int nColor = pahTiles[nBlockXOff + nBlockYOff * nBlocksPerRow].Used;
switch( GetColorInterpretation() )
{
case GCI_RedBand:
nColor >>= 16; break;
case GCI_GreenBand:
nColor >>= 8; break;
default:
break;
}
memset( pImage, nColor, nBlockXSize * nBlockYSize *
GDALGetDataTypeSize( eDataType ) / 8 );
return TRUE;
}
else
return FALSE;
}
// ----------------------------------------------------------------------------
// IntergraphRGBBand::IntergraphRGBBand()
// ----------------------------------------------------------------------------
IntergraphRGBBand::IntergraphRGBBand( IntergraphDataset *poDS,
int nBand,
int nBandOffset,
int nRGorB )
: IntergraphRasterBand( poDS, nBand, nBandOffset )
{
if (pabyBlockBuf == NULL)
return;
nRGBIndex = (uint8) nRGorB;
// --------------------------------------------------------------------
// Reallocate buffer for a block of RGB Data
// --------------------------------------------------------------------
nBlockBufSize *= 3;
CPLFree( pabyBlockBuf );
pabyBlockBuf = (GByte*) VSIMalloc( nBlockBufSize );
if (pabyBlockBuf == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate %d bytes", nBlockBufSize);
}
}
// ----------------------------------------------------------------------------
// IntergraphRGBBand::IReadBlock()
// ----------------------------------------------------------------------------
CPLErr IntergraphRGBBand::IReadBlock( int nBlockXOff,
int nBlockYOff,
void *pImage )
{
if( IntergraphRasterBand::IReadBlock( nBlockXOff,
nBlockYOff,
pImage ) != CE_None )
{
return CE_Failure;
}
// --------------------------------------------------------------------
// Extract the band of interest from the block buffer
// --------------------------------------------------------------------
int i, j;
for ( i = 0, j = ( nRGBIndex - 1 );
i < ( nBlockXSize * nBlockYSize );
i++, j += 3 )
{
( (GByte*) pImage )[i] = pabyBlockBuf[j];
}
return CE_None;
}
// ----------------------------------------------------------------------------
// IntergraphRLEBand::IntergraphRLEBand()
// ----------------------------------------------------------------------------
IntergraphRLEBand::IntergraphRLEBand( IntergraphDataset *poDS,
int nBand,
int nBandOffset,
int nRGorB )
: IntergraphRasterBand( poDS, nBand, nBandOffset )
{
nRLESize = 0;
nRGBIndex = (uint8) nRGorB;
bRLEBlockLoaded = FALSE;
pabyRLEBlock = NULL;
panRLELineOffset = NULL;
if (pabyBlockBuf == NULL)
return;
if( ! this->bTiled )
{
// ------------------------------------------------------------
// Load all rows at once
// ------------------------------------------------------------
nFullBlocksX = 1;
if( eFormat == RunLengthEncodedC || eFormat == RunLengthEncoded )
{
nBlockYSize = 1;
panRLELineOffset = (uint32 *)
CPLCalloc(sizeof(uint32),nRasterYSize);
nFullBlocksY = nRasterYSize;
}
else
{
nBlockYSize = nRasterYSize;
nFullBlocksY = 1;
}
nRLESize = INGR_GetDataBlockSize( poDS->pszFilename,
hHeaderTwo.CatenatedFilePointer,
nDataOffset);
nBlockBufSize = nBlockXSize * nBlockYSize;
}
else
{
// ------------------------------------------------------------
// Find the biggest tile
// ------------------------------------------------------------
uint32 iTiles;
for( iTiles = 0; iTiles < nTiles; iTiles++)
{
nRLESize = MAX( pahTiles[iTiles].Used, nRLESize );
}
}
// ----------------------------------------------------------------
// Realocate the decompressed Buffer
// ----------------------------------------------------------------
if( eFormat == AdaptiveRGB ||
eFormat == ContinuousTone )
{
nBlockBufSize *= 3;
}
CPLFree( pabyBlockBuf );
pabyBlockBuf = (GByte*) VSIMalloc( nBlockBufSize );
if (pabyBlockBuf == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate %d bytes", nBlockBufSize);
}
// ----------------------------------------------------------------
// Create a RLE buffer
// ----------------------------------------------------------------
pabyRLEBlock = (GByte*) VSIMalloc( nRLESize );
if (pabyRLEBlock == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate %d bytes", nRLESize);
}
// ----------------------------------------------------------------
// Set a black and white Color Table
// ----------------------------------------------------------------
if( eFormat == RunLengthEncoded )
{
BlackWhiteCT( true );
}
}
// ----------------------------------------------------------------------------
// IntergraphRLEBand::IntergraphRLEBand()
// ----------------------------------------------------------------------------
IntergraphRLEBand::~IntergraphRLEBand()
{
CPLFree( pabyRLEBlock );
CPLFree( panRLELineOffset );
}
// ----------------------------------------------------------------------------
// IntergraphRLEBand::IReadBlock()
// ----------------------------------------------------------------------------
CPLErr IntergraphRLEBand::IReadBlock( int nBlockXOff,
int nBlockYOff,
void *pImage )
{
// --------------------------------------------------------------------
// Load Block Buffer
// --------------------------------------------------------------------
uint32 nBytesRead;
if( bTiled || !bRLEBlockLoaded )
{
if (HandleUninstantiatedTile( nBlockXOff, nBlockYOff, pImage ))
return CE_None;
if (!bTiled)
{
// With RLE, we want to load all of the data.
// So load (0,0) since that's the only offset that will load everything.
nBytesRead = LoadBlockBuf( 0, 0, nRLESize, pabyRLEBlock );
}
else
{
nBytesRead = LoadBlockBuf( nBlockXOff, nBlockYOff, nRLESize, pabyRLEBlock );
}
bRLEBlockLoaded = TRUE;
}
else
nBytesRead = nRLESize;
if( nBytesRead == 0 )
{
memset( pImage, 0, nBlockXSize * nBlockYSize *
GDALGetDataTypeSize( eDataType ) / 8 );
CPLError( CE_Failure, CPLE_FileIO,
"Can't read (%s) tile with X offset %d and Y offset %d.\n%s",
((IntergraphDataset*)poDS)->pszFilename, nBlockXOff, nBlockYOff,
VSIStrerror( errno ) );
return CE_Failure;
}
// ----------------------------------------------------------------
// Calculate the resulting image dimmention
// ----------------------------------------------------------------
int nVirtualXSize = nBlockXSize;
int nVirtualYSize = nBlockYSize;
if( nBlockXOff == nFullBlocksX )
{
nVirtualXSize = nRasterXSize % nBlockXSize;
}
if( nBlockYOff == nFullBlocksY )
{
nVirtualYSize = nRasterYSize % nBlockYSize;
}
// --------------------------------------------------------------------
// Decode Run Length
// --------------------------------------------------------------------
if( bTiled && eFormat == RunLengthEncoded )
{
nBytesRead =
INGR_DecodeRunLengthBitonalTiled( pabyRLEBlock, pabyBlockBuf,
nRLESize, nBlockBufSize, NULL );
}
else if( bTiled || panRLELineOffset == NULL )
{
nBytesRead = INGR_Decode( eFormat, pabyRLEBlock, pabyBlockBuf,
nRLESize, nBlockBufSize,
NULL );
}
else
{
uint32 nBytesConsumed;
// If we are missing the offset to this line, process all
// preceding lines that are not initialized.
if( nBlockYOff > 0 && panRLELineOffset[nBlockYOff] == 0 )
{
int iLine = nBlockYOff - 1;
// Find the last line that is initialized (or line 0).
while ((iLine != 0) && (panRLELineOffset[iLine] == 0))
iLine--;
for( ; iLine < nBlockYOff; iLine++ )
{
// Pass NULL as destination so that no decompression
// actually takes place.
INGR_Decode( eFormat,
pabyRLEBlock + panRLELineOffset[iLine],
NULL, nRLESize - panRLELineOffset[iLine], nBlockBufSize,
&nBytesConsumed );
if( iLine < nRasterYSize-1 )
panRLELineOffset[iLine+1] =
panRLELineOffset[iLine] + nBytesConsumed;
}
}
// Read the requested line.
nBytesRead =
INGR_Decode( eFormat,
pabyRLEBlock + panRLELineOffset[nBlockYOff],
pabyBlockBuf, nRLESize - panRLELineOffset[nBlockYOff], nBlockBufSize,
&nBytesConsumed );
if( nBlockYOff < nRasterYSize-1 )
panRLELineOffset[nBlockYOff+1] =
panRLELineOffset[nBlockYOff] + nBytesConsumed;
}
// --------------------------------------------------------------------
// Reshape blocks if needed
// --------------------------------------------------------------------
if( nBlockXOff == nFullBlocksX ||
nBlockYOff == nFullBlocksY )
{
ReshapeBlock( nBlockXOff, nBlockYOff, nBlockBufSize, pabyBlockBuf );
}
// --------------------------------------------------------------------
// Extract the band of interest from the block buffer (BIL)
// --------------------------------------------------------------------
if( eFormat == AdaptiveRGB ||
eFormat == ContinuousTone )
{
int i, j;
GByte *pabyImage = (GByte*) pImage;
j = ( nRGBIndex - 1 ) * nVirtualXSize;
for ( i = 0; i < nVirtualYSize; i++ )
{
memcpy( &pabyImage[i * nBlockXSize], &pabyBlockBuf[j], nBlockXSize );
j += ( 3 * nBlockXSize );
}
}
else
{
memcpy( pImage, pabyBlockBuf, nBlockBufSize );
}
return CE_None;
}
// ----------------------------------------------------------------------------
// IntergraphBitmapBand::IntergraphBitmapBand()
// ----------------------------------------------------------------------------
IntergraphBitmapBand::IntergraphBitmapBand( IntergraphDataset *poDS,
int nBand,
int nBandOffset,
int nRGorB )
: IntergraphRasterBand( poDS, nBand, nBandOffset, GDT_Byte )
{
nBMPSize = 0;
nRGBBand = nRGorB;
pabyBMPBlock = NULL;
if (pabyBlockBuf == NULL)
return;
if( ! this->bTiled )
{
// ------------------------------------------------------------
// Load all rows at once
// ------------------------------------------------------------
nBlockYSize = nRasterYSize;
nBMPSize = INGR_GetDataBlockSize( poDS->pszFilename,
hHeaderTwo.CatenatedFilePointer,
nDataOffset);
}
else
{
// ------------------------------------------------------------
// Find the biggest tile
// ------------------------------------------------------------
uint32 iTiles;
for( iTiles = 0; iTiles < nTiles; iTiles++)
{
nBMPSize = MAX( pahTiles[iTiles].Used, nBMPSize );
}
}
// ----------------------------------------------------------------
// Create a Bitmap buffer
// ----------------------------------------------------------------
pabyBMPBlock = (GByte*) VSIMalloc( nBMPSize );
if (pabyBMPBlock == NULL)
{
CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate %d bytes", nBMPSize);
}
// ----------------------------------------------------------------
// Set a black and white Color Table
// ----------------------------------------------------------------
if( eFormat == CCITTGroup4 )
{
BlackWhiteCT( true );
}
// ----------------------------------------------------------------
// Read JPEG Quality from Application Data
// ----------------------------------------------------------------
if( eFormat == JPEGGRAY ||
eFormat == JPEGRGB ||
eFormat == JPEGCYMK )
{
nQuality = INGR_ReadJpegQuality( poDS->fp,
hHeaderTwo.ApplicationPacketPointer,
nDataOffset );
}
}
// ----------------------------------------------------------------------------
// IntergraphBitmapBand::~IntergraphBitmapBand()
// ----------------------------------------------------------------------------
IntergraphBitmapBand::~IntergraphBitmapBand()
{
CPLFree( pabyBMPBlock );
}
// ----------------------------------------------------------------------------
// IntergraphBitmapBand::GetColorInterpretation()
// ----------------------------------------------------------------------------
GDALColorInterp IntergraphBitmapBand::GetColorInterpretation()
{
if( eFormat == JPEGRGB)
{
switch( nRGBBand )
{
case 1:
return GCI_RedBand;
case 2:
return GCI_GreenBand;
case 3:
return GCI_BlueBand;
}
return GCI_GrayIndex;
}
else
{
if( poColorTable->GetColorEntryCount() > 0 )
{
return GCI_PaletteIndex;
}
else
{
return GCI_GrayIndex;
}
}
}
// ----------------------------------------------------------------------------
// IntergraphBitmapBand::IReadBlock()
// ----------------------------------------------------------------------------
CPLErr IntergraphBitmapBand::IReadBlock( int nBlockXOff,
int nBlockYOff,
void *pImage )
{
IntergraphDataset *poGDS = ( IntergraphDataset * ) poDS;
// ----------------------------------------------------------------
// Load the block of a tile or a whole image
// ----------------------------------------------------------------
if (HandleUninstantiatedTile( nBlockXOff, nBlockYOff, pImage ))
return CE_None;
uint32 nBytesRead = LoadBlockBuf( nBlockXOff, nBlockYOff, nBMPSize, pabyBMPBlock );
if( nBytesRead == 0 )
{
memset( pImage, 0, nBlockXSize * nBlockYSize *
GDALGetDataTypeSize( eDataType ) / 8 );
CPLError( CE_Failure, CPLE_FileIO,
"Can't read (%s) tile with X offset %d and Y offset %d.\n%s",
((IntergraphDataset*)poDS)->pszFilename, nBlockXOff, nBlockYOff,
VSIStrerror( errno ) );
return CE_Failure;
}
// ----------------------------------------------------------------
// Calculate the resulting image dimmention
// ----------------------------------------------------------------
int nVirtualXSize = nBlockXSize;
int nVirtualYSize = nBlockYSize;
if( nBlockXOff == nFullBlocksX )
{
nVirtualXSize = nRasterXSize % nBlockXSize;
}
if( nBlockYOff == nFullBlocksY )
{
nVirtualYSize = nRasterYSize % nBlockYSize;
}
// ----------------------------------------------------------------
// Create an in memory small tiff file (~400K)
// ----------------------------------------------------------------
poGDS->hVirtual = INGR_CreateVirtualFile( poGDS->pszFilename,
eFormat,
nVirtualXSize,
nVirtualYSize,
hTileDir.TileSize,
nQuality,
pabyBMPBlock,
nBytesRead,
nRGBBand );
if( poGDS->hVirtual.poDS == NULL )
{
memset( pImage, 0, nBlockXSize * nBlockYSize *
GDALGetDataTypeSize( eDataType ) / 8 );
CPLError( CE_Failure, CPLE_AppDefined,
"Unable to open virtual file.\n"
"Is the GTIFF and JPEG driver available?" );
return CE_Failure;
}
// ----------------------------------------------------------------
// Read the unique block from the in memory file and release it
// ----------------------------------------------------------------
poGDS->hVirtual.poBand->RasterIO( GF_Read, 0, 0,
nVirtualXSize, nVirtualYSize, pImage,
nVirtualXSize, nVirtualYSize, GDT_Byte, 0, 0, NULL );
// --------------------------------------------------------------------
// Reshape blocks if needed
// --------------------------------------------------------------------
if( nBlockXOff == nFullBlocksX ||
nBlockYOff == nFullBlocksY )
{
ReshapeBlock( nBlockXOff, nBlockYOff, nBlockBufSize, (GByte*) pImage );
}
INGR_ReleaseVirtual( &poGDS->hVirtual );
return CE_None;
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::LoadBlockBuf()
// ----------------------------------------------------------------------------
int IntergraphRasterBand::LoadBlockBuf( int nBlockXOff,
int nBlockYOff,
int nBlobkBytes,
GByte *pabyBlock )
{
IntergraphDataset *poGDS = ( IntergraphDataset * ) poDS;
uint32 nSeekOffset = 0;
uint32 nReadSize = 0;
uint32 nBlockId = 0;
// --------------------------------------------------------------------
// Read from tiles or read from strip
// --------------------------------------------------------------------
if( bTiled )
{
nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
if( pahTiles[nBlockId].Start == 0 )
{
return 0;
}
nSeekOffset = pahTiles[nBlockId].Start + nDataOffset;
nReadSize = pahTiles[nBlockId].Used;
if( (int) nReadSize > nBlobkBytes )
{
CPLDebug( "INGR",
"LoadBlockBuf(%d,%d) - trimmed tile size from %d to %d.",
nBlockXOff, nBlockYOff,
(int) nReadSize, (int) nBlobkBytes );
nReadSize = nBlobkBytes;
}
}
else
{
nSeekOffset = nDataOffset + ( nBlockBufSize * nBlockYOff );
nReadSize = nBlobkBytes;
}
if( VSIFSeekL( poGDS->fp, nSeekOffset, SEEK_SET ) < 0 )
{
return 0;
}
return VSIFReadL( pabyBlock, 1, nReadSize, poGDS->fp );
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::ReshapeBlock()
// ----------------------------------------------------------------------------
/**
* Complete Tile with zeroes to fill up a Block
*
* ### ##000 ###### ###00
* ### => ##000 , 000000 or ###00
* ##000 000000 00000
***/
void IntergraphRasterBand::ReshapeBlock( int nBlockXOff,
int nBlockYOff,
int nBlockBytes,
GByte *pabyBlock )
{
GByte *pabyTile = (GByte*) CPLCalloc( 1, nBlockBufSize );
memcpy( pabyTile, pabyBlock, nBlockBytes );
memset( pabyBlock, 0, nBlockBytes );
int nColSize = nBlockXSize;
int nRowSize = nBlockYSize;
int nCellBytes = GDALGetDataTypeSize( eDataType ) / 8;
if( nBlockXOff + 1 == nBlocksPerRow )
{
nColSize = nRasterXSize % nBlockXSize;
}
if( nBlockYOff + 1 == nBlocksPerColumn )
{
nRowSize = nRasterYSize % nBlockYSize;
}
if( nRGBIndex > 0 )
{
nCellBytes = nCellBytes * 3;
}
for( int iRow = 0; iRow < nRowSize; iRow++ )
{
memcpy( pabyBlock + ( iRow * nCellBytes * nBlockXSize ),
pabyTile + ( iRow * nCellBytes * nColSize ),
nCellBytes * nColSize);
}
CPLFree( pabyTile );
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::IWriteBlock()
// ----------------------------------------------------------------------------
CPLErr IntergraphRasterBand::IWriteBlock( int nBlockXOff,
int nBlockYOff,
void *pImage )
{
uint32 nBlockSize = nBlockBufSize;
uint32 nBlockOffset = nBlockBufSize * nBlockYOff;
IntergraphDataset *poGDS = ( IntergraphDataset * ) poDS;
if( ( nBlockXOff == 0 ) && ( nBlockYOff == 0 ) )
{
FlushBandHeader();
}
if( nRGBIndex > 0 )
{
if( nBand > 1 )
{
VSIFSeekL( poGDS->fp, nDataOffset + ( nBlockBufSize * nBlockYOff ), SEEK_SET );
VSIFReadL( pabyBlockBuf, 1, nBlockBufSize, poGDS->fp );
}
int i, j;
for( i = 0, j = ( 3 - nRGBIndex ); i < nBlockXSize; i++, j += 3 )
{
pabyBlockBuf[j] = ( ( GByte * ) pImage )[i];
}
}
else if (eFormat == RunLengthEncoded)
{
// Series of [OFF, ON,] OFF spans.
int nLastCount = 0;
GByte *pInput = ( GByte * ) pImage;
GInt16 *pOutput = ( GInt16 * ) pabyBlockBuf;
nBlockOffset = this->nRLEOffset * 2;
int nRLECount = 0;
GByte nValue = 0; // Start with OFF spans.
for(uint32 i=0; i<nBlockBufSize; i++)
{
if (((nValue == 0) && (pInput[i] == 0)) || ((nValue == 1) && pInput[i]))
{
nLastCount++;
}
else
{
// Change of span type.
while(nLastCount>32767)
{
pOutput[nRLECount++] = CPL_LSBWORD16(32767);
pOutput[nRLECount++] = CPL_LSBWORD16(0);
nLastCount -= 32767;
}
pOutput[nRLECount++] = CPL_LSBWORD16(nLastCount);
nLastCount = 1;
nValue ^= 1;
}
}
// Output tail end of scanline
while(nLastCount>32767)
{
pOutput[nRLECount++] = CPL_LSBWORD16(32767);
pOutput[nRLECount++] = CPL_LSBWORD16(0);
nLastCount -= 32767;
}
if (nLastCount != 0)
{
pOutput[nRLECount++] = CPL_LSBWORD16(nLastCount);
nLastCount = 0;
nValue ^= 1;
}
if (nValue == 0)
pOutput[nRLECount++] = CPL_LSBWORD16(0);
this->nRLEOffset += nRLECount;
nBlockSize = nRLECount * 2;
}
else
{
memcpy( pabyBlockBuf, pImage, nBlockBufSize );
#ifdef CPL_MSB
if( eDataType == GDT_Int16 || eDataType == GDT_UInt16)
GDALSwapWords( pabyBlockBuf, 2, nBlockXSize * nBlockYSize, 2 );
else if( eDataType == GDT_Int32 || eDataType == GDT_UInt32 || eDataType == GDT_Float32 )
GDALSwapWords( pabyBlockBuf, 4, nBlockXSize * nBlockYSize, 4 );
else if (eDataType == GDT_Float64 )
GDALSwapWords( pabyBlockBuf, 8, nBlockXSize * nBlockYSize, 8 );
#endif
}
VSIFSeekL( poGDS->fp, nDataOffset + nBlockOffset, SEEK_SET );
if( ( uint32 ) VSIFWriteL( pabyBlockBuf, 1, nBlockSize, poGDS->fp ) < nBlockSize )
{
CPLError( CE_Failure, CPLE_FileIO,
"Can't write (%s) block with X offset %d and Y offset %d.\n%s",
poGDS->pszFilename, nBlockXOff, nBlockYOff, VSIStrerror( errno ) );
return CE_Failure;
}
return CE_None;
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::FlushBandHeader()
// ----------------------------------------------------------------------------
void IntergraphRasterBand::FlushBandHeader( void )
{
if( nRGBIndex > 1 )
{
return;
}
IntergraphDataset *poGDS = ( IntergraphDataset* ) poDS;
INGR_ColorTable256 hCTab;
if( poColorTable->GetColorEntryCount() > 0 )
{
hHeaderTwo.ColorTableType = IGDSColorTable;
hHeaderTwo.NumberOfCTEntries = poColorTable->GetColorEntryCount();
INGR_SetIGDSColors( poColorTable, &hCTab );
}
if( nBand > poDS->GetRasterCount() )
{
hHeaderTwo.CatenatedFilePointer = nBand *
( ( 3 * SIZEOF_HDR1 ) + ( nBlockBufSize * nRasterYSize ) );
}
VSIFSeekL( poGDS->fp, nBandStart, SEEK_SET );
GByte abyBuf[MAX(SIZEOF_HDR1,SIZEOF_CTAB)];
INGR_HeaderOneMemToDisk( &hHeaderOne, abyBuf );
VSIFWriteL( abyBuf, 1, SIZEOF_HDR1, poGDS->fp );
INGR_HeaderTwoAMemToDisk( &hHeaderTwo, abyBuf );
VSIFWriteL( abyBuf, 1, SIZEOF_HDR2_A, poGDS->fp );
unsigned int i = 0;
unsigned int n = 0;
for( i = 0; i < 256; i++ )
{
STRC2BUF( abyBuf, n, hCTab.Entry[i].v_red );
STRC2BUF( abyBuf, n, hCTab.Entry[i].v_green );
STRC2BUF( abyBuf, n, hCTab.Entry[i].v_blue );
}
VSIFWriteL( abyBuf, 1, SIZEOF_CTAB, poGDS->fp );
}
// ----------------------------------------------------------------------------
// IntergraphRasterBand::BlackWhiteCT()
// ----------------------------------------------------------------------------
void IntergraphRasterBand::BlackWhiteCT( bool bReverse )
{
GDALColorEntry oBlack;
GDALColorEntry oWhite;
oWhite.c1 = (short) 255;
oWhite.c2 = (short) 255;
oWhite.c3 = (short) 255;
oWhite.c4 = (short) 255;
oBlack.c1 = (short) 0;
oBlack.c2 = (short) 0;
oBlack.c3 = (short) 0;
oBlack.c4 = (short) 255;
if( bReverse )
{
poColorTable->SetColorEntry( 0, &oWhite );
poColorTable->SetColorEntry( 1, &oBlack );
}
else
{
poColorTable->SetColorEntry( 0, &oBlack );
poColorTable->SetColorEntry( 1, &oWhite );
}
}