[DEV] add store in png
This commit is contained in:
parent
7965135796
commit
99eae9d10f
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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]
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user