Commit 7e8af607 authored by Janis Born's avatar Janis Born

ensure correct endianness for decoding and encoding 16 bit raw data using LodePNG

parent c021ba6b
......@@ -15,6 +15,7 @@
#include <cstdio>
#include <ctime>
#include <stdexcept>
#include <fstream>
#include "lodepng/lodepng.h"
#include "rgbe/rgbe.hh"
......@@ -163,83 +164,110 @@ bool saveScreenshotWithDate(const std::string& _prefix, const std::string& _file
// library specific load
///////////////////////////////////////////////////////////////////////////////////////////////////
struct LodepngFile
{
public:
LodepngFile(const std::string& _filename)
{
unsigned int errorCode = lodepng_load_file(&mData, &mSize, _filename.c_str());
if(errorCode)
{
std::stringstream errorMsg;
errorMsg << "LodePNG error while loading file " << _filename << " - " << errorCode << ": " << lodepng_error_text(errorCode);
mData = nullptr;
throw std::runtime_error(errorMsg.str());
}
}
~LodepngFile()
{
free(mData);
}
unsigned char* mData;
size_t mSize;
};
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)
try
{
ACGL::Utils::error() << "LodePNG error while loading file " << _filename << " - " << errorCode << ": " << lodepng_error_text(errorCode) << std::endl;
return data;
}
LodepngFile lodepngFile(_filename);
// Extract metadata (bit depth, color type)
// Extract metadata (bit depth, color type)
errorCode = lodepng_inspect(&width, &height, &state, lodepngFile.mData, lodepngFile.mSize);
if(errorCode)
{
std::stringstream errorMsg;
errorMsg << "LodePNG error " << errorCode << ": " << lodepng_error_text(errorCode);
throw std::runtime_error(errorMsg.str());
}
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 bitdepth = state.info_png.color.bitdepth;
LodePNGColorType colorType = state.info_png.color.colortype;
unsigned int channels = 0;
GLenum glFormat = 0;
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; }
if(colorType == LCT_PALETTE) { channels = 4; glFormat = GL_RGBA; colorType = LCT_RGBA; } // force LodePNG to convert paletted data to RGBA
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; }
if(colorType == LCT_PALETTE) { channels = 4; glFormat = GL_RGBA; colorType = LCT_RGBA; } // force LodePNG to convert paletted data to RGBA
GLenum glType = 0;
if(bitdepth == 8) glType = GL_UNSIGNED_BYTE;
if(bitdepth == 16) glType = GL_UNSIGNED_SHORT;
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)
{
std::stringstream errorMsg;
errorMsg << "Could not load " << _filename << ": " << "unsupported bit depth or format";
throw std::runtime_error(errorMsg.str());
}
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, lodepngFile.mData, lodepngFile.mSize, colorType, bitdepth);
if(errorCode)
{
std::stringstream errorMsg;
errorMsg << "LodePNG error while decoding file " << _filename << " - " << errorCode << ": " << lodepng_error_text(errorCode);
throw std::runtime_error(errorMsg.str());
}
// Decode the image
// LodePNG decodes 16 bit PNGs in big endian format ==> Convert
#ifndef ACGL_BIG_ENDIAN
if(bitdepth == 16)
for(int i = 0; i < (width * height * channels * 2); i += 2)
std::swap(image[i], image[i+1]);
#endif
unsigned char* image;
errorCode = lodepng_decode_memory(&image, &width, &height, png, pngsize, colorType, bitdepth);
if(errorCode)
// 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);
// Flip
data->flipVertically();
}
catch(std::runtime_error& error)
{
ACGL::Utils::error() << "LodePNG error while loading file " << _filename << " - " << errorCode << ": " << lodepng_error_text(errorCode) << std::endl;
return data;
ACGL::Utils::error() << error.what() << std::endl;
}
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);
// Flip
data->flipVertically();
return data;
}
......@@ -626,6 +654,12 @@ bool saveTextureDataToLodepng( const SharedTextureData &_data, const std::string
return false;
}
// LodePNG expects 16 bit image data in big endian format ==> convert
#ifndef ACGL_BIG_ENDIAN
if(channelBitCount == 16)
for(int i = 0; i < _data->getWidth() * _data->getHeight() * _data->getNumberOfChannels() * 2; i += 2)
std::swap(processedData[i], processedData[i+1]);
#endif
LodePNGColorType colorType;
if (channelCount == 1) colorType = LCT_GREY;
......
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