[DEV] Add bitmap export with Alpha correct (reverse ingeneer of BMP, do not ask me how it work ...)
This commit is contained in:
parent
85af6d85d0
commit
a1f83ee5da
@ -28,7 +28,7 @@ esvg::PaintState::PaintState() :
|
||||
}
|
||||
|
||||
void esvg::PaintState::clear() {
|
||||
fill = etk::color::none;
|
||||
fill = etk::color::black;
|
||||
stroke = etk::color::none;
|
||||
strokeWidth = 1.0;
|
||||
viewPort.setValue(255,255);
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <esvg/debug.h>
|
||||
#include <esvg/Renderer.h>
|
||||
#include <etk/os/FSNode.h>
|
||||
|
||||
// 4 is for the RGBA ...
|
||||
#define DATA_ALLOCATION_ELEMENT (4)
|
||||
@ -163,29 +164,146 @@ void esvg::Renderer::print(const esvg::render::Weight& _weightFill,
|
||||
#endif
|
||||
|
||||
|
||||
// Writing the buffer to a .PPM file, assuming it has
|
||||
// RGB-structure, one byte per color component
|
||||
//--------------------------------------------------
|
||||
void esvg::Renderer::writePpm(std::string fileName) {
|
||||
void esvg::Renderer::writePPM(const std::string& _fileName) {
|
||||
if (m_buffer.size() == 0) {
|
||||
return;
|
||||
}
|
||||
FILE* fd = fopen(fileName.c_str(), "wb");
|
||||
if(fd != nullptr) {
|
||||
int32_t sizeX = m_size.x();
|
||||
int32_t sizeY = m_size.y();
|
||||
#if DEBUG
|
||||
sizeX *= m_factor;
|
||||
sizeY *= m_factor;
|
||||
#endif
|
||||
SVG_DEBUG("Generate ppm : " << m_size << " debug size=" << ivec2(sizeX,sizeY));
|
||||
fprintf(fd, "P6 %d %d 255 ", sizeX, sizeY);
|
||||
for (int32_t iii=0 ; iii<sizeX*sizeY; iii++) {
|
||||
etk::Color<uint8_t,3> tmp = m_buffer[iii];
|
||||
fwrite(&tmp, 1, 3, fd);
|
||||
}
|
||||
fclose(fd);
|
||||
etk::FSNode tmpFile(_fileName);
|
||||
if(tmpFile.fileOpenWrite() == false) {
|
||||
SVG_ERROR("Can not find the file name=\"" << tmpFile << "\"");
|
||||
return;
|
||||
}
|
||||
int32_t sizeX = m_size.x();
|
||||
int32_t sizeY = m_size.y();
|
||||
#if DEBUG
|
||||
sizeX *= m_factor;
|
||||
sizeY *= m_factor;
|
||||
#endif
|
||||
SVG_DEBUG("Generate ppm : " << m_size << " debug size=" << ivec2(sizeX,sizeY));
|
||||
char tmpValue[1024];
|
||||
sprintf(tmpValue, "P6 %d %d 255 ", sizeX, sizeY);
|
||||
tmpFile.fileWrite(tmpValue,1,sizeof(tmpValue));
|
||||
for (int32_t iii=0 ; iii<sizeX*sizeY; iii++) {
|
||||
etk::Color<uint8_t,3> tmp = m_buffer[iii];
|
||||
tmpFile.fileWrite(&tmp, 1, 3);
|
||||
}
|
||||
tmpFile.fileClose();
|
||||
}
|
||||
#define PLOPPP
|
||||
extern "C" {
|
||||
#pragma pack(push,1)
|
||||
struct bitmapFileHeader {
|
||||
int16_t bfType;
|
||||
int32_t bfSize;
|
||||
int32_t bfReserved;
|
||||
int32_t bfOffBits;
|
||||
};
|
||||
struct bitmapInfoHeader {
|
||||
int32_t biSize;
|
||||
int32_t biWidth;
|
||||
int32_t biHeight;
|
||||
int16_t biPlanes;
|
||||
int16_t biBitCount;
|
||||
int32_t biCompression;
|
||||
int32_t biSizeImage;
|
||||
int32_t biXPelsPerMeter;
|
||||
int32_t biYPelsPerMeter;
|
||||
#ifndef PLOPPP
|
||||
int32_t biClrUsed;
|
||||
int32_t biClrImportant;
|
||||
#else
|
||||
// https://en.wikipedia.org/wiki/BMP_file_format / example 2
|
||||
int32_t biPaletteNumber;
|
||||
int32_t biImportantColor;
|
||||
int32_t biBitMaskRed;
|
||||
int32_t biBitMaskGreen;
|
||||
int32_t biBitMaskBlue;
|
||||
int32_t biBitMaskAlpha;
|
||||
int32_t biLCSColorSpace;
|
||||
int32_t biUnused[16];
|
||||
#endif
|
||||
};
|
||||
#pragma pack(pop)
|
||||
}
|
||||
void esvg::Renderer::writeBMP(const std::string& _fileName) {
|
||||
if (m_buffer.size() == 0) {
|
||||
return;
|
||||
}
|
||||
etk::FSNode tmpFile(_fileName);
|
||||
|
||||
if(tmpFile.fileOpenWrite() == false) {
|
||||
SVG_ERROR("Can not find the file name=\"" << tmpFile << "\"");
|
||||
return;
|
||||
}
|
||||
struct bitmapFileHeader fileHeader;
|
||||
struct bitmapInfoHeader infoHeader;
|
||||
|
||||
int32_t sizeX = m_size.x();
|
||||
int32_t sizeY = m_size.y();
|
||||
#if DEBUG
|
||||
sizeX *= m_factor;
|
||||
sizeY *= m_factor;
|
||||
#endif
|
||||
|
||||
fileHeader.bfType = 0x4D42;
|
||||
fileHeader.bfSize = sizeof(struct bitmapFileHeader) + sizeof(struct bitmapInfoHeader) + sizeX*sizeY*4;
|
||||
fileHeader.bfReserved = 0;
|
||||
fileHeader.bfOffBits = sizeof(struct bitmapFileHeader) + sizeof(struct bitmapInfoHeader);
|
||||
|
||||
|
||||
infoHeader.biSize = sizeof(struct bitmapInfoHeader);
|
||||
infoHeader.biWidth = sizeX;
|
||||
infoHeader.biHeight = sizeY;
|
||||
infoHeader.biPlanes = 1;
|
||||
infoHeader.biBitCount = 32;
|
||||
#ifndef PLOPPP
|
||||
infoHeader.biCompression = 0;
|
||||
#else
|
||||
infoHeader.biCompression = 3;
|
||||
#endif
|
||||
infoHeader.biSizeImage = sizeX*sizeY*4;
|
||||
infoHeader.biXPelsPerMeter = 75;
|
||||
infoHeader.biYPelsPerMeter = 75;
|
||||
#ifndef PLOPPP
|
||||
infoHeader.biClrUsed = 0;
|
||||
infoHeader.biClrImportant = 0;
|
||||
#else
|
||||
infoHeader.biPaletteNumber = 0;
|
||||
infoHeader.biImportantColor = 0;
|
||||
infoHeader.biBitMaskRed = 0xFF000000;
|
||||
infoHeader.biBitMaskGreen = 0x00FF0000;
|
||||
infoHeader.biBitMaskBlue =0x0000FF00;
|
||||
infoHeader.biBitMaskAlpha = 0x000000FF;
|
||||
infoHeader.biLCSColorSpace = 0x73524742; // "???"
|
||||
for (int32_t jjj=0; jjj<16; ++jjj) {
|
||||
infoHeader.biUnused[jjj] = 0;
|
||||
}
|
||||
infoHeader.biUnused[12] = 0x00000002;
|
||||
#endif
|
||||
// get the data :
|
||||
tmpFile.fileWrite(&fileHeader, sizeof(struct bitmapFileHeader), 1);
|
||||
tmpFile.fileWrite(&infoHeader, sizeof(struct bitmapInfoHeader), 1);
|
||||
|
||||
uint8_t data[16];
|
||||
for(int32_t yyy=sizeY-1; yyy>=0; --yyy) {
|
||||
for(int32_t xxx=0; xxx<sizeX; ++xxx) {
|
||||
const etk::Color<uint8_t,4>& tmpColor = m_buffer[sizeX*yyy + xxx];
|
||||
uint8_t* pointer = data;
|
||||
#ifndef PLOPPP
|
||||
*pointer++ = tmpColor.a();
|
||||
*pointer++ = tmpColor.r();
|
||||
*pointer++ = tmpColor.g();
|
||||
*pointer++ = tmpColor.b();
|
||||
#else
|
||||
*pointer++ = tmpColor.a();
|
||||
*pointer++ = tmpColor.b();
|
||||
*pointer++ = tmpColor.g();
|
||||
*pointer++ = tmpColor.r();
|
||||
#endif
|
||||
tmpFile.fileWrite(data,1,4);
|
||||
}
|
||||
}
|
||||
tmpFile.fileClose();
|
||||
}
|
||||
|
||||
|
||||
|
@ -50,7 +50,8 @@ namespace esvg {
|
||||
void setNumberSubScanLine(int32_t _value);
|
||||
int32_t getNumberSubScanLine() const;
|
||||
public:
|
||||
void writePpm(std::string fileName);
|
||||
void writePPM(const std::string& _fileName);
|
||||
void writeBMP(const std::string& _fileName);
|
||||
protected:
|
||||
etk::Color<float,4> mergeColor(etk::Color<float,4> _base, const etk::Color<float,4>& _integration);
|
||||
public:
|
||||
|
@ -85,7 +85,7 @@ void esvg::Document::generateTestFile()
|
||||
std::string tmpFileOut = "yyy_out_";
|
||||
tmpFileOut += m_fileName;
|
||||
tmpFileOut += ".ppm";
|
||||
m_renderedElement->writePpm(tmpFileOut);
|
||||
m_renderedElement->writePPM(tmpFileOut);
|
||||
|
||||
}
|
||||
|
||||
@ -117,7 +117,13 @@ void esvg::Document::generateAnImage(const ivec2& _size, const std::string& _fil
|
||||
//basicTrans *= etk::mat2Translate(vec2(width/3, height/3));
|
||||
|
||||
draw(*m_renderedElement, basicTrans);
|
||||
m_renderedElement->writePpm(_fileName);
|
||||
if (etk::end_with(_fileName, ".ppm") == true) {
|
||||
m_renderedElement->writePPM(_fileName);
|
||||
} else if (etk::end_with(_fileName, ".bmp") == true) {
|
||||
m_renderedElement->writeBMP(_fileName);
|
||||
} else {
|
||||
SVG_ERROR("Can not store with this extention : " << _fileName << " not in .bmp/.ppm");
|
||||
}
|
||||
}
|
||||
/*
|
||||
void esvg::Document::generateAnImage(draw::Image& _output) {
|
||||
|
@ -21,7 +21,7 @@ TEST(TestCircle, fill) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestCircle_fill.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestCircle_fill.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestCircle_fill.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestCircle, stroke) {
|
||||
@ -32,7 +32,7 @@ TEST(TestCircle, stroke) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestCircle_stroke.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestCircle_stroke.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestCircle_stroke.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestCircle, fill_and_stroke) {
|
||||
@ -43,5 +43,5 @@ TEST(TestCircle, fill_and_stroke) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestCircle_fill_and_stroke.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestCircle_fill_and_stroke.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestCircle_fill_and_stroke.bmp", g_visualDebug);
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ TEST(TestEllipse, fill) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestEllipse_fill.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestEllipse_fill.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestEllipse_fill.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestEllipse, stroke) {
|
||||
@ -32,7 +32,7 @@ TEST(TestEllipse, stroke) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestEllipse_stroke.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestEllipse_stroke.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestEllipse_stroke.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestEllipse, fill_and_stroke) {
|
||||
@ -43,6 +43,6 @@ TEST(TestEllipse, fill_and_stroke) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestEllipse_fill_and_stroke.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestEllipse_fill_and_stroke.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestEllipse_fill_and_stroke.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ TEST(TestLine, stroke) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestLine_stroke.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestLine_stroke.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestLine_stroke.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@ TEST(TestPath, fill) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestPath_fill.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestPath_fill.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestPath_fill.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestPath, stroke) {
|
||||
@ -34,7 +34,7 @@ TEST(TestPath, stroke) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestPath_stroke.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestPath_stroke.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestPath_stroke.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestPath, fill_and_stroke) {
|
||||
@ -46,5 +46,5 @@ TEST(TestPath, fill_and_stroke) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestPath_fill_and_stroke.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestPath_fill_and_stroke.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestPath_fill_and_stroke.bmp", g_visualDebug);
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ TEST(TestPolygon, fill) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestPolygon_fill.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestPolygon_fill.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestPolygon_fill.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestPolygon, stroke) {
|
||||
@ -32,7 +32,7 @@ TEST(TestPolygon, stroke) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestPolygon_stroke.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestPolygon_stroke.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestPolygon_stroke.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestPolygon, fill_and_stroke) {
|
||||
@ -43,5 +43,5 @@ TEST(TestPolygon, fill_and_stroke) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestPolygon_fill_and_stroke.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestPolygon_fill_and_stroke.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestPolygon_fill_and_stroke.bmp", g_visualDebug);
|
||||
}
|
@ -21,7 +21,7 @@ TEST(TestRectangle, fill) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestRectangle_fill.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_fill.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_fill.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestRectangle, stroke) {
|
||||
@ -32,7 +32,7 @@ TEST(TestRectangle, stroke) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestRectangle_stroke.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_stroke.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_stroke.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestRectangle, fill_and_stroke) {
|
||||
@ -43,7 +43,7 @@ TEST(TestRectangle, fill_and_stroke) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestRectangle_fill_and_stroke.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_fill_and_stroke.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_fill_and_stroke.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestRectangle, fill_and_stroke_blend) {
|
||||
@ -54,7 +54,7 @@ TEST(TestRectangle, fill_and_stroke_blend) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestRectangle_fill_and_stroke_blend.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_fill_and_stroke_blend.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_fill_and_stroke_blend.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestRectangle, fill_and_stroke_opacity) {
|
||||
@ -65,7 +65,7 @@ TEST(TestRectangle, fill_and_stroke_opacity) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestRectangle_fill_and_stroke_blend.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_fill_and_stroke_blend.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_fill_and_stroke_blend.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestRectangle, corned_fill) {
|
||||
@ -76,7 +76,7 @@ TEST(TestRectangle, corned_fill) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestRectangle_corned_fill.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_corned_fill.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_corned_fill.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestRectangle, corned_stroke) {
|
||||
@ -87,7 +87,7 @@ TEST(TestRectangle, corned_stroke) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestRectangle_corned_stroke.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_corned_stroke.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_corned_stroke.bmp", g_visualDebug);
|
||||
}
|
||||
|
||||
TEST(TestRectangle, corned_fill_and_stroke) {
|
||||
@ -98,5 +98,5 @@ TEST(TestRectangle, corned_fill_and_stroke) {
|
||||
esvg::Document doc;
|
||||
doc.parse(data);
|
||||
etk::FSNodeWriteAllData("TestRectangle_corned_fill_and_stroke.svg", data);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_corned_fill_and_stroke.ppm", g_visualDebug);
|
||||
doc.generateAnImage(ivec2(100, 100), "TestRectangle_corned_fill_and_stroke.bmp", g_visualDebug);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user