mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-19 14:15:21 -06:00
654 lines
23 KiB
C++
654 lines
23 KiB
C++
/******************************************************************************
|
|
* $Id: xpmdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $
|
|
*
|
|
* Project: XPM Driver
|
|
* Purpose: Implement GDAL XPM Support
|
|
* Author: Frank Warmerdam, warmerdam@pobox.com
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2002, Frank Warmerdam
|
|
* Copyright (c) 2008-2010, 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_pam.h"
|
|
#include "cpl_string.h"
|
|
#include "memdataset.h"
|
|
#include "gdal_frmts.h"
|
|
|
|
|
|
CPL_CVSID("$Id: xpmdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $");
|
|
|
|
static unsigned char *ParseXPM( const char *pszInput,
|
|
int *pnXSize, int *pnYSize,
|
|
GDALColorTable **ppoRetTable );
|
|
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* XPMDataset */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
class XPMDataset : public GDALPamDataset
|
|
{
|
|
public:
|
|
XPMDataset();
|
|
~XPMDataset();
|
|
|
|
static GDALDataset *Open( GDALOpenInfo * );
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* XPMDataset() */
|
|
/************************************************************************/
|
|
|
|
XPMDataset::XPMDataset()
|
|
|
|
{
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~XPMDataset() */
|
|
/************************************************************************/
|
|
|
|
XPMDataset::~XPMDataset()
|
|
|
|
{
|
|
FlushCache();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Open() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset *XPMDataset::Open( GDALOpenInfo * poOpenInfo )
|
|
|
|
{
|
|
/* -------------------------------------------------------------------- */
|
|
/* First we check to see if the file has the expected header */
|
|
/* bytes. For now we expect the XPM file to start with a line */
|
|
/* containing the letters XPM, and to have "static" in the */
|
|
/* header. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( poOpenInfo->nHeaderBytes < 32
|
|
|| strstr((const char *) poOpenInfo->pabyHeader,"XPM") == NULL
|
|
|| strstr((const char *) poOpenInfo->pabyHeader,"static") == NULL )
|
|
return NULL;
|
|
|
|
if( poOpenInfo->eAccess == GA_Update )
|
|
{
|
|
CPLError( CE_Failure, CPLE_NotSupported,
|
|
"The XPM driver does not support update access to existing"
|
|
" files." );
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Read the whole file into a memory strings. */
|
|
/* -------------------------------------------------------------------- */
|
|
unsigned int nFileSize;
|
|
char *pszFileContents;
|
|
VSILFILE *fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
|
|
if( fp == NULL )
|
|
return NULL;
|
|
|
|
VSIFSeekL( fp, 0, SEEK_END );
|
|
nFileSize = (unsigned int) VSIFTellL( fp );
|
|
|
|
pszFileContents = (char *) VSIMalloc(nFileSize+1);
|
|
if( pszFileContents == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_OutOfMemory,
|
|
"Insufficient memory for loading XPM file %s into memory.",
|
|
poOpenInfo->pszFilename );
|
|
VSIFCloseL(fp);
|
|
return NULL;
|
|
}
|
|
pszFileContents[nFileSize] = '\0';
|
|
|
|
VSIFSeekL( fp, 0, SEEK_SET );
|
|
|
|
if( VSIFReadL( pszFileContents, 1, nFileSize, fp ) != nFileSize)
|
|
{
|
|
CPLFree( pszFileContents );
|
|
CPLError( CE_Failure, CPLE_FileIO,
|
|
"Failed to read all %d bytes from file %s.",
|
|
nFileSize, poOpenInfo->pszFilename );
|
|
VSIFCloseL(fp);
|
|
return NULL;
|
|
}
|
|
|
|
VSIFCloseL(fp);
|
|
fp = NULL;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Convert into a binary image. */
|
|
/* -------------------------------------------------------------------- */
|
|
GByte *pabyImage;
|
|
int nXSize, nYSize;
|
|
GDALColorTable *poCT = NULL;
|
|
|
|
CPLErrorReset();
|
|
|
|
pabyImage = ParseXPM( pszFileContents, &nXSize, &nYSize, &poCT );
|
|
CPLFree( pszFileContents );
|
|
|
|
if( pabyImage == NULL )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create a corresponding GDALDataset. */
|
|
/* -------------------------------------------------------------------- */
|
|
XPMDataset *poDS;
|
|
|
|
poDS = new XPMDataset();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Capture some information from the file that is of interest. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->nRasterXSize = nXSize;
|
|
poDS->nRasterYSize = nYSize;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create band information objects. */
|
|
/* -------------------------------------------------------------------- */
|
|
MEMRasterBand *poBand;
|
|
|
|
poBand = new MEMRasterBand( poDS, 1, pabyImage, GDT_Byte, 1, nXSize,
|
|
TRUE );
|
|
poBand->SetColorTable( poCT );
|
|
poDS->SetBand( 1, poBand );
|
|
|
|
delete poCT;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Initialize any PAM information. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->SetDescription( poOpenInfo->pszFilename );
|
|
poDS->TryLoadXML();
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Support overviews. */
|
|
/* -------------------------------------------------------------------- */
|
|
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
|
|
|
|
return poDS;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* XPMCreateCopy() */
|
|
/************************************************************************/
|
|
|
|
static GDALDataset *
|
|
XPMCreateCopy( const char * pszFilename,
|
|
CPL_UNUSED GDALDataset *poSrcDS,
|
|
int bStrict,
|
|
CPL_UNUSED char ** papszOptions,
|
|
CPL_UNUSED GDALProgressFunc pfnProgress,
|
|
CPL_UNUSED void * pProgressData )
|
|
{
|
|
int nBands = poSrcDS->GetRasterCount();
|
|
int nXSize = poSrcDS->GetRasterXSize();
|
|
int nYSize = poSrcDS->GetRasterYSize();
|
|
GDALColorTable *poCT;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Some some rudimentary checks */
|
|
/* -------------------------------------------------------------------- */
|
|
if( nBands != 1 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_NotSupported,
|
|
"XPM driver only supports one band images.\n" );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte
|
|
&& bStrict )
|
|
{
|
|
CPLError( CE_Failure, CPLE_NotSupported,
|
|
"XPM driver doesn't support data type %s. "
|
|
"Only eight bit bands supported.\n",
|
|
GDALGetDataTypeName(
|
|
poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* If there is no colortable on the source image, create a */
|
|
/* greyscale one with 64 levels of grey. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALRasterBand *poBand = poSrcDS->GetRasterBand(1);
|
|
int i;
|
|
GDALColorTable oGreyTable;
|
|
|
|
poCT = poBand->GetColorTable();
|
|
if( poCT == NULL )
|
|
{
|
|
poCT = &oGreyTable;
|
|
|
|
for( i = 0; i < 256; i++ )
|
|
{
|
|
GDALColorEntry sColor;
|
|
|
|
sColor.c1 = (short) i;
|
|
sColor.c2 = (short) i;
|
|
sColor.c3 = (short) i;
|
|
sColor.c4 = 255;
|
|
|
|
poCT->SetColorEntry( i, &sColor );
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Build list of active colors, and the mapping from pixels to */
|
|
/* our active colormap. */
|
|
/* -------------------------------------------------------------------- */
|
|
const char *pszColorCodes = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-+=[]|:;,.<>?/";
|
|
|
|
int anPixelMapping[256];
|
|
GDALColorEntry asPixelColor[256];
|
|
int nActiveColors = MIN(poCT->GetColorEntryCount(),256);
|
|
|
|
// Setup initial colortable and pixel value mapping.
|
|
memset( anPixelMapping+0, 0, sizeof(int) * 256 );
|
|
for( i = 0; i < nActiveColors; i++ )
|
|
{
|
|
poCT->GetColorEntryAsRGB( i, asPixelColor + i );
|
|
anPixelMapping[i] = i;
|
|
}
|
|
|
|
/* ==================================================================== */
|
|
/* Iterate merging colors until we are under our limit (about 85). */
|
|
/* ==================================================================== */
|
|
while( nActiveColors > (int) strlen(pszColorCodes) )
|
|
{
|
|
int nClosestDistance = 768;
|
|
int iClose1 = -1, iClose2 = -1;
|
|
int iColor1, iColor2;
|
|
|
|
// Find the closest pair of colors.
|
|
for( iColor1 = 0; iColor1 < nActiveColors; iColor1++ )
|
|
{
|
|
for( iColor2 = iColor1+1; iColor2 < nActiveColors; iColor2++ )
|
|
{
|
|
int nDistance;
|
|
|
|
if( asPixelColor[iColor1].c4 < 128
|
|
&& asPixelColor[iColor2].c4 < 128 )
|
|
nDistance = 0;
|
|
else
|
|
nDistance =
|
|
ABS(asPixelColor[iColor1].c1-asPixelColor[iColor2].c1)
|
|
+ ABS(asPixelColor[iColor1].c2-asPixelColor[iColor2].c2)
|
|
+ ABS(asPixelColor[iColor1].c3-asPixelColor[iColor2].c3);
|
|
|
|
if( nDistance < nClosestDistance )
|
|
{
|
|
nClosestDistance = nDistance;
|
|
iClose1 = iColor1;
|
|
iClose2 = iColor2;
|
|
}
|
|
}
|
|
|
|
if( nClosestDistance < 8 )
|
|
break;
|
|
}
|
|
|
|
// This should never happen!
|
|
if( iClose1 == -1 )
|
|
break;
|
|
|
|
// Merge two selected colors - shift icolor2 into icolor1 and
|
|
// move the last active color into icolor2's slot.
|
|
for( i = 0; i < 256; i++ )
|
|
{
|
|
if( anPixelMapping[i] == iClose2 )
|
|
anPixelMapping[i] = iClose1;
|
|
else if( anPixelMapping[i] == nActiveColors-1 )
|
|
anPixelMapping[i] = iClose2;
|
|
}
|
|
|
|
asPixelColor[iClose2] = asPixelColor[nActiveColors-1];
|
|
nActiveColors--;
|
|
}
|
|
|
|
/* ==================================================================== */
|
|
/* Write the output image. */
|
|
/* ==================================================================== */
|
|
VSILFILE *fpPBM;
|
|
|
|
fpPBM = VSIFOpenL( pszFilename, "wb+" );
|
|
if( fpPBM == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_OpenFailed,
|
|
"Unable to create file `%s'.",
|
|
pszFilename );
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Write the header lines. */
|
|
/* -------------------------------------------------------------------- */
|
|
VSIFPrintfL( fpPBM, "/* XPM */\n" );
|
|
VSIFPrintfL( fpPBM, "static char *%s[] = {\n",
|
|
CPLGetBasename( pszFilename ) );
|
|
VSIFPrintfL( fpPBM, "/* width height num_colors chars_per_pixel */\n" );
|
|
VSIFPrintfL( fpPBM, "\" %3d %3d %3d 1\",\n",
|
|
nXSize, nYSize, nActiveColors );
|
|
VSIFPrintfL( fpPBM, "/* colors */\n" );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Write the color table. */
|
|
/* -------------------------------------------------------------------- */
|
|
for( i = 0; i < nActiveColors; i++ )
|
|
{
|
|
if( asPixelColor[i].c4 < 128 )
|
|
VSIFPrintfL( fpPBM, "\"%c c None\",\n", pszColorCodes[i] );
|
|
else
|
|
VSIFPrintfL( fpPBM,
|
|
"\"%c c #%02x%02x%02x\",\n",
|
|
pszColorCodes[i],
|
|
asPixelColor[i].c1,
|
|
asPixelColor[i].c2,
|
|
asPixelColor[i].c3 );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Dump image. */
|
|
/* -------------------------------------------------------------------- */
|
|
int iLine;
|
|
GByte *pabyScanline;
|
|
|
|
pabyScanline = (GByte *) CPLMalloc( nXSize );
|
|
for( iLine = 0; iLine < nYSize; iLine++ )
|
|
{
|
|
poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
|
|
(void *) pabyScanline, nXSize, 1, GDT_Byte, 0, 0, NULL );
|
|
|
|
VSIFPutcL( '"', fpPBM );
|
|
for( int iPixel = 0; iPixel < nXSize; iPixel++ )
|
|
VSIFPutcL( pszColorCodes[anPixelMapping[pabyScanline[iPixel]]],
|
|
fpPBM);
|
|
VSIFPrintfL( fpPBM, "\",\n" );
|
|
}
|
|
|
|
CPLFree( pabyScanline );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* cleanup */
|
|
/* -------------------------------------------------------------------- */
|
|
VSIFPrintfL( fpPBM, "};\n" );
|
|
VSIFCloseL( fpPBM );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Re-open dataset, and copy any auxiliary pam information. */
|
|
/* -------------------------------------------------------------------- */
|
|
GDALPamDataset *poDS = (GDALPamDataset *)
|
|
GDALOpen( pszFilename, GA_ReadOnly );
|
|
|
|
if( poDS )
|
|
poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
|
|
|
|
return poDS;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALRegister_XPM() */
|
|
/************************************************************************/
|
|
|
|
void GDALRegister_XPM()
|
|
|
|
{
|
|
GDALDriver *poDriver;
|
|
|
|
if( GDALGetDriverByName( "XPM" ) == NULL )
|
|
{
|
|
poDriver = new GDALDriver();
|
|
|
|
poDriver->SetDescription( "XPM" );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
|
|
"X11 PixMap Format" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
|
|
"frmt_various.html#XPM" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "xpm" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/x-xpixmap" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
|
|
"Byte" );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
|
|
|
|
poDriver->pfnOpen = XPMDataset::Open;
|
|
poDriver->pfnCreateCopy = XPMCreateCopy;
|
|
|
|
GetGDALDriverManager()->RegisterDriver( poDriver );
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ParseXPM() */
|
|
/************************************************************************/
|
|
|
|
static unsigned char *
|
|
ParseXPM( const char *pszInput, int *pnXSize, int *pnYSize,
|
|
GDALColorTable **ppoRetTable )
|
|
|
|
{
|
|
/* ==================================================================== */
|
|
/* Parse input into an array of strings from within the first C */
|
|
/* initializer (list os comma separated strings in braces). */
|
|
/* ==================================================================== */
|
|
char **papszXPMList = NULL;
|
|
const char *pszNext = pszInput;
|
|
int i;
|
|
|
|
// Skip till after open brace.
|
|
while( *pszNext != '\0' && *pszNext != '{' )
|
|
pszNext++;
|
|
|
|
if( *pszNext == '\0' )
|
|
return NULL;
|
|
|
|
pszNext++;
|
|
|
|
// Read lines till close brace.
|
|
|
|
while( *pszNext != '\0' && *pszNext != '}' )
|
|
{
|
|
// skip whole comment.
|
|
if( EQUALN(pszNext,"/*",2) )
|
|
{
|
|
pszNext += 2;
|
|
while( *pszNext != '\0' && !EQUALN(pszNext,"*/",2) )
|
|
pszNext++;
|
|
}
|
|
|
|
// reading string constants
|
|
else if( *pszNext == '"' )
|
|
{
|
|
char *pszLine;
|
|
|
|
pszNext++;
|
|
i = 0;
|
|
|
|
while( pszNext[i] != '\0' && pszNext[i] != '"' )
|
|
i++;
|
|
|
|
if( pszNext[i] == '\0' )
|
|
{
|
|
CSLDestroy( papszXPMList );
|
|
return NULL;
|
|
}
|
|
|
|
pszLine = (char *) CPLMalloc(i+1);
|
|
strncpy( pszLine, pszNext, i );
|
|
pszLine[i] = '\0';
|
|
|
|
papszXPMList = CSLAddString( papszXPMList, pszLine );
|
|
CPLFree( pszLine );
|
|
pszNext = pszNext + i + 1;
|
|
}
|
|
|
|
// just ignore everything else (whitespace, commas, newlines, etc).
|
|
else
|
|
pszNext++;
|
|
}
|
|
|
|
if( CSLCount(papszXPMList) < 3 || *pszNext != '}' )
|
|
{
|
|
CSLDestroy( papszXPMList );
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Get the image information. */
|
|
/* -------------------------------------------------------------------- */
|
|
int nColorCount, nCharsPerPixel;
|
|
|
|
if( sscanf( papszXPMList[0], "%d %d %d %d",
|
|
pnXSize, pnYSize, &nColorCount, &nCharsPerPixel ) != 4 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Image definition (%s) not well formed.",
|
|
papszXPMList[0] );
|
|
CSLDestroy( papszXPMList );
|
|
return NULL;
|
|
}
|
|
|
|
if( nCharsPerPixel != 1 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Only one character per pixel XPM images supported by GDAL at this time." );
|
|
CSLDestroy( papszXPMList );
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Parse out colors. */
|
|
/* -------------------------------------------------------------------- */
|
|
int iColor;
|
|
int anCharLookup[256];
|
|
GDALColorTable oCTable;
|
|
|
|
for( i = 0; i < 256; i++ )
|
|
anCharLookup[i] = -1;
|
|
|
|
for( iColor = 0; iColor < nColorCount; iColor++ )
|
|
{
|
|
char **papszTokens = CSLTokenizeString( papszXPMList[iColor+1]+1 );
|
|
GDALColorEntry sColor;
|
|
int nRed, nGreen, nBlue;
|
|
|
|
if( CSLCount(papszTokens) != 2 || !EQUAL(papszTokens[0],"c") )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Ill formed color definition (%s) in XPM header.",
|
|
papszXPMList[iColor+1] );
|
|
CSLDestroy( papszXPMList );
|
|
CSLDestroy( papszTokens );
|
|
return NULL;
|
|
}
|
|
|
|
anCharLookup[(int)papszXPMList[iColor+1][0]] = iColor;
|
|
|
|
if( EQUAL(papszTokens[1],"None") )
|
|
{
|
|
sColor.c1 = 0;
|
|
sColor.c2 = 0;
|
|
sColor.c3 = 0;
|
|
sColor.c4 = 0;
|
|
}
|
|
else if( sscanf( papszTokens[1], "#%02x%02x%02x",
|
|
&nRed, &nGreen, &nBlue ) != 3 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Ill formed color definition (%s) in XPM header.",
|
|
papszXPMList[iColor+1] );
|
|
CSLDestroy( papszXPMList );
|
|
CSLDestroy( papszTokens );
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
sColor.c1 = (short) nRed;
|
|
sColor.c2 = (short) nGreen;
|
|
sColor.c3 = (short) nBlue;
|
|
sColor.c4 = 255;
|
|
}
|
|
|
|
oCTable.SetColorEntry( iColor, &sColor );
|
|
|
|
CSLDestroy( papszTokens );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Prepare image buffer. */
|
|
/* -------------------------------------------------------------------- */
|
|
GByte *pabyImage;
|
|
|
|
pabyImage = (GByte *) VSIMalloc2(*pnXSize, *pnYSize);
|
|
if( pabyImage == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_OutOfMemory,
|
|
"Insufficient memory for %dx%d XPM image buffer.",
|
|
*pnXSize, *pnYSize );
|
|
CSLDestroy( papszXPMList );
|
|
return NULL;
|
|
}
|
|
|
|
memset( pabyImage, 0, *pnXSize * *pnYSize );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Parse image. */
|
|
/* -------------------------------------------------------------------- */
|
|
for( int iLine = 0; iLine < *pnYSize; iLine++ )
|
|
{
|
|
const char *pszInLine = papszXPMList[iLine + nColorCount + 1];
|
|
|
|
if( pszInLine == NULL )
|
|
{
|
|
CPLFree( pabyImage );
|
|
CSLDestroy( papszXPMList );
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Insufficient imagery lines in XPM image." );
|
|
return NULL;
|
|
}
|
|
|
|
for( int iPixel = 0;
|
|
pszInLine[iPixel] != '\0' && iPixel < *pnXSize;
|
|
iPixel++ )
|
|
{
|
|
int nPixelValue = anCharLookup[(int)pszInLine[iPixel]];
|
|
if( nPixelValue != -1 )
|
|
pabyImage[iLine * *pnXSize + iPixel] = (GByte) nPixelValue;
|
|
}
|
|
}
|
|
|
|
CSLDestroy( papszXPMList );
|
|
|
|
*ppoRetTable = oCTable.Clone();
|
|
|
|
return pabyImage;
|
|
}
|