From b34c3e3ba243215e82eff2ef3c297c6671e3c6ed Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 7 Aug 2007 10:37:42 +0000 Subject: [PATCH] Re-introduceed GDAL plugin --- src/osgPlugins/gdal/CMakeLists.txt | 8 + src/osgPlugins/gdal/ReaderWriterGDAL.cpp | 738 +++++++++++++++++++++++ 2 files changed, 746 insertions(+) create mode 100644 src/osgPlugins/gdal/CMakeLists.txt create mode 100644 src/osgPlugins/gdal/ReaderWriterGDAL.cpp diff --git a/src/osgPlugins/gdal/CMakeLists.txt b/src/osgPlugins/gdal/CMakeLists.txt new file mode 100644 index 000000000..e8a85f0d7 --- /dev/null +++ b/src/osgPlugins/gdal/CMakeLists.txt @@ -0,0 +1,8 @@ +INCLUDE_DIRECTORIES( ${GDAL_INCLUDE_DIR} ${OSG_INCLUDE_DIR} ) + +SET(TARGET_SRC ReaderWriterGDAL.cpp ) + +SET(TARGET_LIBRARIES_VARS GDAL_LIBRARY ) + +#### end var setup ### +SETUP_PLUGIN(gdal) diff --git a/src/osgPlugins/gdal/ReaderWriterGDAL.cpp b/src/osgPlugins/gdal/ReaderWriterGDAL.cpp new file mode 100644 index 000000000..0fcb33c7f --- /dev/null +++ b/src/osgPlugins/gdal/ReaderWriterGDAL.cpp @@ -0,0 +1,738 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#define SERIALIZER() OpenThreads::ScopedLock lock(_serializerMutex) + +// From easyrgb.com +float Hue_2_RGB( float v1, float v2, float vH ) +{ + if ( vH < 0 ) vH += 1; + if ( vH > 1 ) vH -= 1; + if ( ( 6 * vH ) < 1 ) return ( v1 + ( v2 - v1 ) * 6 * vH ); + if ( ( 2 * vH ) < 1 ) return ( v2 ); + if ( ( 3 * vH ) < 2 ) return ( v1 + ( v2 - v1 ) * ( ( 2 / 3 ) - vH ) * 6 ); + return ( v1 ); +} + +class ReaderWriterGDAL : public osgDB::ReaderWriter +{ + public: + virtual const char* className() const { return "GDAL Image Reader"; } + virtual bool acceptsExtension(const std::string& extension) const + { + return osgDB::equalCaseInsensitive(extension,"gdal") || osgDB::equalCaseInsensitive(extension,"gdal"); + } + + virtual ReadResult readImage(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const + { + OpenThreads::ScopedLock lock(_serializerMutex); + return const_cast(this)->local_readImage(fileName, options); + } + + virtual ReadResult readHeightField(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const + { + OpenThreads::ScopedLock lock(_serializerMutex); + return const_cast(this)->local_readHeightField(fileName, options); + } + + virtual ReadResult local_readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) + { + // Looks like gdal's GDALRasterBand::GetColorInterpretation() + // is not giving proper values for ecw images. There is small + // hack to get around + bool ecwLoad = osgDB::equalCaseInsensitive(osgDB::getFileExtension(file),"ecw"); + + //if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; + + osg::notify(osg::INFO) << "GDAL : " << file << std::endl; + + std::string fileName = osgDB::findDataFile( file, options ); + if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; + + initGDAL(); + + std::auto_ptr dataset((GDALDataset*)GDALOpen(fileName.c_str(),GA_ReadOnly)); + if (!dataset.get()) return ReadResult::FILE_NOT_HANDLED; + + int dataWidth = dataset->GetRasterXSize(); + int dataHeight = dataset->GetRasterYSize(); + + int windowX = 0; + int windowY = 0; + int windowWidth = dataWidth; + int windowHeight = dataHeight; + + int destX = 0; + int destY = 0; + int destWidth = osg::minimum(dataWidth,1024); + int destHeight = osg::minimum(dataHeight,1024); +// int destWidth = osg::minimum(dataWidth,4096); +// int destHeight = osg::minimum(dataHeight,4096); + + + osgDB::ImageOptions::TexCoordRange* texCoordRange = 0; + + osgDB::ImageOptions* imageOptions = dynamic_cast(const_cast(options)); + if (imageOptions) + { + osg::notify(osg::INFO)<<"Got ImageOptions"<_sourceImageWindowMode) + { + case(osgDB::ImageOptions::RATIO_WINDOW): + { + double desiredX = (double)dataWidth * imageOptions->_sourceRatioWindow.windowX; + double desiredY = (double)dataHeight * imageOptions->_sourceRatioWindow.windowY; + double desiredWidth = (double)dataWidth * imageOptions->_sourceRatioWindow.windowWidth; + double desiredHeight = (double)dataHeight * imageOptions->_sourceRatioWindow.windowHeight; + + windowX = osg::maximum((int)(floor(desiredX))-margin,0); + windowY = osg::maximum((int)(floor(desiredY))-margin,0); + windowWidth = osg::minimum((int)(ceil(desiredX + desiredWidth))+margin,dataWidth)-windowX; + windowHeight = osg::minimum((int)(ceil(desiredY + desiredHeight))+margin,dataHeight)-windowY; + + texCoordRange = new osgDB::ImageOptions::TexCoordRange; + texCoordRange->set((desiredX-(double)windowX)/(double)windowWidth, + ((double)(windowY+windowHeight) -(desiredY+desiredHeight))/(double)windowHeight, + (desiredWidth)/(double)windowWidth, + (desiredHeight)/(double)windowHeight); + osg::notify(osg::INFO)<<"tex coord range "<_x<<" "<_y<<" "<_w<<" "<_h<_sourcePixelWindow.windowX; + windowY = imageOptions->_sourcePixelWindow.windowY; + windowWidth = imageOptions->_sourcePixelWindow.windowWidth; + windowHeight = imageOptions->_sourcePixelWindow.windowHeight; + break; + default: + // leave source window dimensions as whole image. + break; + } + + // reapply the window coords to the pixel window so that calling code + // knows the original pixel size + imageOptions->_sourcePixelWindow.windowX = windowX; + imageOptions->_sourcePixelWindow.windowY = windowY; + imageOptions->_sourcePixelWindow.windowWidth = windowWidth; + imageOptions->_sourcePixelWindow.windowHeight = windowHeight; + + switch(imageOptions->_destinationImageWindowMode) + { + case(osgDB::ImageOptions::RATIO_WINDOW): + destX = (unsigned int)(floor((double)dataWidth * imageOptions->_destinationRatioWindow.windowX)); + destY = (unsigned int)(floor((double)dataHeight * imageOptions->_destinationRatioWindow.windowY)); + destWidth = (unsigned int)(ceil((double)dataWidth * (imageOptions->_destinationRatioWindow.windowX + imageOptions->_destinationRatioWindow.windowWidth)))-windowX; + destHeight = (unsigned int)(ceil((double)dataHeight * (imageOptions->_destinationRatioWindow.windowY + imageOptions->_destinationRatioWindow.windowHeight)))-windowY; + break; + case(osgDB::ImageOptions::PIXEL_WINDOW): + destX = imageOptions->_destinationPixelWindow.windowX; + destY = imageOptions->_destinationPixelWindow.windowY; + destWidth = imageOptions->_destinationPixelWindow.windowWidth; + destHeight = imageOptions->_destinationPixelWindow.windowHeight; + break; + default: + // leave source window dimensions as whole image. + break; + } + + } + +// windowX = 0; +// windowY = 0; +// windowWidth = destWidth; +// windowHeight = destHeight; + + osg::notify(osg::INFO) << " windowX = "<GetRasterCount()<GetProjectionRef()<GetGeoTransform(geoTransform)==CE_None) + { + osg::notify(osg::INFO) << " GetGeoTransform "<< std::endl; + osg::notify(osg::INFO) << " Origin = "<GetRasterCount(); + + + GDALRasterBand* bandGray = 0; + GDALRasterBand* bandRed = 0; + GDALRasterBand* bandGreen = 0; + GDALRasterBand* bandBlue = 0; + GDALRasterBand* bandAlpha = 0; + GDALRasterBand* bandPalette = 0; + + int internalFormat = GL_LUMINANCE; + unsigned int pixelFormat = GL_LUMINANCE; + unsigned int dataType = 0; + unsigned int numBytesPerPixel = 0; + + GDALDataType targetGDALType = GDT_Byte; + + for(int b=1;b<=numBands;++b) + { + + GDALRasterBand* band = dataset->GetRasterBand(b); + + osg::notify(osg::INFO) << " Band "<GetColorTable()->GetPaletteInterpretation()) << std::endl; + } + +// int gotMin,gotMax; +// double minmax[2]; +// +// minmax[0] = band->GetMinimum(&gotMin); +// minmax[1] = band->GetMaximum(&gotMax); +// if (!(gotMin && gotMax)) +// { +// osg::notify(osg::INFO)<<" computing min max"<GetRasterDataType(); + switch(band->GetRasterDataType()) + { + case(GDT_Byte): dataType = GL_UNSIGNED_BYTE; numBytesPerPixel = 1; break; + case(GDT_UInt16): dataType = GL_UNSIGNED_SHORT; numBytesPerPixel = 2; break; + case(GDT_Int16): dataType = GL_SHORT; numBytesPerPixel = 2; break; + case(GDT_UInt32): dataType = GL_UNSIGNED_INT; numBytesPerPixel = 4; break; + case(GDT_Int32): dataType = GL_INT; numBytesPerPixel = 4; break; + case(GDT_Float32): dataType = GL_FLOAT; numBytesPerPixel = 4; break; + case(GDT_Float64): dataType = GL_DOUBLE; numBytesPerPixel = 8; break; // not handled + default: dataType = 0; numBytesPerPixel = 0; break; // not handled + } + } + } + + + int s = destWidth; + int t = destHeight; + int r = 1; + + + if (dataType==0) + { + dataType = GL_UNSIGNED_BYTE; + numBytesPerPixel = 1; + targetGDALType = GDT_Byte; + } + + unsigned char* imageData = 0; + + if (bandRed && bandGreen && bandBlue) + { + if (bandAlpha) + { + // RGBA + + int pixelSpace=4*numBytesPerPixel; + int lineSpace=destWidth * pixelSpace; + + imageData = new unsigned char[destWidth * destHeight * pixelSpace]; + pixelFormat = GL_RGBA; + internalFormat = GL_RGBA; + + osg::notify(osg::INFO) << "reading RGBA"<RasterIO(GF_Read,windowX,windowY,windowWidth,windowHeight,(void*)(imageData+0),destWidth,destHeight,targetGDALType,pixelSpace,lineSpace); + bandGreen->RasterIO(GF_Read,windowX,windowY,windowWidth,windowHeight,(void*)(imageData+1),destWidth,destHeight,targetGDALType,pixelSpace,lineSpace); + bandBlue->RasterIO(GF_Read,windowX,windowY,windowWidth,windowHeight,(void*)(imageData+2),destWidth,destHeight,targetGDALType,pixelSpace,lineSpace); + bandAlpha->RasterIO(GF_Read,windowX,windowY,windowWidth,windowHeight,(void*)(imageData+3),destWidth,destHeight,targetGDALType,pixelSpace,lineSpace); + + } + else + { + // RGB + + int pixelSpace=3*numBytesPerPixel; + int lineSpace=destWidth * pixelSpace; + + imageData = new unsigned char[destWidth * destHeight * pixelSpace]; + pixelFormat = GL_RGB; + internalFormat = GL_RGB; + + osg::notify(osg::INFO) << "reading RGB"<RasterIO(GF_Read,windowX,windowY,windowWidth,windowHeight,(void*)(imageData+0),destWidth,destHeight,targetGDALType,pixelSpace,lineSpace); + bandGreen->RasterIO(GF_Read,windowX,windowY,windowWidth,windowHeight,(void*)(imageData+1),destWidth,destHeight,targetGDALType,pixelSpace,lineSpace); + bandBlue->RasterIO(GF_Read,windowX,windowY,windowWidth,windowHeight,(void*)(imageData+2),destWidth,destHeight,targetGDALType,pixelSpace,lineSpace); + + } + } + else if (bandGray) + { + if (bandAlpha) + { + // Luminance alpha + int pixelSpace=2*numBytesPerPixel; + int lineSpace=destWidth * pixelSpace; + + imageData = new unsigned char[destWidth * destHeight * pixelSpace]; + pixelFormat = GL_LUMINANCE_ALPHA; + internalFormat = GL_LUMINANCE_ALPHA; + + osg::notify(osg::INFO) << "reading grey + alpha"<RasterIO(GF_Read,windowX,windowY,windowWidth,windowHeight,(void*)(imageData+0),destWidth,destHeight,targetGDALType,pixelSpace,lineSpace); + bandAlpha->RasterIO(GF_Read,windowX,windowY,windowWidth,windowHeight,(void*)(imageData+1),destWidth,destHeight,targetGDALType,pixelSpace,lineSpace); + } + else + { + // Luminance map + int pixelSpace=1*numBytesPerPixel; + int lineSpace=destWidth * pixelSpace; + + imageData = new unsigned char[destWidth * destHeight * pixelSpace]; + pixelFormat = GL_LUMINANCE; + internalFormat = GL_LUMINANCE; + + osg::notify(osg::INFO) << "reading grey"<RasterIO(GF_Read,windowX,windowY,windowWidth,windowHeight,(void*)(imageData+0),destWidth,destHeight,targetGDALType,pixelSpace,lineSpace); + } + } + else if (bandAlpha) + { + // alpha map + int pixelSpace=1*numBytesPerPixel; + int lineSpace=destWidth * pixelSpace; + + imageData = new unsigned char[destWidth * destHeight * pixelSpace]; + pixelFormat = GL_ALPHA; + internalFormat = GL_ALPHA; + + osg::notify(osg::INFO) << "reading alpha"<RasterIO(GF_Read,windowX,windowY,windowWidth,windowHeight,(void*)(imageData+0),destWidth,destHeight,targetGDALType,pixelSpace,lineSpace); + + } + else if (bandPalette) + { + // Paletted map + int pixelSpace=1*numBytesPerPixel; + int lineSpace=destWidth * pixelSpace; + + unsigned char *rawImageData; + rawImageData = new unsigned char[destWidth * destHeight * pixelSpace]; + imageData = new unsigned char[destWidth * destHeight * 4/*RGBA*/]; + pixelFormat = GL_RGBA; + internalFormat = GL_RGBA; + + osg::notify(osg::INFO) << "reading palette"<RasterIO(GF_Read,windowX,windowY,windowWidth,windowHeight,(void*)(rawImageData),destWidth,destHeight,targetGDALType,pixelSpace,lineSpace); + + // Map the indexes to an actual RGBA Value. + for (int i = 0; i < destWidth * destHeight; i++) + { + const GDALColorEntry *colorEntry = bandPalette->GetColorTable()->GetColorEntry(rawImageData[i]); + GDALPaletteInterp interp = bandPalette->GetColorTable()->GetPaletteInterpretation(); + if (!colorEntry) + { + //FIXME: What to do here? + + //osg::notify(osg::INFO) << "NO COLOR ENTRY FOR COLOR " << rawImageData[i] << std::endl; + imageData[4*i+0] = 255; + imageData[4*i+1] = 0; + imageData[4*i+2] = 0; + imageData[4*i+3] = 1; + + } + else + { + if (interp == GPI_RGB) + { + imageData[4*i+0] = colorEntry->c1; + imageData[4*i+1] = colorEntry->c2; + imageData[4*i+2] = colorEntry->c3; + imageData[4*i+3] = colorEntry->c4; + } + else if (interp == GPI_CMYK) + { + // from wikipedia.org + short C = colorEntry->c1; + short M = colorEntry->c2; + short Y = colorEntry->c3; + short K = colorEntry->c4; + imageData[4*i+0] = 255 - C*(255 - K) - K; + imageData[4*i+1] = 255 - M*(255 - K) - K; + imageData[4*i+2] = 255 - Y*(255 - K) - K; + imageData[4*i+3] = 255; + } + else if (interp == GPI_HLS) + { + // from easyrgb.com + float H = colorEntry->c1; + float S = colorEntry->c3; + float L = colorEntry->c2; + float R, G, B; + if ( S == 0 ) //HSL values = 0 - 1 + { + R = L; //RGB results = 0 - 1 + G = L; + B = L; + } + else + { + float var_2, var_1; + if ( L < 0.5 ) + var_2 = L * ( 1 + S ); + else + var_2 = ( L + S ) - ( S * L ); + + var_1 = 2 * L - var_2; + + R = Hue_2_RGB( var_1, var_2, H + ( 1 / 3 ) ); + G = Hue_2_RGB( var_1, var_2, H ); + B = Hue_2_RGB( var_1, var_2, H - ( 1 / 3 ) ); + } + imageData[4*i+0] = static_cast(R*255.0f); + imageData[4*i+1] = static_cast(G*255.0f); + imageData[4*i+2] = static_cast(B*255.0f); + imageData[4*i+3] = static_cast(255.0f); + } + else if (interp == GPI_Gray) + { + imageData[4*i+0] = static_cast(colorEntry->c1*255.0f); + imageData[4*i+1] = static_cast(colorEntry->c1*255.0f); + imageData[4*i+2] = static_cast(colorEntry->c1*255.0f); + imageData[4*i+3] = static_cast(255.0f); + } + } + } + delete [] rawImageData; + } + else + { + osg::notify(osg::INFO) << "not found any usable bands in file."<setFileName(fileName.c_str()); + image->setImage(s,t,r, + internalFormat, + pixelFormat, + dataType, + (unsigned char *)imageData, + osg::Image::USE_NEW_DELETE); + + if (texCoordRange) image->setUserData(texCoordRange); + + image->flipVertical(); + + return image; + + } + + return 0; + + } + + + ReadResult local_readHeightField(const std::string& fileName, const osgDB::ReaderWriter::Options* options) + { + //std::string ext = osgDB::getFileExtension(fileName); + //if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; + + initGDAL(); + + std::auto_ptr dataset((GDALDataset*)GDALOpen(fileName.c_str(),GA_ReadOnly)); + if (!dataset.get()) return ReadResult::FILE_NOT_HANDLED; + + int dataWidth = dataset->GetRasterXSize(); + int dataHeight = dataset->GetRasterYSize(); + + int windowX = 0; + int windowY = 0; + int windowWidth = dataWidth; + int windowHeight = dataHeight; + + int destX = 0; + int destY = 0; + int destWidth = osg::minimum(dataWidth,1024); + int destHeight = osg::minimum(dataHeight,1024); + + osgDB::ImageOptions::TexCoordRange* texCoordRange = 0; + + const osgDB::ImageOptions* imageOptions = dynamic_cast(options); + if (imageOptions) + { + osg::notify(osg::INFO)<<"Got ImageOptions"<_sourceImageWindowMode) + { + case(osgDB::ImageOptions::RATIO_WINDOW): + { + double desiredX = (double)dataWidth * imageOptions->_sourceRatioWindow.windowX; + double desiredY = (double)dataHeight * imageOptions->_sourceRatioWindow.windowY; + double desiredWidth = (double)dataWidth * imageOptions->_sourceRatioWindow.windowWidth; + double desiredHeight = (double)dataHeight * imageOptions->_sourceRatioWindow.windowHeight; + + windowX = osg::maximum((int)(floor(desiredX))-margin,0); + windowY = osg::maximum((int)(floor(desiredY))-margin,0); + windowWidth = osg::minimum((int)(ceil(desiredX + desiredWidth))+margin,dataWidth)-windowX; + windowHeight = osg::minimum((int)(ceil(desiredY + desiredHeight))+margin,dataHeight)-windowY; + + texCoordRange = new osgDB::ImageOptions::TexCoordRange; + texCoordRange->set((desiredX-(double)windowX)/(double)windowWidth, + ((double)(windowY+windowHeight) -(desiredY+desiredHeight))/(double)windowHeight, + (desiredWidth)/(double)windowWidth, + (desiredHeight)/(double)windowHeight); + osg::notify(osg::INFO)<<"tex coord range "<_x<<" "<_y<<" "<_w<<" "<_h<_sourcePixelWindow.windowX; + windowY = imageOptions->_sourcePixelWindow.windowY; + windowWidth = imageOptions->_sourcePixelWindow.windowWidth; + windowHeight = imageOptions->_sourcePixelWindow.windowHeight; + break; + default: + // leave source window dimensions as whole image. + break; + } + + switch(imageOptions->_destinationImageWindowMode) + { + case(osgDB::ImageOptions::RATIO_WINDOW): + destX = (unsigned int)(floor((double)dataWidth * imageOptions->_destinationRatioWindow.windowX)); + destY = (unsigned int)(floor((double)dataHeight * imageOptions->_destinationRatioWindow.windowY)); + destWidth = (unsigned int)(ceil((double)dataWidth * (imageOptions->_destinationRatioWindow.windowX + imageOptions->_destinationRatioWindow.windowWidth)))-windowX; + destHeight = (unsigned int)(ceil((double)dataHeight * (imageOptions->_destinationRatioWindow.windowY + imageOptions->_destinationRatioWindow.windowHeight)))-windowY; + break; + case(osgDB::ImageOptions::PIXEL_WINDOW): + destX = imageOptions->_destinationPixelWindow.windowX; + destY = imageOptions->_destinationPixelWindow.windowY; + destWidth = imageOptions->_destinationPixelWindow.windowWidth; + destHeight = imageOptions->_destinationPixelWindow.windowHeight; + break; + default: + // leave source window dimensions as whole image. + break; + } + + } + +// windowX = 0; +// windowY = 0; +// windowWidth = destWidth; +// windowHeight = destHeight; + + osg::notify(osg::INFO) << " windowX = "<GetRasterCount()<GetProjectionRef()<GetGeoTransform(geoTransform)<<" == CE_None"<GetGCPCount()<GetRasterCount(); + + + GDALRasterBand* bandGray = 0; + GDALRasterBand* bandRed = 0; + GDALRasterBand* bandGreen = 0; + GDALRasterBand* bandBlue = 0; + GDALRasterBand* bandAlpha = 0; + + for(int b=1;b<=numBands;++b) + { + + GDALRasterBand* band = dataset->GetRasterBand(b); + + osg::notify(osg::INFO) << " Band "<GetColorInterpretation()==GCI_GrayIndex) bandGray = band; + else if (band->GetColorInterpretation()==GCI_RedBand) bandRed = band; + else if (band->GetColorInterpretation()==GCI_GreenBand) bandGreen = band; + else if (band->GetColorInterpretation()==GCI_BlueBand) bandBlue = band; + else if (band->GetColorInterpretation()==GCI_AlphaBand) bandAlpha = band; + else bandGray = band; + + } + + + GDALRasterBand* bandSelected = 0; + if (!bandSelected && bandGray) bandSelected = bandGray; + else if (!bandSelected && bandAlpha) bandSelected = bandAlpha; + else if (!bandSelected && bandRed) bandSelected = bandRed; + else if (!bandSelected && bandGreen) bandSelected = bandGreen; + else if (!bandSelected && bandBlue) bandSelected = bandBlue; + + if (bandSelected) + { + osg::HeightField* hf = new osg::HeightField; + hf->allocate(destWidth,destHeight); + + bandSelected->RasterIO(GF_Read,windowX,windowY,windowWidth,windowHeight,(void*)(&(hf->getHeightList().front())),destWidth,destHeight,GDT_Float32,0,0); + + // now need to flip since the OSG's origin is in lower left corner. + osg::notify(osg::INFO)<<"flipping"<getNumRows()-1; + for(unsigned int r=0;rgetNumColumns();++c) + { + float temp = hf->getHeight(c,r); + hf->setHeight(c,r,hf->getHeight(c,copy_r)); + hf->setHeight(c,copy_r,temp); + } + } + + return hf; + } + + return ReadResult::FILE_NOT_HANDLED; + + } + + void initGDAL() + { + static bool s_initialized = false; + if (!s_initialized) + { + s_initialized = true; + GDALAllRegister(); + } + } + + mutable OpenThreads::ReentrantMutex _serializerMutex; + +}; + +// now register with Registry to instantiate the above +// reader/writer. +osgDB::RegisterReaderWriterProxy g_readerWriter_GDAL_Proxy;