[DEV] add an API to load raw buffer

This commit is contained in:
Edouard DUPIN 2017-06-25 15:00:33 +02:00
parent f345c9c664
commit 1181bc52e7
10 changed files with 304 additions and 156 deletions

View File

@ -9,6 +9,11 @@
#include <egami/ImagePrivate.hpp> #include <egami/ImagePrivate.hpp>
#include <ememory/memory.hpp> #include <ememory/memory.hpp>
std::ostream& egami::operator <<(std::ostream& _os, const egami::Image& _obj) {
_os << "egami::Image{" << _obj.getSize() << " on GPU: " << _obj.getGPUSize() << " color=" << _obj.getType();
return _os;
}
std::ostream& egami::operator <<(std::ostream& _os, const enum egami::colorType _type) { std::ostream& egami::operator <<(std::ostream& _os, const enum egami::colorType _type) {
switch (_type) { switch (_type) {
case egami::colorType::undefined: case egami::colorType::undefined:
@ -80,6 +85,16 @@ egami::Image::Image() :
} }
egami::Image::Image(const egami::Image& _image):
m_data(_image.m_data) {
}
egami::Image& egami::Image::operator=(const egami::Image& _image) {
m_data = _image.m_data;
return *this;
}
egami::Image::~Image() { egami::Image::~Image() {
} }
@ -204,22 +219,25 @@ const ivec2& egami::Image::getSize() const {
return m_data->getSize(); return m_data->getSize();
} }
/** #if defined(__TARGET_OS__Android) \
* @brief get the next power 2 if the input || defined(__TARGET_OS__IOs)
* @param[in] value Value that we want the next power of 2 /**
* @return result value * @brief get the next power 2 if the input
*/ * @param[in] value Value that we want the next power of 2
static int32_t nextP2(int32_t _value) { * @return result value
int32_t val=1; */
for (int32_t iii=1; iii<31; iii++) { static int32_t nextP2(int32_t _value) {
if (_value <= val) { int32_t val=1;
return val; for (int32_t iii=1; iii<31; iii++) {
if (_value <= val) {
return val;
}
val *=2;
} }
val *=2; EGAMI_CRITICAL("impossible CASE....");
return val;
} }
EGAMI_CRITICAL("impossible CASE...."); #endif
return val;
}
ivec2 egami::Image::getGPUSize() const { ivec2 egami::Image::getGPUSize() const {
if (m_data == nullptr) { if (m_data == nullptr) {

View File

@ -79,6 +79,8 @@ namespace egami {
* @note use @ref configure to set a correct image * @note use @ref configure to set a correct image
*/ */
Image(); Image();
Image(const egami::Image& _image);
Image& operator=(const egami::Image& _image);
Image(const ivec2& _size, Image(const ivec2& _size,
enum colorType _type = egami::colorType::undefined); enum colorType _type = egami::colorType::undefined);
~Image(); ~Image();
@ -142,5 +144,6 @@ namespace egami {
void set(const std::vector<etk::Color<float,4>>& _data, const ivec2& _size); void set(const std::vector<etk::Color<float,4>>& _data, const ivec2& _size);
void set(const std::vector<etk::Color<uint8_t,4>>& _data, const ivec2& _size); void set(const std::vector<etk::Color<uint8_t,4>>& _data, const ivec2& _size);
}; };
std::ostream& operator <<(std::ostream& _os, const egami::Image& _obj);
} }

View File

@ -100,6 +100,39 @@ egami::Image egami::load(const std::string& _fileName, const ivec2& _size) {
return out; return out;
} }
egami::Image egami::load(const std::string& _mineType, const std::vector<uint8_t>& _buffer, const ivec2& _size) {
egami::Image out;
// select the corect Loader :
if (_mineType == "image/bmp") {
out = egami::loadBMP(_buffer);
if (out.exist() == false) {
EGAMI_ERROR("Error to load BMP file '" << _buffer.size() << "'");
}
}else if (_mineType == "image/png") {
#ifdef EGAMI_BUILD_PNG
out = egami::loadPNG(_buffer);
if (out.exist() == false) {
EGAMI_ERROR("Error to load PNG file '" << _buffer.size() << "'");
}
#else
EGAMI_WARNING("egamy not compile with the PNG dependency for file '" << _buffer.size() << "'");
#endif
} else if (_mineType == "image/jpg") {
#ifdef EGAMI_BUILD_JPEG
out = egami::loadJPG(_buffer);
if (out.exist() == false) {
EGAMI_ERROR("Error to load JPG file '" << _buffer.size() << "'");
}
#else
EGAMI_WARNING("egamy not compile with the JPEG dependency for file '" << _buffer.size() << "'");
#endif
} else {
EGAMI_ERROR("Extention not managed '" << _mineType << "' Sopported extention : image/bmp, image/png, image/jpg");
}
return out;
}
bool egami::store(const egami::Image& _input, const std::string& _fileName) { bool egami::store(const egami::Image& _input, const std::string& _fileName) {
std::string tmpName = etk::tolower(_fileName); std::string tmpName = etk::tolower(_fileName);
EGAMI_DEBUG("Store file : " << _fileName); EGAMI_DEBUG("Store file : " << _fileName);

View File

@ -19,6 +19,13 @@ namespace egami {
* @param[in] _size Dimention of the file when resizable (SVG). * @param[in] _size Dimention of the file when resizable (SVG).
*/ */
egami::Image load(const std::string& _fileName, const ivec2& _size=ivec2(-1,-1) ); egami::Image load(const std::string& _fileName, const ivec2& _size=ivec2(-1,-1) );
/**
* @brief Load a specific ilage file in the requested image data.
* @param[in] _mineType mineType of the buffer.
* @param[in] _buffer memory file.
* @param[in] _size Dimention of the file when resizable (SVG).
*/
egami::Image load(const std::string& _mineType, const std::vector<uint8_t>& _buffer, const ivec2& _size=ivec2(-1,-1) );
/** /**
* @brief Save an image in a file. * @brief Save an image in a file.
* @param[in] _input Data of the image. * @param[in] _input Data of the image.
@ -26,6 +33,13 @@ namespace egami {
* @return true if the file is corectly Stored, false otherwise * @return true if the file is corectly Stored, false otherwise
*/ */
bool store(const egami::Image& _input, const std::string& _fileName); bool store(const egami::Image& _input, const std::string& _fileName);
/**
* @brief Save an image in a memory buffer.
* @param[in] _input Data of the image.
* @param[out] _buffer Store file in this buffer.
* @return true if the file is corectly Stored, false otherwise
*/
bool store(const egami::Image& _input, std::vector<uint8_t>& _buffer);
/** /**
* @brief know if a file can have multiple size definition. * @brief know if a file can have multiple size definition.
* @param[in] _fileName Name of the file. * @param[in] _fileName Name of the file.

View File

@ -106,9 +106,22 @@ static void display(struct bitmapFileHeader _header, struct bitmapInfoHeader _in
}*/ }*/
} }
egami::Image egami::loadBMP(const std::string& _inputFile) { egami::Image egami::loadBMP(const std::string& _inputFile) {
etk::FSNode fileName(_inputFile);
if (fileName.exist() == false) {
EGAMI_ERROR("File does not existed='" << fileName << "'");
return egami::Image();
}
if(fileName.fileOpenRead() == false) {
EGAMI_ERROR("Can not find the file name='" << fileName << "'");
return egami::Image();
}
std::vector<uint8_t> allData = fileName.fileReadAll<uint8_t>();
fileName.fileClose();
return egami::loadBMP(allData);
}
egami::Image egami::loadBMP(const std::vector<uint8_t>& _buffer) {
egami::Image out; egami::Image out;
enum modeBitmap m_dataMode = BITS_16_R5G6B5; enum modeBitmap m_dataMode = BITS_16_R5G6B5;
int32_t m_width = 0; int32_t m_width = 0;
@ -117,34 +130,18 @@ egami::Image egami::loadBMP(const std::string& _inputFile) {
bool useExtended = false; bool useExtended = false;
struct bitmapInfoHeader m_InfoHeader; struct bitmapInfoHeader m_InfoHeader;
struct bitmapInfoHeaderExtended m_InfoHeaderExtended; struct bitmapInfoHeaderExtended m_InfoHeaderExtended;
if (_buffer.size() < sizeof(struct bitmapFileHeader)) {
etk::FSNode fileName(_inputFile); EGAMI_ERROR("error loading file header, not enough data");
// get the fileSize ...
/*if (fileName.size() < (int32_t)(sizeof(struct bitmapFileHeader) + sizeof(struct bitmapFileHeader) ) ) {
EGAMI_ERROR("not enought data in the file named=\"" << fileName << "\"");
return;
}*/
if (fileName.exist() == false) {
EGAMI_ERROR("File does not existed=\"" << fileName << "\"");
return out;
}
if(fileName.fileOpenRead() ==false) {
EGAMI_ERROR("Can not find the file name=\"" << fileName << "\"");
return out;
}
// get the data :
if (fileName.fileRead(&m_FileHeader,sizeof(struct bitmapFileHeader),1) != 1) {
EGAMI_ERROR("error loading file header");
fileName.fileClose();
return out; return out;
} }
memcpy(&m_FileHeader, &_buffer[0], sizeof(struct bitmapFileHeader));
if (m_FileHeader.bfOffBits > sizeof(struct bitmapFileHeader) + sizeof(struct bitmapInfoHeader)) { if (m_FileHeader.bfOffBits > sizeof(struct bitmapFileHeader) + sizeof(struct bitmapInfoHeader)) {
EGAMI_VERBOSE("Read bitmap in EXTENDED mode ..."); EGAMI_VERBOSE("Read bitmap in EXTENDED mode ...");
if (fileName.fileRead(&m_InfoHeaderExtended,sizeof(struct bitmapInfoHeaderExtended),1) != 1) { if (_buffer.size() < sizeof(struct bitmapFileHeader) + sizeof(struct bitmapInfoHeaderExtended)) {
EGAMI_ERROR("error loading file header"); EGAMI_ERROR("error loading file header, not enough data");
fileName.fileClose();
return out; return out;
} }
memcpy(&m_FileHeader, &_buffer[sizeof(struct bitmapFileHeader)], sizeof(struct bitmapInfoHeaderExtended));
useExtended = true; useExtended = true;
m_InfoHeader.biSize = m_InfoHeaderExtended.biSize; m_InfoHeader.biSize = m_InfoHeaderExtended.biSize;
m_InfoHeader.biWidth = m_InfoHeaderExtended.biWidth; m_InfoHeader.biWidth = m_InfoHeaderExtended.biWidth;
@ -158,29 +155,22 @@ egami::Image egami::loadBMP(const std::string& _inputFile) {
m_InfoHeader.biYPelsPerMeter = m_InfoHeaderExtended.biYPelsPerMeter; m_InfoHeader.biYPelsPerMeter = m_InfoHeaderExtended.biYPelsPerMeter;
} else { } else {
EGAMI_VERBOSE("Read bitmap in BASIC mode ..."); EGAMI_VERBOSE("Read bitmap in BASIC mode ...");
if (fileName.fileRead(&m_InfoHeader,sizeof(struct bitmapInfoHeader),1) != 1) { if (_buffer.size() < sizeof(struct bitmapFileHeader) + sizeof(struct bitmapInfoHeader)) {
EGAMI_ERROR("error loading file header"); EGAMI_ERROR("error loading file header, not enough data");
fileName.fileClose();
return out; return out;
} }
memcpy(&m_FileHeader, &_buffer[sizeof(struct bitmapFileHeader)], sizeof(struct bitmapInfoHeader));
useExtended = false; useExtended = false;
} }
int32_t offset = m_FileHeader.bfOffBits;
//display(m_FileHeader, m_InfoHeader); //display(m_FileHeader, m_InfoHeader);
//EGAMI_ERROR("plopppppppppppppp " << m_FileHeader.bfOffBits);
if(fileName.fileSeek(m_FileHeader.bfOffBits, etk::seekNode_start) == false) {
EGAMI_ERROR("error with the 'bfOffBits' in the file named=\"" << fileName << "\"");
fileName.fileClose();
return out;
}
// check the header error : // check the header error :
if (m_FileHeader.bfType != 0x4D42) { if (m_FileHeader.bfType != 0x4D42) {
EGAMI_ERROR("the file=\"" << fileName << "\" is not a bitmap file ..."); EGAMI_ERROR("the Buffer is not a bitmap file ...");
fileName.fileClose();
return out; return out;
} }
if (m_FileHeader.bfReserved != 0x00000000) { if (m_FileHeader.bfReserved != 0x00000000) {
EGAMI_ERROR("the bfReserved feald is not at 0 == > not supported format ..."); EGAMI_ERROR("the bfReserved feald is not at 0 == > not supported format ...");
fileName.fileClose();
return out; return out;
} }
m_width = m_InfoHeader.biWidth; m_width = m_InfoHeader.biWidth;
@ -207,25 +197,21 @@ egami::Image egami::loadBMP(const std::string& _inputFile) {
out.configure(ivec2(m_width,m_height), egami::colorType::RGBA8); out.configure(ivec2(m_width,m_height), egami::colorType::RGBA8);
} else { } else {
EGAMI_ERROR("the biBitCount & biCompression fealds are unknow == > not supported format ..."); EGAMI_ERROR("the biBitCount & biCompression fealds are unknow == > not supported format ...");
fileName.fileClose();;
return out; return out;
} }
std::vector<uint8_t> m_data;
if(m_InfoHeader.biSizeImage != 0) { if(m_InfoHeader.biSizeImage != 0) {
m_data.resize(m_InfoHeader.biSizeImage, 0); if (_buffer.size() < offset + m_InfoHeader.biSizeImage) {
if (fileName.fileRead(&m_data[0],m_InfoHeader.biSizeImage,1) != 1){
EGAMI_CRITICAL("Can not read the file with the good size..."); EGAMI_CRITICAL("Can not read the file with the good size...");
} }
} }
fileName.fileClose();
etk::Color<> tmpColor(0,0,0,0); etk::Color<> tmpColor(0,0,0,0);
// need now to generate RGBA data ... // need now to generate RGBA data ...
switch(m_dataMode) { switch(m_dataMode) {
case BITS_16_R5G6B5: { case BITS_16_R5G6B5: {
uint16_t * pointer = (uint16_t*)(&m_data[0]); const uint16_t * pointer = (const uint16_t*)(&_buffer[offset]);
for(int32_t yyy=0; yyy<m_height; yyy++) { for(int32_t yyy=0; yyy<m_height; yyy++) {
for(int32_t xxx=0; xxx<m_width; xxx++) { for(int32_t xxx=0; xxx<m_width; xxx++) {
tmpColor.setB((uint8_t)((*pointer & 0xF800) >> 8)); tmpColor.setB((uint8_t)((*pointer & 0xF800) >> 8));
@ -239,7 +225,7 @@ egami::Image egami::loadBMP(const std::string& _inputFile) {
} }
break; break;
case BITS_16_X1R5G5B5: { case BITS_16_X1R5G5B5: {
uint16_t * pointer = (uint16_t*)(&m_data[0]); const uint16_t * pointer = (const uint16_t*)(&_buffer[offset]);
for(int32_t yyy=0; yyy<m_height; yyy++) { for(int32_t yyy=0; yyy<m_height; yyy++) {
for(int32_t xxx=0; xxx<m_width; xxx++) { for(int32_t xxx=0; xxx<m_width; xxx++) {
tmpColor.setB((int8_t)((*pointer & 0x7C00) >> 7)); tmpColor.setB((int8_t)((*pointer & 0x7C00) >> 7));
@ -262,7 +248,7 @@ egami::Image egami::loadBMP(const std::string& _inputFile) {
} else if ((baseLine%4) == 3) { } else if ((baseLine%4) == 3) {
offset = 1; offset = 1;
} }
uint8_t * pointer = (&m_data[0]); const uint8_t * pointer = (&_buffer[offset]);
for(int32_t yyy=0; yyy<m_height; yyy++) { for(int32_t yyy=0; yyy<m_height; yyy++) {
for(int32_t xxx=0; xxx<m_width; xxx++) { for(int32_t xxx=0; xxx<m_width; xxx++) {
tmpColor.setB(*pointer++); tmpColor.setB(*pointer++);
@ -278,7 +264,7 @@ egami::Image egami::loadBMP(const std::string& _inputFile) {
} }
break; break;
case BITS_32_X8R8G8B8: { case BITS_32_X8R8G8B8: {
uint8_t * pointer = (&m_data[0]); const uint8_t * pointer = (&_buffer[offset]);
for(int32_t yyy=0; yyy<m_height; yyy++) { for(int32_t yyy=0; yyy<m_height; yyy++) {
for(int32_t xxx=0; xxx<m_width; xxx++) { for(int32_t xxx=0; xxx<m_width; xxx++) {
pointer++; pointer++;
@ -292,7 +278,7 @@ egami::Image egami::loadBMP(const std::string& _inputFile) {
} }
break; break;
case BITS_32_A8R8G8B8: { case BITS_32_A8R8G8B8: {
uint8_t * pointer = (&m_data[0]); const uint8_t * pointer = (&_buffer[offset]);
for(int32_t yyy=0; yyy<m_height; yyy++) { for(int32_t yyy=0; yyy<m_height; yyy++) {
for(int32_t xxx=0; xxx<m_width; xxx++) { for(int32_t xxx=0; xxx<m_width; xxx++) {
tmpColor.setB(*pointer++); tmpColor.setB(*pointer++);

View File

@ -14,6 +14,12 @@ namespace egami {
* @return Generate image or empty image * @return Generate image or empty image
*/ */
egami::Image loadBMP(const std::string& _fileName); egami::Image loadBMP(const std::string& _fileName);
/**
* @breif Load a bmp file in the image.
* @param[in] _buffer file buffer
* @return Generate image or empty image
*/
egami::Image loadBMP(const std::vector<uint8_t>& _buffer);
/** /**
* @breif Store a bmp file in the image. * @breif Store a bmp file in the image.
* @param[in] _fileName Name of the file. * @param[in] _fileName Name of the file.

View File

@ -40,19 +40,22 @@ void put_scanline_someplace(const uint8_t* _buffer, int32_t _row_stride) {
egami::Image egami::loadJPG(const std::string& _inputFile) { egami::Image egami::loadJPG(const std::string& _inputFile) {
egami::Image out;
etk::FSNode fileName(_inputFile); etk::FSNode fileName(_inputFile);
if (fileName.exist() == false) { if (fileName.exist() == false) {
EGAMI_ERROR("File does not existed='" << fileName << "'"); EGAMI_ERROR("File does not existed='" << fileName << "'");
return out; return egami::Image();
} }
if(fileName.fileOpenRead() == false) { if(fileName.fileOpenRead() == false) {
EGAMI_ERROR("Can not find the file name='" << fileName << "'"); EGAMI_ERROR("Can not find the file name='" << fileName << "'");
return out; return egami::Image();
} }
std::vector<uint8_t> allData = fileName.fileReadAll<uint8_t>(); std::vector<uint8_t> allData = fileName.fileReadAll<uint8_t>();
fileName.fileClose(); fileName.fileClose();
return egami::loadJPG(allData);
}
egami::Image egami::loadJPG(const std::vector<uint8_t>& _buffer) {
egami::Image out;
// This struct contains the JPEG decompression parameters and pointers to working space (which is allocated as needed by the JPEG library). // This struct contains the JPEG decompression parameters and pointers to working space (which is allocated as needed by the JPEG library).
struct jpeg_decompress_struct cinfo; struct jpeg_decompress_struct cinfo;
// We use our private extension JPEG error handler. Note that this struct must live as long as the main JPEG parameter struct, to avoid dangling-pointer problems. // We use our private extension JPEG error handler. Note that this struct must live as long as the main JPEG parameter struct, to avoid dangling-pointer problems.
@ -76,7 +79,7 @@ egami::Image egami::loadJPG(const std::string& _inputFile) {
jpeg_create_decompress(&cinfo); jpeg_create_decompress(&cinfo);
// Step 2: specify data source (eg, a file) // Step 2: specify data source (eg, a file)
jpeg_mem_src(&cinfo, &allData[0], allData.size()); jpeg_mem_src(&cinfo, &_buffer[0], _buffer.size());
// Step 3: read file parameters with jpeg_read_header() // Step 3: read file parameters with jpeg_read_header()
(void)jpeg_read_header(&cinfo, TRUE); (void)jpeg_read_header(&cinfo, TRUE);

View File

@ -14,5 +14,11 @@ namespace egami {
* @return Read Image. * @return Read Image.
*/ */
egami::Image loadJPG(const std::string& _fileName); egami::Image loadJPG(const std::string& _fileName);
/**
* @breif Load a jpeg file in the image.
* @param[in] _buffer file Buffer
* @return Read Image.
*/
egami::Image loadJPG(const std::vector<uint8_t>& _buffer);
} }

View File

@ -10,12 +10,47 @@
#include <egami/wrapperPNG.hpp> #include <egami/wrapperPNG.hpp>
#include <etk/os/FSNode.hpp> #include <etk/os/FSNode.hpp>
#include <png/png.h> #include <png/png.h>
namespace egami {
class ReaderInstance {
public:
virtual ~ReaderInstance() = default;
virtual void read(png_bytep data, png_size_t length) = 0;
};
class ReaderInstanceFSNode : public egami::ReaderInstance {
private:
etk::FSNode& m_data;
public:
ReaderInstanceFSNode(etk::FSNode& _data):
m_data(_data) {
}
void read(png_bytep data, png_size_t length) override {
m_data.fileRead(data, 1, length);
}
};
class ReaderInstanceBuffer : public egami::ReaderInstance {
private:
const std::vector<uint8_t>& m_data;
int32_t m_offset;
public:
ReaderInstanceBuffer(const std::vector<uint8_t>& _data, int32_t _offset):
m_data(_data),
m_offset(_offset) {
}
void read(png_bytep data, png_size_t length) override {
memcpy(data, &m_data[m_offset], length);
m_offset += length;
}
};
}
// we must change the access of the IO of the png lib : // we must change the access of the IO of the png lib :
static void local_ReadData(png_structp png_ptr, png_bytep data, png_size_t length) { static void local_ReadData(png_structp png_ptr, png_bytep data, png_size_t length) {
etk::FSNode* fileNode = static_cast<etk::FSNode*>(png_get_io_ptr(png_ptr)); egami::ReaderInstance* instance = static_cast<egami::ReaderInstance*>(png_get_io_ptr(png_ptr));
if (fileNode != nullptr) { if (instance != nullptr) {
fileNode->fileRead(data, 1, length); instance->read(data, length);
} }
} }
/* /*
@ -44,74 +79,18 @@ void user_warning_fn(png_structp _pngPtr, png_const_charp _warningMsg) {
EGAMI_WARNING("libpng warning: '" << _warningMsg << "'"); EGAMI_WARNING("libpng warning: '" << _warningMsg << "'");
} }
egami::Image egami::loadPNG(const std::string& _inputFile) { static egami::Image genericLoader(png_structp _pngPtr, png_infop _infoPtr) {
egami::Image out; egami::Image out;
etk::FSNode fileName(_inputFile);
if (fileName.exist() == false) {
EGAMI_ERROR("File does not existed='" << fileName << "'");
return out;
}
if(fileName.fileOpenRead() == false) {
EGAMI_ERROR("Can not find the file name='" << fileName << "'");
return out;
}
unsigned char header[8];
png_infop info_ptr;
png_structp png_ptr;
if (fileName.fileRead(header,1,8) != 8) {
EGAMI_ERROR("error loading file header");
fileName.fileClose();
return out;
}
if (png_sig_cmp(header, 0, 8)) {
EGAMI_ERROR("Invalid file :" << fileName);
return out;
}
// PNG read setup
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, user_error_fn, user_warning_fn);
if (png_ptr == nullptr) {
EGAMI_ERROR("Can not Allocate PNG structure");
fileName.fileClose();
return out;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == nullptr) {
EGAMI_ERROR("Can not Allocate PNG info structure");
png_destroy_read_struct(&png_ptr, nullptr, nullptr);
fileName.fileClose();
return out;
}
/*
if (setjmp(png_jmpbuf(png_ptr))) {
EGAMI_ERROR(" Can not set the JUMP buffer adresses");
// Free all of the memory associated with the png_ptr and info_ptr
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
fileName.fileClose();
return false;
}
*/
// overwrite the read and write function :
png_set_read_fn(png_ptr,
&fileName,
&local_ReadData);
/*
png_set_write_fn(png_ptr,
&fileName,
&LocalWriteData,
&localFlushData);
*/
// If we have already read some of the signature // If we have already read some of the signature
png_set_sig_bytes(png_ptr, 8); png_set_sig_bytes(_pngPtr, 8);
png_read_info(png_ptr, info_ptr); png_read_info(_pngPtr, _infoPtr);
png_uint_32 width = 0; png_uint_32 width = 0;
png_uint_32 height = 0; png_uint_32 height = 0;
int bit_depth = 0; int bit_depth = 0;
int colorType = 0; int colorType = 0;
int interlace_type = 0; int interlace_type = 0;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &colorType, &interlace_type, nullptr, nullptr); png_get_IHDR(_pngPtr, _infoPtr, &width, &height, &bit_depth, &colorType, &interlace_type, nullptr, nullptr);
// reallocate the image // reallocate the image
EGAMI_VERBOSE("Load PNG image : (" << width << "," << height << ")" ); EGAMI_VERBOSE("Load PNG image : (" << width << "," << height << ")" );
switch (colorType) { switch (colorType) {
@ -133,34 +112,34 @@ egami::Image egami::loadPNG(const std::string& _inputFile) {
// Tell libpng to strip 16 bits/color files down to 8 bits/color. Use accurate scaling if it's available, otherwise just chop off the low byte. // Tell libpng to strip 16 bits/color files down to 8 bits/color. Use accurate scaling if it's available, otherwise just chop off the low byte.
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
png_set_scale_16(png_ptr); png_set_scale_16(_pngPtr);
#else #else
png_set_strip_16(png_ptr); png_set_strip_16(_pngPtr);
#endif #endif
// Strip alpha bytes from the input data without combining with the background (not recommended). // Strip alpha bytes from the input data without combining with the background (not recommended).
//png_set_strip_alpha(png_ptr); //png_set_strip_alpha(_pngPtr);
// Extract multiple pixels with bit depths of 1, 2, and 4 from a single byte into separate bytes (useful for paletted and grayscale images). // Extract multiple pixels with bit depths of 1, 2, and 4 from a single byte into separate bytes (useful for paletted and grayscale images).
png_set_packing(png_ptr); png_set_packing(_pngPtr);
// Change the order of packed pixels to least significant bit first (not useful if you are using png_set_packing). // Change the order of packed pixels to least significant bit first (not useful if you are using png_set_packing).
png_set_packswap(png_ptr); png_set_packswap(_pngPtr);
/* Expand paletted colors into true RGB triplets */ /* Expand paletted colors into true RGB triplets */
if (colorType == PNG_COLOR_TYPE_PALETTE) { if (colorType == PNG_COLOR_TYPE_PALETTE) {
png_set_palette_to_rgb(png_ptr); png_set_palette_to_rgb(_pngPtr);
} }
// Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel
if ( colorType == PNG_COLOR_TYPE_GRAY if ( colorType == PNG_COLOR_TYPE_GRAY
&& bit_depth < 8) { && bit_depth < 8) {
png_set_expand_gray_1_2_4_to_8(png_ptr); png_set_expand_gray_1_2_4_to_8(_pngPtr);
} }
// Expand paletted or RGB images with transparency to full alpha channels so the data will be available as RGBA quartets. // Expand paletted or RGB images with transparency to full alpha channels so the data will be available as RGBA quartets.
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) != 0) { if (png_get_valid(_pngPtr, _infoPtr, PNG_INFO_tRNS) != 0) {
png_set_tRNS_to_alpha(png_ptr); png_set_tRNS_to_alpha(_pngPtr);
} }
/* Set the background color to draw transparent and alpha images over. /* Set the background color to draw transparent and alpha images over.
@ -171,19 +150,19 @@ egami::Image egami::loadPNG(const std::string& _inputFile) {
*/ */
/* /*
png_color::16 my_background, *image_background; png_color::16 my_background, *image_background;
if (png_get_bKGD(png_ptr, info_ptr, &image_background) != 0) { if (png_get_bKGD(_pngPtr, _infoPtr, &image_background) != 0) {
png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); png_set_background(_pngPtr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
} else { } else {
png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); png_set_background(_pngPtr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
} }
*/ */
/* Optional call to gamma correct and add the background to the palette /* Optional call to gamma correct and add the background to the palette
* and update info structure. REQUIRED if you are expecting libpng to * and update info structure. REQUIRED if you are expecting libpng to
* update the palette for you (ie you selected such a transform above). * update the palette for you (ie you selected such a transform above).
*/ */
png_read_update_info(png_ptr, info_ptr); png_read_update_info(_pngPtr, _infoPtr);
// Allocate the memory to hold the image using the fields of info_ptr. // Allocate the memory to hold the image using the fields of _infoPtr.
// The easiest way to read the image: // The easiest way to read the image:
png_bytep row_pointers[height]; png_bytep row_pointers[height];
/* Clear the pointer array */ /* Clear the pointer array */
@ -191,15 +170,13 @@ egami::Image egami::loadPNG(const std::string& _inputFile) {
row_pointers[row] = nullptr; row_pointers[row] = nullptr;
} }
for (png_uint_32 row = 0; row < height; row++) { for (png_uint_32 row = 0; row < height; row++) {
row_pointers[row] = (png_bytep)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); row_pointers[row] = (png_bytep)png_malloc(_pngPtr, png_get_rowbytes(_pngPtr, _infoPtr));
} }
EGAMI_DEBUG("Load image: " << _inputFile); png_read_image(_pngPtr, row_pointers);
png_read_image(png_ptr, row_pointers); // Read rest of file, and get additional chunks in _infoPtr - REQUIRED
EGAMI_DEBUG("Load image: " << _inputFile << " DONE"); png_read_end(_pngPtr, _infoPtr);
// Read rest of file, and get additional chunks in info_ptr - REQUIRED
png_read_end(png_ptr, info_ptr);
//png_set_expand(png_ptr); //png_set_expand(_pngPtr);
etk::Color<> tmpColor(0,0,0,0); etk::Color<> tmpColor(0,0,0,0);
switch (colorType) { switch (colorType) {
@ -252,21 +229,117 @@ egami::Image egami::loadPNG(const std::string& _inputFile) {
} }
break; break;
default: default:
EGAMI_ERROR("Must be RGB+alpha?/GRAY+alpha? not supported : " << (int64_t)png_get_color_type(png_ptr, info_ptr)); EGAMI_ERROR("Must be RGB+alpha?/GRAY+alpha? not supported : " << (int64_t)png_get_color_type(_pngPtr, _infoPtr));
if ((png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_PALETTE) != 0) { if ((png_get_color_type(_pngPtr, _infoPtr) & PNG_COLOR_MASK_PALETTE) != 0) {
EGAMI_ERROR(" palette"); EGAMI_ERROR(" palette");
} }
if ((png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) != 0) { if ((png_get_color_type(_pngPtr, _infoPtr) & PNG_COLOR_MASK_COLOR) != 0) {
EGAMI_ERROR(" color"); EGAMI_ERROR(" color");
} }
if ((png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_ALPHA) != 0) { if ((png_get_color_type(_pngPtr, _infoPtr) & PNG_COLOR_MASK_ALPHA) != 0) {
EGAMI_ERROR(" Alpha"); EGAMI_ERROR(" Alpha");
} }
return egami::Image(); return egami::Image();
} }
fileName.fileClose();
// Clean up after the read, and free any memory allocated - REQUIRED // Clean up after the read, and free any memory allocated - REQUIRED
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); png_destroy_read_struct(&_pngPtr, &_infoPtr, nullptr);
return out; return out;
} }
egami::Image egami::loadPNG(const std::string& _inputFile) {
egami::Image out;
etk::FSNode fileName(_inputFile);
if (fileName.exist() == false) {
EGAMI_ERROR("File does not existed='" << fileName << "'");
return out;
}
if(fileName.fileOpenRead() == false) {
EGAMI_ERROR("Can not find the file name='" << fileName << "'");
return out;
}
unsigned char header[8];
if (fileName.fileRead(header,1,8) != 8) {
EGAMI_ERROR("error loading file header");
fileName.fileClose();
return out;
}
if (png_sig_cmp(header, 0, 8)) {
EGAMI_ERROR("Invalid file :" << fileName);
return out;
}
// PNG read setup
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, user_error_fn, user_warning_fn);
if (png_ptr == nullptr) {
EGAMI_ERROR("Can not Allocate PNG structure");
fileName.fileClose();
return out;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == nullptr) {
EGAMI_ERROR("Can not Allocate PNG info structure");
png_destroy_read_struct(&png_ptr, nullptr, nullptr);
fileName.fileClose();
return out;
}
/*
if (setjmp(png_jmpbuf(png_ptr))) {
EGAMI_ERROR(" Can not set the JUMP buffer adresses");
// Free all of the memory associated with the png_ptr and info_ptr
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
fileName.fileClose();
return false;
}
*/
ReaderInstanceFSNode tmpNode(fileName);
ReaderInstance* tmpPoiter = &tmpNode;
// overwrite the read and write function :
png_set_read_fn(png_ptr,
tmpPoiter,
&local_ReadData);
/*
png_set_write_fn(png_ptr,
&fileName,
&LocalWriteData,
&localFlushData);
*/
out = genericLoader(png_ptr, info_ptr);
fileName.fileClose();
return out;
}
egami::Image egami::loadPNG(const std::vector<uint8_t>& _buffer) {
egami::Image out;
unsigned char header[8];
if (png_sig_cmp(&_buffer[0], 0, 8)) {
EGAMI_ERROR("Invalid start buffer:");
return out;
}
// PNG read setup
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, user_error_fn, user_warning_fn);
if (png_ptr == nullptr) {
EGAMI_ERROR("Can not Allocate PNG structure");
return out;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == nullptr) {
EGAMI_ERROR("Can not Allocate PNG info structure");
png_destroy_read_struct(&png_ptr, nullptr, nullptr);
return out;
}
egami::ReaderInstanceBuffer tmpNode(_buffer, 8);
egami::ReaderInstance* tmpPoiter = &tmpNode;
// overwrite the read and write function :
png_set_read_fn(png_ptr,
tmpPoiter,
&local_ReadData);
out = genericLoader(png_ptr, info_ptr);
return out;
}

View File

@ -14,5 +14,11 @@ namespace egami {
* @return Read Image. * @return Read Image.
*/ */
egami::Image loadPNG(const std::string& _fileName); egami::Image loadPNG(const std::string& _fileName);
/**
* @breif Load a png file in the image.
* @param[in] _buffer File buffer.
* @return Read Image.
*/
egami::Image loadPNG(const std::vector<uint8_t>& _buffer);
} }