[DEV] add store in png

This commit is contained in:
Edouard DUPIN 2017-10-09 22:22:48 +02:00
parent 7965135796
commit 99eae9d10f
10 changed files with 208 additions and 52 deletions

View File

@ -156,12 +156,12 @@ enum egami::colorType egami::Image::getType() const {
return m_data->getType();
}
void* egami::Image::getTextureDataPointer() {
void* egami::Image::getTextureDataPointer() const{
if (m_data == nullptr) {
EGAMI_DEBUG("No internal data for image (nullptr)");
return nullptr;
}
return m_data->getTextureDataPointer();
return (void*)m_data->getTextureDataPointer();
}
void egami::Image::resize(const ivec2& _size, const ivec2& _startPos) {

View File

@ -37,7 +37,7 @@ namespace egami {
public:
ImagePrivate() {};
virtual ~ImagePrivate() {};
virtual void* getTextureDataPointer() {
virtual void* getTextureDataPointer() const {
return nullptr;
};
virtual const ivec2& getSize() const = 0;
@ -89,7 +89,7 @@ namespace egami {
public:
void configure(const ivec2& _size=ivec2(32,32),
enum colorType _type=egami::colorType::RGBA8);
void* getTextureDataPointer();
void* getTextureDataPointer() const;
enum colorType getType() const;
bool exist() {
return m_data != nullptr;

View File

@ -23,8 +23,8 @@ namespace egami {
~ImageMono() { };
// EWOL internal API for Texture system :
public:
void* getTextureDataPointer() {
return &m_data[0];
void* getTextureDataPointer() const {
return (void*)&m_data[0];
};
/*
enum colorType getType() {

View File

@ -37,8 +37,8 @@ namespace egami {
virtual ~ImageTemplate() { };
// EWOL internal API for Texture system:
public:
void* getTextureDataPointer() {
return &m_data[0];
void* getTextureDataPointer() const {
return (void*)&m_data[0];
};
enum colorType getType() const;
const ivec2& getSize() {

View File

@ -151,8 +151,10 @@ bool egami::store(const egami::Image& _input, const etk::String& _fileName) {
EGAMI_ERROR("Can not store in SVG file '" << _fileName << "'");
return false;
} else if (etk::end_with(tmpName, ".png") == true) {
EGAMI_ERROR("Can not store in PNG file '" << _fileName << "'");
return false;
if (egami::storePNG(_fileName, _input) == false) {
EGAMI_ERROR("Error to store PNG file '" << _fileName << "'");
return false;
}
} else if (etk::end_with(tmpName, ".jpg") == true) {
EGAMI_ERROR("Can not store in JPEG file '" << _fileName << "'");
return false;
@ -168,7 +170,10 @@ bool egami::store(const egami::Image& _input, const etk::String& _fileName) {
}
return true;
}
bool egami::store(const egami::Image& _input, etk::Vector<uint8_t>& _buffer, const etk::String& _mineType) {
return false;
}
static void generateDistanceField(const egami::ImageMono& _input, egami::Image& _output) {

View File

@ -37,9 +37,10 @@ namespace egami {
* @brief Save an image in a memory buffer.
* @param[in] _input Data of the image.
* @param[out] _buffer Store file in this buffer.
* @param[in] _mineType mineType of the output buffer.
* @return true if the file is corectly Stored, false otherwise
*/
bool store(const egami::Image& _input, etk::Vector<uint8_t>& _buffer);
bool store(const egami::Image& _input, etk::Vector<uint8_t>& _buffer, const etk::String& _mineType);
/**
* @brief know if a file can have multiple size definition.
* @param[in] _fileName Name of the file.

View File

@ -14,7 +14,9 @@ namespace egami {
class ReaderInstance {
public:
virtual ~ReaderInstance() = default;
virtual void read(png_bytep data, png_size_t length) = 0;
virtual void read(png_bytep _data, png_size_t _length) = 0;
virtual void write(png_bytep _data, png_size_t _length) = 0;
virtual void flush() = 0;
};
class ReaderInstanceFSNode : public egami::ReaderInstance {
@ -25,57 +27,75 @@ namespace egami {
m_data(_data) {
}
void read(png_bytep data, png_size_t length) override {
m_data.fileRead(data, 1, length);
void read(png_bytep _data, png_size_t _length) override {
m_data.fileRead(_data, 1, _length);
}
void write(png_bytep _data, png_size_t _length) override {
m_data.fileWrite(_data, 1, _length);
}
void flush() override {
m_data.fileFlush();
}
};
class ReaderInstanceBuffer : public egami::ReaderInstance {
private:
const etk::Vector<uint8_t>& m_data;
etk::Vector<uint8_t>& m_data;
int32_t m_offset;
public:
ReaderInstanceBuffer(const etk::Vector<uint8_t>& _data, int32_t _offset):
m_data(_data),
m_data(const_cast<etk::Vector<uint8_t>&>(_data)),
m_offset(_offset) {
}
ReaderInstanceBuffer(etk::Vector<uint8_t>& _data):
m_data(_data),
m_offset(0) {
}
void read(png_bytep data, png_size_t length) override {
memcpy(data, &m_data[m_offset], length);
m_offset += length;
}
void write(png_bytep _data, png_size_t _length) override {
for (uint32_t iii=0; iii<_length; ++iii) {
m_data.pushBack(_data[iii]);
m_offset++;
}
}
void flush() override {
// nothing to do ...
}
};
}
// 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) {
egami::ReaderInstance* instance = static_cast<egami::ReaderInstance*>(png_get_io_ptr(png_ptr));
static void local_ReadData(png_structp _pngPtr, png_bytep _data, png_size_t _length) {
egami::ReaderInstance* instance = static_cast<egami::ReaderInstance*>(png_get_io_ptr(_pngPtr));
if (instance != nullptr) {
instance->read(data, length);
}
}
/*
static void LocalWriteData(png_structp png_ptr, png_bytep data, png_size_t length)
{
etk::FSNode* fileNode = static_cast<etk::FSNode*>(png_get_io_ptr(png_ptr));
if (NULL!=fileNode) {
fileNode->FileWrite(data, 1, length);
instance->read(_data, _length);
}
}
static void localFlushData(png_structp png_ptr)
{
etk::FSNode* fileNode = static_cast<etk::FSNode*>(png_get_io_ptr(png_ptr));
if (NULL!=fileNode) {
fileNode->FileFlush();
static void Local_WriteData(png_structp _pngPtr, png_bytep _data, png_size_t _length) {
egami::ReaderInstance* instance = static_cast<egami::ReaderInstance*>(png_get_io_ptr(_pngPtr));
if (instance != nullptr) {
instance->write(_data, _length);
}
}
*/
void user_error_fn(png_structp _pngPtr, png_const_charp _errorMsg) {
static void local_FlushData(png_structp _pngPtr) {
egami::ReaderInstance* instance = static_cast<egami::ReaderInstance*>(png_get_io_ptr(_pngPtr));
if (instance != nullptr) {
instance->flush();
}
}
void userErrorFunction(png_structp _pngPtr, png_const_charp _errorMsg) {
EGAMI_ERROR("libpng error: '" << _errorMsg << "'");
}
void user_warning_fn(png_structp _pngPtr, png_const_charp _warningMsg) {
void userWarningFunction(png_structp _pngPtr, png_const_charp _warningMsg) {
EGAMI_WARNING("libpng warning: '" << _warningMsg << "'");
}
@ -92,7 +112,7 @@ static egami::Image genericLoader(png_structp _pngPtr, png_infop _infoPtr) {
int interlace_type = 0;
png_get_IHDR(_pngPtr, _infoPtr, &width, &height, &bit_depth, &colorType, &interlace_type, nullptr, nullptr);
// reallocate the image
EGAMI_VERBOSE("Load PNG image : (" << width << "," << height << ")" );
EGAMI_ERROR("Load PNG image : (" << width << "," << height << ") bitDepth=" << bit_depth << " colorType=" << colorType);
switch (colorType) {
case PNG_COLOR_TYPE_RGBA:
out.configure(ivec2(width,height), egami::colorType::RGBA8);
@ -271,7 +291,7 @@ egami::Image egami::loadPNG(const etk::String& _inputFile) {
}
// PNG read setup
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, user_error_fn, user_warning_fn);
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, userErrorFunction, userWarningFunction);
if (png_ptr == nullptr) {
EGAMI_ERROR("Can not Allocate PNG structure");
fileName.fileClose();
@ -297,16 +317,10 @@ egami::Image egami::loadPNG(const etk::String& _inputFile) {
ReaderInstance* tmpPoiter = &tmpNode;
// overwrite the read and write function :
// overwrite the read 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;
@ -314,14 +328,13 @@ egami::Image egami::loadPNG(const etk::String& _inputFile) {
egami::Image egami::loadPNG(const etk::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);
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, userErrorFunction, userWarningFunction);
if (png_ptr == nullptr) {
EGAMI_ERROR("Can not Allocate PNG structure");
return out;
@ -336,10 +349,118 @@ egami::Image egami::loadPNG(const etk::Vector<uint8_t>& _buffer) {
egami::ReaderInstance* tmpPoiter = &tmpNode;
// overwrite the read and write function :
// Overwrite the read function:
png_set_read_fn(png_ptr,
tmpPoiter,
&local_ReadData);
out = genericLoader(png_ptr, info_ptr);
return out;
}
bool egami::storePNG(const etk::String& _fileName, const egami::Image& _inputImage) {
/* create file */
/*FILE *fp = fopen(file_name, "wb");
if (!fp) {
abort_("[write_png_file] File %s could not be opened for writing", file_name);
}
*/
etk::FSNode fileName(_fileName);
if(fileName.fileOpenWrite() == false) {
EGAMI_ERROR("Can not find the file name='" << fileName << "'");
return false;
}
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, userErrorFunction, userWarningFunction);
if (png_ptr == nullptr) {
EGAMI_ERROR("Can not Allocate PNG structure");
return false;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == nullptr) {
EGAMI_ERROR("Can not Allocate PNG info structure");
png_destroy_write_struct(&png_ptr, nullptr);
fileName.fileClose();
return false;
}
if (setjmp(png_jmpbuf(png_ptr))) {
EGAMI_ERROR("Error during init_io");
png_destroy_write_struct(&png_ptr, &info_ptr);
fileName.fileClose();
return false;
}
ReaderInstanceFSNode tmpNode(fileName);
ReaderInstance* tmpPoiter = &tmpNode;
// overwrite the write functions:
png_set_write_fn(png_ptr,
tmpPoiter,
&Local_WriteData,
&local_FlushData);
/*
TODO:
out = genericWriter(png_ptr, info_ptr);
fileName.fileClose();
*/
//png_init_io(png_ptr, fp);
/* write header */
if (setjmp(png_jmpbuf(png_ptr))) {
EGAMI_ERROR("Error jump setting");
png_destroy_write_struct(&png_ptr, &info_ptr);
fileName.fileClose();
return false;
}
png_byte bitDepth = 8;
png_byte colorType = 0;
switch(_inputImage.getType()) {
case egami::colorType::RGBA8:
colorType = PNG_COLOR_TYPE_RGB_ALPHA;
//bitDepth = 4;
break;
case egami::colorType::RGB8:
colorType = PNG_COLOR_TYPE_RGB;
//bitDepth = 3;
break;
default:
EGAMI_ERROR("PNG can not export an image with other type than RGB and RGBA request:" << _inputImage.getType());
png_destroy_write_struct(&png_ptr, &info_ptr);
fileName.fileClose();
return false;
}
png_set_IHDR(png_ptr,
info_ptr,
_inputImage.getSize().x(),
_inputImage.getSize().y(),
bitDepth,
colorType,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_BASE);
png_write_info(png_ptr, info_ptr);
/* write bytes */
if (setjmp(png_jmpbuf(png_ptr))) {
EGAMI_ERROR("Error while writing byte");
png_destroy_write_struct(&png_ptr, &info_ptr);
fileName.fileClose();
return false;
}
etk::Vector<png_bytep> rowPointers;
rowPointers.resize(_inputImage.getSize().y(), NULL);
uint8_t* imageData = (uint8_t*)_inputImage.getTextureDataPointer();
for (size_t iii=0; iii<rowPointers.size(); ++iii) {
rowPointers[iii] = &imageData[_inputImage.getSize().x()*getFormatColorSize(_inputImage.getType())*iii];
}
png_write_image(png_ptr, &rowPointers[0]);
/* end write */
if (setjmp(png_jmpbuf(png_ptr))) {
EGAMI_ERROR("Error while writing byte");
png_destroy_write_struct(&png_ptr, &info_ptr);
fileName.fileClose();
return false;
}
png_write_end(png_ptr, NULL);
png_destroy_write_struct(&png_ptr, &info_ptr);
fileName.fileClose();
return true;
}

View File

@ -20,5 +20,12 @@ namespace egami {
* @return Read Image.
*/
egami::Image loadPNG(const etk::Vector<uint8_t>& _buffer);
/**
* @breif Store a PNG file in the image.
* @param[in] _fileName Name of the file.
* @param[in] _inputImage write data.
* @return true if all is done correctly, false otherwise.
*/
bool storePNG(const etk::String& _fileName, const egami::Image& _inputImage);
}

View File

@ -41,7 +41,7 @@ static void readSVG() {
static void readPNG() {
//! [egami_sample_read_file_png]
egami::Image image = egami::load("DATA:read.png");
egami::Image image = egami::load("DATA:read_128x128.png");
//! [egami_sample_read_file_png]
TEST_INFO("image exist (PNG): " << image.exist());
}

View File

@ -13,14 +13,14 @@
static void writeBMP() {
//! [egami_sample_create_image]
// create an empty Image (no type and no inside data)
egami::Image image(ivec2(25,25));
egami::Image image(ivec2(25,25), egami::colorType::RGBA8);
image.set(ivec2(5,5), etk::Color<>(0x88, 0xFF, 0x00, 0xFF));
image.set(ivec2(12,15), etk::Color<>(0x88, 0xFF, 0x00, 0xFF));
image.set(ivec2(4,9), etk::Color<>(0x88, 0xFF, 0x00, 0xFF));
// ...
//! [egami_sample_create_image]
//! [egami_sample_write_file_bmp]
bool ret = egami::store(image, "DATA:read.bmp");
bool ret = egami::store(image, "out/egami_test_write.bmp");
//! [egami_sample_write_file_bmp]
TEST_INFO("image write (BMP): " << ret);
}
@ -30,7 +30,28 @@ static void writeSVG() {
}
static void writePNG() {
TEST_INFO("image write (PNG): Not Avaliiable");
// create an empty Image (no type and no inside data)
egami::Image image(ivec2(25,25), egami::colorType::RGBA8);
image.set(ivec2(5,5), etk::Color<>(0x88, 0xFF, 0x00, 0xFF));
image.set(ivec2(12,15), etk::Color<>(0x88, 0xFF, 0x00, 0xFF));
image.set(ivec2(4,9), etk::Color<>(0x88, 0xFF, 0x00, 0xFF));
// ...
//! [egami_sample_write_file_png]
bool ret = egami::store(image, "out/egami_test_write.png");
//! [egami_sample_write_file_png]
TEST_INFO("image write (PNG): " << ret);
}
static void writeJPG() {
// create an empty Image (no type and no inside data)
egami::Image image(ivec2(25,25), egami::colorType::RGBA8);
image.set(ivec2(5,5), etk::Color<>(0x88, 0xFF, 0x00, 0xFF));
image.set(ivec2(12,15), etk::Color<>(0x88, 0xFF, 0x00, 0xFF));
image.set(ivec2(4,9), etk::Color<>(0x88, 0xFF, 0x00, 0xFF));
// ...
//! [egami_sample_write_file_jpg]
bool ret = egami::store(image, "out/egami_test_write.jpg");
//! [egami_sample_write_file_jpg]
TEST_INFO("image write (JPG): " << ret);
}
@ -38,6 +59,7 @@ void appl::write() {
writeBMP();
writeSVG();
writePNG();
writeJPG();
}
//! [egami_sample_write_all]