Commit b280d4b7 authored by Robert Menzel's avatar Robert Menzel

added PNG load/store functions

parent 6ea55778
......@@ -20,7 +20,14 @@
namespace ACGL{
namespace OpenGL{
bool saveTextureDataToPPM(const ConstSharedTextureData& _textureData, const std::string& _filename);
//! saves to a PPM file
bool saveTextureDataToPPM(const ConstSharedTextureData& _textureData, const std::string &_filename);
//! loads from a PNG using the simple lodepng library
SharedTextureData loadTextureDataFromLodepng(const std::string &_filename);
//! save to a PNG file with lodepng
bool saveTextureDataToLodepng( SharedTextureData _data, const std::string &_filename );
} // OpenGL
} // ACGL
......
......@@ -8,12 +8,16 @@
#include <ACGL/OpenGL/Tools.hh>
#include <fstream>
#include "lodepng/lodepng.h"
using namespace ACGL;
using namespace ACGL::OpenGL;
using namespace ACGL::Utils;
bool ACGL::OpenGL::saveTextureDataToPPM(const ConstSharedTextureData& _textureData, const std::string& _filename)
namespace ACGL{
namespace OpenGL{
bool saveTextureDataToPPM(const ConstSharedTextureData& _textureData, const std::string &_filename)
{
if(_textureData->getFormat() != GL_RGB)
{
......@@ -67,3 +71,163 @@ bool ACGL::OpenGL::saveTextureDataToPPM(const ConstSharedTextureData& _textureDa
outFileStream.close();
return true;
}
SharedTextureData loadTextureDataFromLodepng(const std::string &_filename)
{
SharedTextureData data;
unsigned int errorCode;
unsigned int width, height;
unsigned char* png;
size_t pngsize;
LodePNGState state;
// Load the PNG file from disk
lodepng_state_init(&state);
errorCode = lodepng_load_file(&png, &pngsize, _filename.c_str());
if(errorCode)
{
ACGL::Utils::error() << "LodePNG error while loading file " << _filename << " - " << errorCode << ": " << lodepng_error_text(errorCode) << std::endl;
return data;
}
// Extract metadata (bit depth, color type)
errorCode = lodepng_inspect(&width, &height, &state, png, pngsize);
if(errorCode)
{
ACGL::Utils::error() << "LodePNG error " << errorCode << ": " << lodepng_error_text(errorCode) << std::endl;
return data;
}
unsigned int bitdepth = state.info_png.color.bitdepth;
LodePNGColorType colorType = state.info_png.color.colortype;
unsigned int channels = 0;
GLenum glFormat = 0;
if(colorType == LCT_GREY) { channels = 1; glFormat = GL_RED; }
if(colorType == LCT_GREY_ALPHA) { channels = 2; glFormat = GL_RG; }
if(colorType == LCT_RGB) { channels = 3; glFormat = GL_RGB; }
if(colorType == LCT_RGBA) { channels = 4; glFormat = GL_RGBA; }
GLenum glType = 0;
if(bitdepth == 8) glType = GL_UNSIGNED_BYTE;
if(bitdepth == 16) glType = GL_UNSIGNED_SHORT;
if(bitdepth == 32) glType = GL_UNSIGNED_INT;
if(channels == 0 || glFormat == 0 || glType == 0)
{
ACGL::Utils::error() << "Could not load " << _filename << ": " << "unsupported bit depth or format" << std::endl;
return data;
}
// Decode the image
unsigned char* image;
errorCode = lodepng_decode_memory(&image, &width, &height, png, pngsize, colorType, bitdepth);
if(errorCode)
{
ACGL::Utils::error() << "LodePNG error while loading file " << _filename << " - " << errorCode << ": " << lodepng_error_text(errorCode) << std::endl;
return data;
}
free(png);
// Wrap the data in a TextureData object
data = SharedTextureData(new TextureData());
data->setData((GLubyte*)image);
data->setWidth(width);
data->setHeight(height);
data->setType(glType);
data->setFormat(glFormat);
return data;
}
// helper for saveTextureDataToLodepng
template< typename T>
unsigned char *preProcess( SharedTextureData _data)
{
unsigned int channelCount = getNumberOfChannels( _data->getFormat() );
unsigned int pixelCount = _data->getWidth() * _data->getHeight();
T *processedrawdata = new T[pixelCount * channelCount];
// copy & flip the image:
T *originalrawdata = (T*) _data->getData();
for (int i = 0; i < _data->getHeight(); ++i) {
size_t srcOffset = _data->getWidth() * i * channelCount;
size_t dstOffset = _data->getWidth() * (_data->getHeight()-i-1) * channelCount;
memcpy( processedrawdata + dstOffset, originalrawdata + srcOffset, _data->getWidth()*channelCount * sizeof(T) );
}
return (unsigned char *) processedrawdata;
}
bool saveTextureDataToLodepng( SharedTextureData _data, const std::string &_filename )
{
GLenum channelDataType = _data->getType();
unsigned int channelCount = getNumberOfChannels( _data->getFormat() );
int channelBitCount = 0;
if (channelDataType == GL_BYTE || channelDataType == GL_UNSIGNED_BYTE) channelBitCount = 8;
if (channelDataType == GL_SHORT || channelDataType == GL_UNSIGNED_SHORT) channelBitCount = 16;
if (channelDataType == GL_INT || channelDataType == GL_UNSIGNED_INT) channelBitCount = 32;
unsigned char *processedData;
if ( channelBitCount == 8 ) {
processedData = preProcess<unsigned char>( _data );
} else if ( channelBitCount == 16 ) {
processedData = preProcess<unsigned short>( _data );
} else if ( channelBitCount == 32 ) {
processedData = preProcess<unsigned int>( _data );
// no 32 bit save support -> reduce to 16 bit
uint32_t *original = (uint32_t*) processedData;
uint16_t *processedData16 = new uint16_t[ channelCount*_data->getWidth() * _data->getHeight() ];
for (unsigned int i = 0; i < channelCount*_data->getWidth() * _data->getHeight(); ++i) {
processedData16[i] = (uint16_t) original[i];
}
channelBitCount = 16;
processedData = (unsigned char*) processedData16;
delete[] original;
} else {
error() << "savePNG does not support this data type (yet), could not write " << _filename << std::endl;
return false;
}
LodePNGColorType colorType;
if (channelCount == 1) colorType = LCT_GREY;
if (channelCount == 2) colorType = LCT_GREY_ALPHA;
if (channelCount == 3) colorType = LCT_RGB;
if (channelCount == 4) colorType = LCT_RGBA;
unsigned int errorCode = lodepng_encode_file(_filename.c_str(),
processedData, _data->getWidth(), _data->getHeight(),
colorType, channelBitCount );
delete[] processedData;
//if there's an error, display it
if (errorCode) {
error() << "encoder error " << errorCode << ": "<< lodepng_error_text(errorCode) << std::endl;
return false;
}
return true;
}
} // OpenGL
} // ACGL
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment