[DEV] add stupid edf simple image file

This commit is contained in:
Edouard DUPIN 2014-01-19 19:14:35 +01:00
parent d7363f73e0
commit 929f4a4136
7 changed files with 323 additions and 5 deletions

View File

@ -7,6 +7,7 @@
*/
#include <egami/Image.h>
#include <egami/debug.h>
egami::Image::Image(const ivec2& _size) :
m_size(_size) {
@ -43,6 +44,21 @@ void egami::Image::resize(const ivec2& _size, const ivec2& _startPos) {
}
}
void egami::Image::scale(const ivec2& _size) {
// TODO : Add capabilities ...
int32_t stepX = m_size.x() / _size.x();
int32_t stepY = m_size.y() / _size.y();
stepX = etk_max(1, stepX);
stepY = etk_max(1, stepY);
EGAMI_VERBOSE("move : " << stepX << " , " << stepY << " from : " << m_size << " ==> " << _size);
for (int32_t yyy = 0; yyy < _size.y(); ++yyy) {
for (int32_t xxx = 0; xxx < _size.x(); ++xxx) {
set(ivec2(xxx, yyy), get(ivec2(xxx*stepX, yyy*stepY)));
}
}
resize(_size);
}
void egami::Image::clear(etk::Color<> _fill) {
for (int32_t iii=0; iii<m_size.x()*m_size.y(); iii++) {

View File

@ -49,6 +49,12 @@ namespace egami {
const etk::Color<>& get(const ivec2& _pos) const;
void set(const ivec2& _pos, const etk::Color<>& _newColor);
void insert(const ivec2& _pos, const egami::Image& _input);
/**
* @brief Scale an image in an other dimention.
* @param[in] _size Destination size of the image.
* @TODO Set this function more capacity like not a multiple ratio...
*/
void scale(const ivec2& _size);
};
};

View File

@ -12,6 +12,8 @@
#include <egami/wrapperSVG.h>
#include <egami/wrapperPNG.h>
#include <egami/wrapperBMP.h>
#include <egami/wrapperEDF.h>
#include <edtaa3/edtaa3func.h>
bool egami::scalable(const std::string& _fileName) {
if (true == end_with(_fileName, ".svg") ) {
@ -23,7 +25,12 @@ bool egami::scalable(const std::string& _fileName) {
bool egami::load(egami::Image& _output, const std::string& _fileName, const ivec2& _size) {
std::string tmpName = std::tolower(_fileName);
// select the corect Loader :
if (true == end_with(tmpName, ".bmp") ) {
if (true == end_with(tmpName, ".edf") ) { // internal format for ewol distance field ==> simple sistance field image
if (false == egami::loadEDF(_fileName, _output)) {
EGAMI_ERROR("Error to load EDF file '" << _fileName << "'");
return false;
}
} else if (true == end_with(tmpName, ".bmp") ) {
if (false == egami::loadBMP(_fileName, _output)) {
EGAMI_ERROR("Error to load BMP file '" << _fileName << "'");
return false;
@ -33,13 +40,14 @@ bool egami::load(egami::Image& _output, const std::string& _fileName, const ivec
EGAMI_ERROR("Error to load SVG file '" << _fileName << "'");
return false;
}
egami::storeEDF(_fileName + ".edf", _output);
} else if (true == end_with(tmpName, ".png") ) {
if (false == egami::loadPNG(_fileName, _output)) {
EGAMI_ERROR("Error to load PNG file '" << _fileName << "'");
return false;
}
} else {
EGAMI_ERROR("Extention not managed '" << _fileName << "' Sopported extention : .bmp / .svg / .png");
EGAMI_ERROR("Extention not managed '" << _fileName << "' Sopported extention : .edf / .bmp / .svg / .png");
return false;
}
return true;
@ -47,8 +55,14 @@ bool egami::load(egami::Image& _output, const std::string& _fileName, const ivec
bool egami::store(const egami::Image& _input, const std::string& _fileName) {
std::string tmpName = std::tolower(_fileName);
EGAMI_DEBUG("Store file : " << _fileName);
// select the corect Loader :
if (true == end_with(tmpName, ".bmp") ) {
if (true == end_with(tmpName, ".edf") ) {
if (false == egami::storeEDF(_fileName, _input)) {
EGAMI_ERROR("Error to load EDF file '" << _fileName << "'");
return false;
}
} else if (true == end_with(tmpName, ".bmp") ) {
if (false == egami::storeBMP(_fileName, _input)) {
EGAMI_ERROR("Error to load BMP file '" << _fileName << "'");
return false;
@ -65,3 +79,110 @@ bool egami::store(const egami::Image& _input, const std::string& _fileName) {
}
return true;
}
static void generateDistanceField(const egami::ImageMono& _input, egami::Image& _output) {
int32_t size = _input.getSize().x() * _input.getSize().y();
std::vector<short> xdist(size);
std::vector<short> ydist(size);
std::vector<double> gx(size);
std::vector<double> gy(size);
std::vector<double> data(size);
std::vector<double> outside(size);
std::vector<double> inside(size);
// Convert img into double (data)
double img_min = 255, img_max = -255;
for (int32_t yyy = 0; yyy < _input.getSize().y(); ++yyy) {
for (int32_t xxx = 0; xxx < _input.getSize().x(); ++xxx) {
int32_t iii = yyy * _input.getSize().x() + xxx;
double v = _input.get(ivec2(xxx, yyy));
data[iii] = v;
if (v > img_max) {
img_max = v;
}
if (v < img_min) {
img_min = v;
}
}
}
// Rescale image levels between 0 and 1
for (int32_t yyy = 0; yyy < _input.getSize().y(); ++yyy) {
for (int32_t xxx = 0; xxx < _input.getSize().x(); ++xxx) {
int32_t iii = yyy * _input.getSize().x() + xxx;
data[iii] = (_input.get(ivec2(xxx, yyy))-img_min)/img_max;
}
}
// Compute outside = edtaa3(bitmap); % Transform background (0's)
computegradient(&data[0], _input.getSize().x(), _input.getSize().y(), &gx[0], &gy[0]);
edtaa3(&data[0], &gx[0], &gy[0], _input.getSize().x(), _input.getSize().y(), &xdist[0], &ydist[0], &outside[0]);
for(size_t iii = 0; iii < outside.size(); ++iii) {
if( outside[iii] < 0 ) {
outside[iii] = 0.0;
}
}
// Compute inside = edtaa3(1-bitmap); % Transform foreground (1's)
for(size_t iii = 0; iii < gx.size(); ++iii) {
gx[iii] = 0;
}
for(size_t iii = 0; iii < gy.size(); ++iii) {
gy[iii] = 0;
}
for(size_t iii = 0; iii < data.size(); ++iii) {
data[iii] = 1 - data[iii];
}
computegradient( &data[0], _input.getSize().x(), _input.getSize().y(), &gx[0], &gy[0]);
edtaa3(&data[0], &gx[0], &gy[0], _input.getSize().x(), _input.getSize().y(), &xdist[0], &ydist[0], &inside[0]);
for(size_t iii = 0; iii < inside.size(); ++iii) {
if( inside[iii] < 0 ) {
inside[iii] = 0.0;
}
}
_output.resize(_input.getSize(), etk::Color<>(0));
_output.clear(etk::Color<>(0));
for (int32_t xxx = 0; xxx < _output.getSize().x(); ++xxx) {
for (int32_t yyy = 0; yyy < _output.getSize().y(); ++yyy) {
int32_t iii = yyy * _output.getSize().x() + xxx;
outside[iii] -= inside[iii];
outside[iii] = 128+outside[iii]*16;
if( outside[iii] < 0 ) {
outside[iii] = 0;
}
if( outside[iii] > 255 ) {
outside[iii] = 255;
}
uint8_t val = 255 - (unsigned char) outside[iii];
// TODO : Remove multiple size of the map ...
_output.set(ivec2(xxx, yyy), etk::Color<>((int32_t)val,(int32_t)val,(int32_t)val,(int32_t)val));
}
}
}
bool egami::generateDistanceFieldFile(const std::string& _input, const std::string& _output) {
egami::Image data;
if (std::end_with(_input, ".edf") == true) {
return false;
}
EGAMI_ERROR("Generate distance field : '" << _input << "' ==> '" << _output << "'");
if (egami::load(data, _input, ivec2(64*5,64*5)) == false) {
return false;
}
// Generate distance field :
egami::ImageMono input;
input.resize(data.getSize());
for (size_t yyy = 0; yyy < data.getSize().y(); ++yyy) {
for (size_t xxx = 0; xxx < data.getSize().x(); ++xxx) {
input.set(ivec2(xxx, yyy), data.get(ivec2(xxx, yyy)).a() );
}
}
generateDistanceField(input, data);
// scale:
data.scale(ivec2(64,64));
// store:
return egami::store(data, _output);
}

View File

@ -39,6 +39,14 @@ namespace egami
* @return true if the format is scalable.
*/
bool scalable(const std::string& _fileName);
/**
* @brief Generate a distance field output file from an input file;
* @param[in] _input Input file name
* @param[in] _output Output file name
* @return true All done corectly.
* @return false An error occured.
*/
bool generateDistanceFieldFile(const std::string& _input, const std::string& _output);
};
#endif

125
egami/wrapperEDF.cpp Normal file
View File

@ -0,0 +1,125 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license BSD v3 (see license file)
*/
#include <etk/types.h>
#include <egami/debug.h>
#include <egami/Image.h>
#include <egami/wrapperEDF.h>
#include <etk/os/FSNode.h>
#undef __class__
#define __class__ "wrapperEDF"
//EDF format is a simple format for image in text for distance field image (special case)
// it is composed of the fist line : description of type (starting with #EDF and some other information, the data start just after the first \n
bool egami::loadEDF(const std::string& _inputFile, egami::Image& _ouputImage) {
etk::FSNode file(_inputFile);
if (false == file.exist()) {
EGAMI_ERROR("File does not existed='" << file << "'");
return false;
}
if(false == file.fileOpenRead() ) {
EGAMI_ERROR("Can not find the file name='" << file << "'");
return false;
}
std::string line;
file.fileGets(line);
if (std::start_with(line, "#edf", false) == false) {
EGAMI_ERROR("This file seams not to be a EDF file ...");
file.fileClose();
return false;
}
// count number of colomn max an number of line max:
ivec2 size(0,0);
while (file.fileGets(line) == true) {
if (line.size()/2 > (size_t)size.x()) {
size.setValue(line.size()/2, size.y()+1);
} else {
size += ivec2(0,1);
}
}
if (line.size()/2 > (size_t)size.x()) {
size.setValue(line.size()/2, size.y()+1);
} else {
size += ivec2(0,1);
}
EGAMI_DEBUG("'" << file << "' ==> size=" << size);
// jup to the start of the file
file.fileSeek(0, etk::FSN_SEEK_START);
// drop the first line
file.fileGets(line);
// resize output:
_ouputImage.resize(size);
int32_t currentLineId = 0;
char tmp[3];
tmp[2] = '\0';
while (file.fileGets(line) == true) {
if (line.size() <= 0) {
continue;
}
for (size_t xxx = 0; xxx < line.size()-1; xxx+=2) {
tmp[0] = line[xxx];
tmp[1] = line[xxx+1];
int32_t val = 0;
sscanf(tmp, "%x", &val);
_ouputImage.set(ivec2(xxx/2, currentLineId), etk::Color<>((uint8_t)val, (uint8_t)val, (uint8_t)val, (uint8_t)val));
}
++currentLineId;
}
if (line.size() > 0) {
for (size_t xxx = 0; xxx < line.size()-1; xxx+=2) {
tmp[0] = line[xxx];
tmp[1] = line[xxx+1];
int32_t val = 0;
sscanf(tmp, "%x", &val);
_ouputImage.set(ivec2(xxx/2, currentLineId), etk::Color<>((uint8_t)val, (uint8_t)val, (uint8_t)val, (uint8_t)val));
}
}
file.fileClose();
return true;
}
bool egami::storeEDF(const std::string& _fileName, const egami::Image& _inputImage) {
bool anErrorEccured = false;
etk::FSNode file(_fileName);
if (file.fileOpenWrite() == false) {
EGAMI_ERROR("Can not find the file name=\"" << file << "\"");
return false;
}
anErrorEccured = file.filePuts( std::string("#EDF // Generate with EGAMI (")
+ std::to_string(_inputImage.getSize().x())
+ ","
+ std::to_string(_inputImage.getSize().y()) + ")\n");
char tmp[256];
for (int32_t yyy = 0; yyy < _inputImage.getSize().y(); ++yyy) {
if (yyy != 0) {
if (file.filePut('\n') == false) {
anErrorEccured = false;
}
}
for (int32_t xxx = 0; xxx < _inputImage.getSize().x(); ++xxx) {
sprintf(tmp, "%02X", _inputImage.get(ivec2(xxx, yyy)).a());
/*
if (yyy == 25) {
EGAMI_DEBUG(" set : " << _inputImage.get(ivec2(xxx, yyy)) << " : '" << tmp << "'");
}
*/
if (file.filePuts(tmp) == false) {
anErrorEccured = false;
}
}
}
file.fileClose();
return anErrorEccured;
}

41
egami/wrapperEDF.h Normal file
View File

@ -0,0 +1,41 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license BSD v3 (see license file)
*/
#ifndef __EGAMI_WRAPPER_EDF_H__
#define __EGAMI_WRAPPER_EDF_H__
#include <egami/egami.h>
namespace egami {
/**
* @breif Load a bmp file in the image.
* A simple example of EDF file is :
* [PRE]
* #EDF //Example Of EDF file (5,5)
* *
* * *
* * *
* * *
* *
* [PRE]
* @param[in] _fileName Name of the file.
* @param[out] _ouputImage Read data.
* @return true if all is done correctly, false otherwise.
*/
bool loadEDF(const std::string& _fileName, egami::Image& _ouputImage);
/**
* @breif Store a edf 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 storeEDF(const std::string& _fileName, const egami::Image& _inputImage);
};
#endif

View File

@ -20,10 +20,11 @@ def create(target):
'egami/debug.cpp',
'egami/wrapperPNG.cpp',
'egami/wrapperSVG.cpp',
'egami/wrapperBMP.cpp'])
'egami/wrapperBMP.cpp',
'egami/wrapperEDF.cpp'])
# name of the dependency
myModule.add_module_depend(['etk', 'png', 'esvg'])
myModule.add_module_depend(['etk', 'png', 'esvg', 'edtaa3'])
myModule.compile_flags_CC([
'-Wno-write-strings',