From 5a396c91e6625a0249be2d9b87de74ad1b296f25 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 17 Feb 2012 16:45:49 +0000 Subject: [PATCH] From Martin Lambers, "It adds a new ReaderWriter plugin for the GTA file format (http://gta.nongnu.org). This allows to read and write floating point image data. Unlike other formats, GTA also allows very good compression ratios for floating point data. The compression method can be selected with the COMPRESSION option of the plugin. " --- CMakeLists.txt | 1 + CMakeModules/FindGTA.cmake | 56 ++++ src/osgPlugins/CMakeLists.txt | 3 + src/osgPlugins/gta/CMakeLists.txt | 8 + src/osgPlugins/gta/ReaderWriterGTA.cpp | 378 +++++++++++++++++++++++++ 5 files changed, 446 insertions(+) create mode 100644 CMakeModules/FindGTA.cmake create mode 100644 src/osgPlugins/gta/CMakeLists.txt create mode 100644 src/osgPlugins/gta/ReaderWriterGTA.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fb5b6bd6..dd327746b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -467,6 +467,7 @@ ELSE() FIND_PACKAGE(OpenVRML) FIND_PACKAGE(Performer) FIND_PACKAGE(GDAL) + FIND_PACKAGE(GTA) FIND_PACKAGE(CURL) FIND_PACKAGE(LibVNCServer) FIND_PACKAGE(OurDCMTK) diff --git a/CMakeModules/FindGTA.cmake b/CMakeModules/FindGTA.cmake new file mode 100644 index 000000000..56f6b803d --- /dev/null +++ b/CMakeModules/FindGTA.cmake @@ -0,0 +1,56 @@ +# Locate libgta +# This module defines +# GTA_FOUND, if false, do not try to link to libgta +# GTA_INCLUDE_DIRS, where to find the headers +# GTA_LIBRARIES +# +# $GTA_DIR is an environment variable that would +# correspond to the ./configure --prefix=$GTA_DIR +# used in building libgta. + +INCLUDE(FindPkgConfig OPTIONAL) + +IF(PKG_CONFIG_FOUND) + + INCLUDE(FindPkgConfig) + + PKG_CHECK_MODULES(GTA gta) + +ELSE(PKG_CONFIG_FOUND) + +FIND_PATH(GTA_INCLUDE_DIRS gta/gta.hpp + $ENV{GTA_DIR}/include + $ENV{GTA_DIR} + ~/Library/Frameworks + /Library/Frameworks + /usr/local/include + /usr/include + /sw/include # Fink + /opt/local/include # DarwinPorts + /opt/csw/include # Blastwave + /opt/include + /usr/freeware/include +) + +FIND_LIBRARY(GTA_LIBRARIES + NAMES gta libgta + PATHS + $ENV{GTA_DIR}/lib + $ENV{GTA_DIR} + ~/Library/Frameworks + /Library/Frameworks + /usr/local/lib + /usr/lib + /sw/lib + /opt/local/lib + /opt/csw/lib + /opt/lib + /usr/freeware/lib64 +) + +SET(GTA_FOUND "NO") +IF(GTA_LIBRARIES AND GTA_INCLUDE_DIRS) + SET(GTA_FOUND "YES") +ENDIF(GTA_LIBRARIES AND GTA_INCLUDE_DIRS) + +ENDIF(PKG_CONFIG_FOUND) diff --git a/src/osgPlugins/CMakeLists.txt b/src/osgPlugins/CMakeLists.txt index 0a6cd987f..9a8453bb7 100644 --- a/src/osgPlugins/CMakeLists.txt +++ b/src/osgPlugins/CMakeLists.txt @@ -100,6 +100,9 @@ IF(GDAL_FOUND) ADD_SUBDIRECTORY(gdal) ADD_SUBDIRECTORY(ogr) ENDIF() +IF(GTA_FOUND AND OSG_CPP_EXCEPTIONS_AVAILABLE) + ADD_SUBDIRECTORY(gta) +ENDIF() ############################################################ diff --git a/src/osgPlugins/gta/CMakeLists.txt b/src/osgPlugins/gta/CMakeLists.txt new file mode 100644 index 000000000..16466fefc --- /dev/null +++ b/src/osgPlugins/gta/CMakeLists.txt @@ -0,0 +1,8 @@ +INCLUDE_DIRECTORIES( ${GTA_INCLUDE_DIRS} ) + +SET(TARGET_SRC ReaderWriterGTA.cpp ) + +SET(TARGET_LIBRARIES_VARS GTA_LIBRARIES) + +#### end var setup ### +SETUP_PLUGIN(gta) diff --git a/src/osgPlugins/gta/ReaderWriterGTA.cpp b/src/osgPlugins/gta/ReaderWriterGTA.cpp new file mode 100644 index 000000000..26ce78a6d --- /dev/null +++ b/src/osgPlugins/gta/ReaderWriterGTA.cpp @@ -0,0 +1,378 @@ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* Copyright (C) 2011 Martin Lambers + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. + */ + +class ReaderWriterGTA : public osgDB::ReaderWriter +{ + public: + + ReaderWriterGTA() + { + supportsExtension("gta","GTA (Generic Tagged Arrays) file format"); + supportsOption("COMPRESSION","Set compression method: NONE, ZLIB (default), ZLIB1,...,ZLIB9, BZIP2, or XZ"); + } + + virtual const char* className() const { return "GTA Image Reader"; } + + virtual bool acceptsExtension(const std::string& extension) const + { + return osgDB::equalCaseInsensitive(extension,"gta"); + } + + ReadResult local_readImage(std::istream& fin,const osgDB::ReaderWriter::Options* /* options */) const + { + int s,t,r; + int internalFormat; + unsigned int pixelFormat; + unsigned int dataType; + unsigned char* imageData = NULL; + + std::string my_errmsg; + try + { + gta::header hdr; + hdr.read_from(fin); + if (hdr.data_size() > static_cast(std::numeric_limits::max())) + { + my_errmsg = "GTA too large"; + throw std::exception(); + } + if (hdr.dimensions() < 1 || hdr.dimensions() > 3) + { + my_errmsg = "GTA has less than 1 or more than 3 dimensions"; + throw std::exception(); + } + s = t = r = 1; + for (uintmax_t i = 0; i < hdr.dimensions(); i++) + { + if (hdr.dimension_size(i) > static_cast(std::numeric_limits::max())) + { + my_errmsg = "GTA dimensions too large"; + throw std::exception(); + } + if (i == 0) + s = hdr.dimension_size(i); + else if (i == 1) + t = hdr.dimension_size(i); + else + r = hdr.dimension_size(i); + } + if (hdr.components() < 1 || hdr.components() > 4) + { + my_errmsg = "GTA has less than 1 or more than 4 element components"; + throw std::exception(); + } + pixelFormat = + hdr.components() == 1 ? GL_LUMINANCE : + hdr.components() == 2 ? GL_LUMINANCE_ALPHA : + hdr.components() == 3 ? GL_RGB : + GL_RGBA; + switch (hdr.component_type(0)) + { + case gta::int8: + dataType = GL_BYTE; + break; + case gta::uint8: + dataType = GL_UNSIGNED_BYTE; + break; + case gta::int16: + dataType = GL_SHORT; + break; + case gta::uint16: + dataType = GL_UNSIGNED_SHORT; + break; + case gta::int32: + dataType = GL_INT; + break; + case gta::uint32: + dataType = GL_UNSIGNED_INT; + break; + case gta::float32: + dataType = GL_FLOAT; + break; + default: + my_errmsg = "GTA component type(s) not supported"; + throw std::exception(); + } + for (uintmax_t i = 1; i < hdr.components(); i++) + { + if (hdr.component_type(i) != hdr.component_type(0)) + { + my_errmsg = "GTA component types differ"; + throw std::exception(); + } + } + if (dataType == GL_BYTE || dataType == GL_UNSIGNED_BYTE) + { + internalFormat = hdr.components(); + } + else + { + internalFormat = + hdr.components() == 1 ? GL_LUMINANCE32F_ARB : + hdr.components() == 2 ? GL_LUMINANCE_ALPHA32F_ARB : + hdr.components() == 3 ? GL_RGB32F_ARB : + GL_RGBA32F_ARB; + } + imageData = new unsigned char[hdr.data_size()]; + hdr.read_data(fin, imageData); + } + catch (std::exception& e) + { + delete[] imageData; + if (!(my_errmsg.empty())) + { + OSG_WARN << my_errmsg << std::endl; + } + else + { + OSG_WARN << e.what() << std::endl; + } + return ReadResult::ERROR_IN_READING_FILE; + } + + osg::Image* pOsgImage = new osg::Image; + pOsgImage->setImage(s,t,r, + internalFormat, + pixelFormat, + dataType, + imageData, + osg::Image::USE_NEW_DELETE); + pOsgImage->setOrigin(osg::Image::TOP_LEFT); + + return pOsgImage; + } + + WriteResult local_writeImage(std::ostream& fout,const osg::Image& img,const osgDB::ReaderWriter::Options* options) const + { + std::string my_errmsg; + try + { + gta::header hdr; + gta::compression compression = gta::zlib; + if (options) + { + std::istringstream iss(options->getOptionString()); + std::string opt; + std::string compressionMethod; + while (iss >> opt) + { + if (opt == "COMPRESSION") + { + iss >> compressionMethod; + } + }; + if (compressionMethod == "NONE") + compression = gta::none; + else if (compressionMethod == "ZLIB") + compression = gta::zlib; + else if (compressionMethod == "ZLIB1") + compression = gta::zlib1; + else if (compressionMethod == "ZLIB2") + compression = gta::zlib2; + else if (compressionMethod == "ZLIB3") + compression = gta::zlib3; + else if (compressionMethod == "ZLIB4") + compression = gta::zlib4; + else if (compressionMethod == "ZLIB5") + compression = gta::zlib5; + else if (compressionMethod == "ZLIB6") + compression = gta::zlib6; + else if (compressionMethod == "ZLIB7") + compression = gta::zlib7; + else if (compressionMethod == "ZLIB8") + compression = gta::zlib8; + else if (compressionMethod == "ZLIB9") + compression = gta::zlib9; + else if (compressionMethod == "BZIP2") + compression = gta::bzip2; + else if (compressionMethod == "XZ") + compression = gta::xz; + } + hdr.set_compression(compression); + if (img.s() > 0 && img.t() <= 1 && img.r() <= 1) + { + hdr.set_dimensions(img.s()); + } + else if (img.s() > 0 && img.t() > 1 && img.r() <= 1) + { + hdr.set_dimensions(img.s(), img.t()); + } + else if (img.s() > 0 && img.t() > 1 && img.r() > 1) + { + hdr.set_dimensions(img.s(), img.t(), img.r()); + } + else + { + my_errmsg = "Image has unsupported dimensions"; + throw std::exception(); + } + gta::type type; + switch (img.getDataType()) + { + case GL_BYTE: + type = gta::int8; + break; + case GL_UNSIGNED_BYTE: + type = gta::uint8; + break; + case GL_SHORT: + type = gta::int16; + break; + case GL_UNSIGNED_SHORT: + type = gta::uint16; + break; + case GL_INT: + type = gta::int32; + break; + case GL_UNSIGNED_INT: + type = gta::uint32; + break; + case GL_FLOAT: + type = gta::float32; + break; + default: + my_errmsg = "Image has unsupported data type"; + throw std::exception(); + } + switch (img.getPixelFormat()) + { + case 1: + case GL_DEPTH_COMPONENT: + case GL_LUMINANCE: + case GL_ALPHA: + hdr.set_components(type); + break; + case 2: + case GL_LUMINANCE_ALPHA: + hdr.set_components(type, type); + break; + case 3: + case GL_RGB: + hdr.set_components(type, type, type); + break; + case 4: + case GL_RGBA: + hdr.set_components(type, type, type, type); + break; + default: + my_errmsg = "Image has unsupported pixel format"; + throw std::exception(); + } + if (img.getPacking() != 1) + { + my_errmsg = "Image has unsupported packing"; + throw std::exception(); + } + hdr.write_to(fout); +#if 0 /* Does not seem to be necessary */ + if (img.t() > 1 && img.getOrigin() == osg::Image::BOTTOM_LEFT) + { + int depth = (img.r() >= 1 ? img.r() : 1); + const unsigned char* data = static_cast(img.getDataPointer()); + size_t row_size = hdr.element_size() * img.s(); + gta::io_state io_state; + for (int k = 0; k < depth; k++) + { + const unsigned char* slice = data + k * (row_size * img.t()); + for (int j = 0; j < img.t(); j++) + { + const unsigned char* p = slice + (img.t() - 1 - j) * row_size; + hdr.write_elements(io_state, fout, img.s(), p); + } + } + } + else + { + hdr.write_data(fout, img.getDataPointer()); + } +#endif + hdr.write_data(fout, img.getDataPointer()); + } + catch (std::exception& e) + { + if (!(my_errmsg.empty())) + { + OSG_WARN << my_errmsg << std::endl; + } + else + { + OSG_WARN << e.what() << std::endl; + } + return WriteResult::ERROR_IN_WRITING_FILE; + } + + return WriteResult::FILE_SAVED; + } + + virtual ReadResult readObject(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const + { + return readImage(fin, options); + } + + virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const + { + return readImage(file, options); + } + + virtual ReadResult readImage(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const + { + return local_readImage(fin, options); + } + + virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const + { + std::string ext = osgDB::getLowerCaseFileExtension(file); + if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; + + std::string fileName = osgDB::findDataFile( file, options ); + if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; + + osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary); + if(!istream) return ReadResult::FILE_NOT_HANDLED; + ReadResult rr = local_readImage(istream, options); + if(rr.validImage()) rr.getImage()->setFileName(file); + return rr; + } + + virtual WriteResult writeImage(const osg::Image& img,std::ostream& fout,const osgDB::ReaderWriter::Options* options) const + { + return local_writeImage(fout,img,options); + } + + virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options *options) const + { + std::string ext = osgDB::getFileExtension(fileName); + if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; + + osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary); + if(!fout) return WriteResult::ERROR_IN_WRITING_FILE; + + return writeImage(img,fout,options); + } +}; + +// now register with Registry to instantiate the above +// reader/writer. +REGISTER_OSGPLUGIN(gta, ReaderWriterGTA)