#include <assert.h>
#include "mapserver.h"
#include "mapthread.h"
MS_CVSID("$Id: mapgdal.c 6428 2007-07-31 19:58:45Z dmorissette $")
#ifdef USE_GDAL
#include "gdal.h"
#include "ogr_srs_api.h"
#include "cpl_conv.h"
#include "cpl_string.h"
static char *msProjectionObjToWKT( projectionObj *proj );
static int bGDALInitialized = 0;
void msGDALInitialize( void )
{
if( !bGDALInitialized )
{
msAcquireLock( TLOCK_GDAL );
GDALAllRegister();
CPLPushErrorHandler( CPLQuietErrorHandler );
msReleaseLock( TLOCK_GDAL );
bGDALInitialized = 1;
}
}
void msGDALCleanup( void )
{
if( bGDALInitialized )
{
int iRepeat = 5;
msAcquireLock( TLOCK_GDAL );
while( iRepeat-- )
CPLPopErrorHandler();
#if GDAL_RELEASE_DATE > 20021001
GDALDestroyDriverManager();
#endif
#if GDAL_RELEASE_DATE > 20040101
CPLFreeConfig();
#endif
msReleaseLock( TLOCK_GDAL );
bGDALInitialized = 0;
}
}
int msSaveImageGDAL( mapObj *map, imageObj *image, char *filename )
{
int bFileIsTemporary = MS_FALSE;
GDALDatasetH hMemDS, hOutputDS;
GDALDriverH hMemDriver, hOutputDriver;
int nBands = 1;
int iLine;
GByte *pabyAlphaLine = NULL;
char **papszOptions = NULL;
outputFormatObj *format = image->format;
GDALDataType eDataType = GDT_Byte;
msGDALInitialize();
if( filename == NULL )
{
const char *pszExtension = format->extension;
if( pszExtension == NULL )
pszExtension = "img.tmp";
if( map != NULL && map->web.imagepath != NULL )
filename = msTmpFile(map->mappath,map->web.imagepath,pszExtension);
else
{
#ifndef _WIN32
filename = msTmpFile(NULL, "/tmp/", pszExtension );
#else
filename = msTmpFile(NULL, "C:\\", pszExtension );
#endif
}
bFileIsTemporary = MS_TRUE;
}
if( format->imagemode == MS_IMAGEMODE_RGB )
{
nBands = 3;
assert( gdImageTrueColor( image->img.gd ) );
}
else if( format->imagemode == MS_IMAGEMODE_RGBA )
{
pabyAlphaLine = (GByte *) calloc(image->width,1);
nBands = 4;
assert( gdImageTrueColor( image->img.gd ) );
}
else if( format->imagemode == MS_IMAGEMODE_INT16 )
{
nBands = format->bands;
eDataType = GDT_Int16;
}
else if( format->imagemode == MS_IMAGEMODE_FLOAT32 )
{
nBands = format->bands;
eDataType = GDT_Float32;
}
else if( format->imagemode == MS_IMAGEMODE_BYTE )
{
nBands = format->bands;
eDataType = GDT_Byte;
}
else
{
assert( format->imagemode == MS_IMAGEMODE_PC256
&& !gdImageTrueColor( image->img.gd ) );
}
msAcquireLock( TLOCK_GDAL );
hMemDriver = GDALGetDriverByName( "MEM" );
if( hMemDriver == NULL )
{
msReleaseLock( TLOCK_GDAL );
msSetError( MS_MISCERR, "Failed to find MEM driver.",
"msSaveImageGDAL()" );
return MS_FAILURE;
}
hMemDS = GDALCreate( hMemDriver, "msSaveImageGDAL_temp",
image->width, image->height, nBands,
eDataType, NULL );
if( hMemDS == NULL )
{
msReleaseLock( TLOCK_GDAL );
msSetError( MS_MISCERR, "Failed to create MEM dataset.",
"msSaveImageGDAL()" );
return MS_FAILURE;
}
for( iLine = 0; iLine < image->height; iLine++ )
{
int iBand;
for( iBand = 0; iBand < nBands; iBand++ )
{
GDALRasterBandH hBand = GDALGetRasterBand( hMemDS, iBand+1 );
if( format->imagemode == MS_IMAGEMODE_INT16 )
{
GDALRasterIO( hBand, GF_Write, 0, iLine, image->width, 1,
image->img.raw_16bit + iLine * image->width
+ iBand * image->width * image->height,
image->width, 1, GDT_Int16, 2, 0 );
}
else if( format->imagemode == MS_IMAGEMODE_FLOAT32 )
{
GDALRasterIO( hBand, GF_Write, 0, iLine, image->width, 1,
image->img.raw_float + iLine * image->width
+ iBand * image->width * image->height,
image->width, 1, GDT_Float32, 4, 0 );
}
else if( format->imagemode == MS_IMAGEMODE_BYTE )
{
GDALRasterIO( hBand, GF_Write, 0, iLine, image->width, 1,
image->img.raw_byte + iLine * image->width
+ iBand * image->width * image->height,
image->width, 1, GDT_Byte, 1, 0 );
}
#if GD2_VERS > 1
else if( nBands > 1 && iBand < 3 )
{
GByte *pabyData;
#ifdef CPL_MSB
pabyData = ((GByte *) image->img.gd->tpixels[iLine])+iBand+1;
#else
pabyData = ((GByte *) image->img.gd->tpixels[iLine])+(2-iBand);
#endif
GDALRasterIO( hBand, GF_Write, 0, iLine, image->width, 1,
pabyData, image->width, 1, GDT_Byte, 4, 0 );
}
else if( nBands > 1 && iBand == 3 )
{
int x;
#ifdef CPL_MSB
GByte *pabySrc = ((GByte *) image->img.gd->tpixels[iLine]);
#else
GByte *pabySrc = ((GByte *) image->img.gd->tpixels[iLine])+3;
#endif
for( x = 0; x < image->width; x++ )
{
if( *pabySrc == 127 )
pabyAlphaLine[x] = 0;
else
pabyAlphaLine[x] = 255 - 2 * *pabySrc;
pabySrc += 4;
}
GDALRasterIO( hBand, GF_Write, 0, iLine, image->width, 1,
pabyAlphaLine, image->width, 1, GDT_Byte, 1, 0 );
}
#endif
else
{
GDALRasterIO( hBand, GF_Write, 0, iLine, image->width, 1,
image->img.gd->pixels[iLine],
image->width, 1, GDT_Byte, 0, 0 );
}
}
}
if( pabyAlphaLine != NULL )
free( pabyAlphaLine );
if( format->imagemode == MS_IMAGEMODE_PC256 )
{
GDALColorEntry sEntry;
int iColor;
GDALColorTableH hCT;
hCT = GDALCreateColorTable( GPI_RGB );
for( iColor = 0; iColor < image->img.gd->colorsTotal; iColor++ )
{
sEntry.c1 = image->img.gd->red[iColor];
sEntry.c2 = image->img.gd->green[iColor];
sEntry.c3 = image->img.gd->blue[iColor];
if( iColor == gdImageGetTransparent( image->img.gd ) )
sEntry.c4 = 0;
else if( iColor == 0
&& gdImageGetTransparent( image->img.gd ) == -1
&& format->transparent )
sEntry.c4 = 0;
else
sEntry.c4 = 255;
GDALSetColorEntry( hCT, iColor, &sEntry );
}
GDALSetRasterColorTable( GDALGetRasterBand( hMemDS, 1 ), hCT );
GDALDestroyColorTable( hCT );
}
#if GDAL_VERSION_NUM > 1170
else if( format->imagemode == MS_IMAGEMODE_RGB )
{
GDALSetRasterColorInterpretation(
GDALGetRasterBand( hMemDS, 1 ), GCI_RedBand );
GDALSetRasterColorInterpretation(
GDALGetRasterBand( hMemDS, 2 ), GCI_GreenBand );
GDALSetRasterColorInterpretation(
GDALGetRasterBand( hMemDS, 3 ), GCI_BlueBand );
}
else if( format->imagemode == MS_IMAGEMODE_RGBA )
{
GDALSetRasterColorInterpretation(
GDALGetRasterBand( hMemDS, 1 ), GCI_RedBand );
GDALSetRasterColorInterpretation(
GDALGetRasterBand( hMemDS, 2 ), GCI_GreenBand );
GDALSetRasterColorInterpretation(
GDALGetRasterBand( hMemDS, 3 ), GCI_BlueBand );
GDALSetRasterColorInterpretation(
GDALGetRasterBand( hMemDS, 4 ), GCI_AlphaBand );
}
#endif
if( map != NULL )
{
char *pszWKT;
GDALSetGeoTransform( hMemDS, map->gt.geotransform );
pszWKT = msProjectionObjToWKT( &(map->projection) );
if( pszWKT != NULL )
{
GDALSetProjection( hMemDS, pszWKT );
CPLFree( pszWKT );
}
}
hOutputDriver = GDALGetDriverByName( format->driver+5 );
if( hOutputDriver == NULL )
{
GDALClose( hMemDS );
msReleaseLock( TLOCK_GDAL );
msSetError( MS_MISCERR, "Failed to find %s driver.",
"msSaveImageGDAL()", format->driver+5 );
return MS_FAILURE;
}
papszOptions = (char**)calloc(sizeof(char *),(format->numformatoptions+1));
memcpy( papszOptions, format->formatoptions,
sizeof(char *) * format->numformatoptions );
hOutputDS = GDALCreateCopy( hOutputDriver, filename, hMemDS, FALSE,
papszOptions, NULL, NULL );
free( papszOptions );
if( hOutputDS == NULL )
{
GDALClose( hMemDS );
msReleaseLock( TLOCK_GDAL );
msSetError( MS_MISCERR, "Failed to create output %s file.\n%s",
"msSaveImageGDAL()", format->driver+5,
CPLGetLastErrorMsg() );
return MS_FAILURE;
}
GDALClose( hMemDS );
GDALClose( hOutputDS );
msReleaseLock( TLOCK_GDAL );
if( bFileIsTemporary )
{
FILE *fp;
unsigned char block[4000];
int bytes_read;
if( msIO_needBinaryStdout() == MS_FAILURE )
return MS_FAILURE;
fp = fopen( filename, "rb" );
if( fp == NULL )
{
msSetError( MS_MISCERR,
"Failed to open %s for streaming to stdout.",
"msSaveImageGDAL()", filename );
return MS_FAILURE;
}
while( (bytes_read = fread(block, 1, sizeof(block), fp)) > 0 )
msIO_fwrite( block, 1, bytes_read, stdout );
fclose( fp );
unlink( filename );
free( filename );
}
return MS_SUCCESS;
}
int msInitDefaultGDALOutputFormat( outputFormatObj *format )
{
GDALDriverH hDriver;
msGDALInitialize();
hDriver = GDALGetDriverByName( format->driver+5 );
if( hDriver == NULL )
{
msSetError( MS_MISCERR, "No GDAL driver named `%s' available.",
"msInitGDALOutputFormat()", format->driver+5 );
return MS_FAILURE;
}
#ifdef GDAL_DCAP_CREATE
if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) == NULL
&& GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) == NULL )
{
msSetError( MS_MISCERR, "GDAL `%s' driver does not support output.",
"msInitGDALOutputFormat()", format->driver+5 );
return MS_FAILURE;
}
#endif
format->imagemode = MS_IMAGEMODE_RGB;
format->renderer = MS_RENDER_WITH_GD;
#ifdef GDAL_DMD_MIMETYPE
if( GDALGetMetadataItem( hDriver, GDAL_DMD_MIMETYPE, NULL ) != NULL )
format->mimetype =
strdup(GDALGetMetadataItem(hDriver,GDAL_DMD_MIMETYPE,NULL));
if( GDALGetMetadataItem( hDriver, GDAL_DMD_EXTENSION, NULL ) != NULL )
format->extension =
strdup(GDALGetMetadataItem(hDriver,GDAL_DMD_EXTENSION,NULL));
#else
if( strcasecmp(format->driver,"GDAL/GTiff") )
{
format->mimetype = strdup("image/tiff");
format->extension = strdup("tif");
}
#endif
return MS_SUCCESS;
}
char *msProjectionObjToWKT( projectionObj *projection )
{
OGRSpatialReferenceH hSRS;
char *pszWKT=NULL, *pszProj4;
int nLength = 0, i;
OGRErr eErr;
if( projection->proj == NULL )
return NULL;
for( i = 0; i < projection->numargs; i++ )
nLength += strlen(projection->args[i]) + 2;
pszProj4 = (char *) CPLMalloc(nLength+2);
pszProj4[0] = '\0';
for( i = 0; i < projection->numargs; i++ )
{
strcat( pszProj4, "+" );
strcat( pszProj4, projection->args[i] );
strcat( pszProj4, " " );
}
hSRS = OSRNewSpatialReference( NULL );
eErr = OSRImportFromProj4( hSRS, pszProj4 );
CPLFree( pszProj4 );
if( eErr == OGRERR_NONE )
eErr = OSRExportToWkt( hSRS, &pszWKT );
OSRDestroySpatialReference( hSRS );
return pszWKT;
}
#else
void msGDALInitialize( void ) {}
void msGDALCleanup(void) {}
#endif