314 lines
9.0 KiB
C++
314 lines
9.0 KiB
C++
/**
|
|
*******************************************************************************
|
|
* @file parserSVG/Base.cpp
|
|
* @brief basic Element parsing (Sources)
|
|
* @author Edouard DUPIN
|
|
* @date 20/03/2012
|
|
* @par Project
|
|
* parserSVG
|
|
*
|
|
* @par Copyright
|
|
* Copyright 2011 Edouard DUPIN, all right reserved
|
|
*
|
|
* This software is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY.
|
|
*
|
|
* Licence summary :
|
|
* You can modify and redistribute the sources code and binaries.
|
|
* You can send me the bug-fix
|
|
*
|
|
* Term of the licence in in the file licence.txt.
|
|
*
|
|
*******************************************************************************
|
|
*/
|
|
|
|
|
|
#include <parserSVG/Debug.h>
|
|
#include <parserSVG/Base.h>
|
|
#include <math.h>
|
|
|
|
svg::Base::Base(paintState_ts parentPaintState)
|
|
{
|
|
// copy the parent painting properties ...
|
|
m_paint = parentPaintState;
|
|
}
|
|
|
|
/**
|
|
* @brief Parse the transform balise C String.
|
|
* @param[in] inputString String data inside the transform attribute
|
|
* @param[in,out] baseMatrice matrice that must be update
|
|
* @return ---
|
|
*/
|
|
void svg::Base::ParseTransform(TiXmlNode *node)
|
|
{
|
|
SVG_CHECK_INOUT(node);
|
|
const char * inputString = (char*)node->ToElement()->Attribute("transform");
|
|
if (NULL == inputString) {
|
|
return;
|
|
}
|
|
char tmpData[2048];
|
|
for (int32_t iii=0; inputString[iii]=='\0' && iii<2047; iii++) {
|
|
if (inputString[iii] == ',') {
|
|
tmpData[iii] = ' ';
|
|
} else {
|
|
tmpData[iii] = inputString[iii];
|
|
}
|
|
// end of the string ...
|
|
tmpData[iii+1] = '\0';
|
|
}
|
|
etkFloat_t base[6];
|
|
etkFloat_t zzz[6];
|
|
etkFloat_t angle, xxx, yyy;
|
|
int32_t n;
|
|
char * pointerOnData = tmpData;
|
|
while (*pointerOnData) {
|
|
base[0] = 1.0;
|
|
base[1] = 0.0;
|
|
base[2] = 0.0;
|
|
base[3] = 1.0;
|
|
base[4] = 0.0;
|
|
base[5] = 0.0;
|
|
if (sscanf(pointerOnData, "matrix (%f %f %f %f %f %f) %n", &base[0], &base[1], &base[2], &base[3], &base[4], &base[5], &n) == 6) {
|
|
// nothing to do ...
|
|
} else if (sscanf(pointerOnData, "translate (%f %f) %n", &base[4], &base[5], &n) == 2) {
|
|
// nothing to do ...
|
|
} else if (sscanf(pointerOnData, "translate (%f) %n", &base[4], &n) == 1) {
|
|
// nothing to do ...
|
|
} else if (sscanf(pointerOnData, "scale (%f %f) %n", &base[0], &base[3], &n) == 2) {
|
|
// nothing to do ...
|
|
} else if (sscanf(pointerOnData, "scale (%f) %n", &base[0], &n) == 1) {
|
|
base[3] = base[0];
|
|
} else if (sscanf(pointerOnData, "rotate (%f %f %f) %n", &angle, &xxx, &yyy, &n) == 3) {
|
|
angle = angle / 180 * M_PI;
|
|
base[0] = cos(angle);
|
|
base[1] = sin(angle);
|
|
base[2] = -sin(angle);
|
|
base[3] = cos(angle);
|
|
base[4] = -xxx * cos(angle) + yyy * sin(angle) + xxx;
|
|
base[5] = -xxx * sin(angle) - yyy * cos(angle) + yyy;
|
|
} else if (sscanf(pointerOnData, "rotate (%f) %n", &angle, &n) == 1) {
|
|
angle = angle / 180 * M_PI;
|
|
base[0] = cos(angle);
|
|
base[1] = sin(angle);
|
|
base[2] = -sin(angle);
|
|
base[3] = cos(angle);
|
|
} else if (sscanf(pointerOnData, "skewX (%f) %n", &angle, &n) == 1) {
|
|
angle = angle / 180 * M_PI;
|
|
base[2] = tan(angle);
|
|
} else if (sscanf(pointerOnData, "skewY (%f) %n", &angle, &n) == 1) {
|
|
angle = angle / 180 * M_PI;
|
|
base[1] = tan(angle);
|
|
} else {
|
|
break;
|
|
}
|
|
zzz[0] = m_paint.matrix[0]*base[0] + m_paint.matrix[2]*base[1];
|
|
zzz[1] = m_paint.matrix[1]*base[0] + m_paint.matrix[3]*base[1];
|
|
zzz[2] = m_paint.matrix[0]*base[2] + m_paint.matrix[2]*base[3];
|
|
zzz[3] = m_paint.matrix[1]*base[2] + m_paint.matrix[3]*base[3];
|
|
zzz[4] = m_paint.matrix[0]*base[4] + m_paint.matrix[2]*base[5] + m_paint.matrix[4];
|
|
zzz[5] = m_paint.matrix[1]*base[4] + m_paint.matrix[3]*base[5] + m_paint.matrix[5];
|
|
memcpy(m_paint.matrix, zzz, sizeof(etkFloat_t) * 6 );
|
|
pointerOnData += n;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Parse x, y, width, height attribute of the xml node
|
|
* @param[in] node XML node
|
|
* @param[out] pos parsed position
|
|
* @param[out] size parsed dimention
|
|
* @return ---
|
|
*/
|
|
void svg::Base::ParsePosition(const TiXmlNode *node, coord2D_ts &pos, coord2D_ts &size)
|
|
{
|
|
pos.x = 0;
|
|
pos.y = 0;
|
|
size.x = m_paint.viewPort.x;
|
|
size.y = m_paint.viewPort.y;
|
|
|
|
const char * content = node->ToElement()->Attribute("x");
|
|
if (NULL != content) {
|
|
pos.x = ParseLength(content);
|
|
}
|
|
content = node->ToElement()->Attribute("y");
|
|
if (NULL != content) {
|
|
pos.y = ParseLength(content);
|
|
}
|
|
content = node->ToElement()->Attribute("width");
|
|
if (NULL != content) {
|
|
size.x = ParseLength(content);
|
|
}
|
|
content = node->ToElement()->Attribute("height");
|
|
if (NULL != content) {
|
|
size.y = ParseLength(content);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Parse a lenght of the xml element
|
|
* @param[in] dataInput Data C String with the printed lenght
|
|
* @return standart number of pixels
|
|
*/
|
|
etkFloat_t svg::Base::ParseLength(const char *dataInput)
|
|
{
|
|
int32_t numLength = strspn(dataInput, "0123456789+-.");
|
|
const char *unit = dataInput + numLength;
|
|
etkFloat_t n = atof(dataInput);
|
|
etkFloat_t font_size = 20.0;
|
|
|
|
if (unit[0] == '\0') {
|
|
return n;
|
|
} else if (unit[0] == '%') { // xxx %
|
|
return n / 100.0 * m_paint.viewPort.x;
|
|
} else if (unit[0] == 'e' && unit[1] == 'm') { // xxx em
|
|
return n * font_size;
|
|
} else if (unit[0] == 'e' && unit[1] == 'x') { // xxx ex
|
|
return n / 2.0 * font_size;
|
|
} else if (unit[0] == 'p' && unit[1] == 'x') { // xxx px
|
|
return n;
|
|
} else if (unit[0] == 'p' && unit[1] == 't') { // xxx pt
|
|
return n * 1.25;
|
|
} else if (unit[0] == 'p' && unit[1] == 'c') { // xxx pc
|
|
return n * 15.0;
|
|
} else if (unit[0] == 'm' && unit[1] == 'm') { // xxx mm
|
|
return n * 3.543307;
|
|
} else if (unit[0] == 'c' && unit[1] == 'm') { // xxx cm
|
|
return n * 35.43307;
|
|
} else if (unit[0] == 'i' && unit[1] == 'n') { // xxx in
|
|
return n * 90;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Parse a Painting attribute of a specific node
|
|
* @param[in] node : basic node of the XML that might be parsed
|
|
* @return ---
|
|
*/
|
|
void svg::Base::ParsePaintAttr(const TiXmlNode *node)
|
|
{
|
|
const char * content = node->ToElement()->Attribute("fill");
|
|
if (NULL != content) {
|
|
m_paint.fill = ParseColor(content);
|
|
}
|
|
content = node->ToElement()->Attribute("stroke");
|
|
if (NULL != content) {
|
|
m_paint.stroke = ParseColor(content);
|
|
}
|
|
content = node->ToElement()->Attribute("stroke-width");
|
|
if (NULL != content) {
|
|
m_paint.strokeWidth = ParseLength(content);
|
|
}
|
|
content = node->ToElement()->Attribute("style");
|
|
if (NULL != content) {
|
|
const char *sss;
|
|
if ((sss = strstr(content, "fill:"))) {
|
|
sss += 5;
|
|
while( sss[0] ==' '
|
|
&& sss[0]!='\0' ) {
|
|
sss++;
|
|
}
|
|
m_paint.fill = ParseColor(sss);
|
|
}
|
|
if ((sss = strstr(content, "stroke:"))) {
|
|
sss += 7;
|
|
while( sss[0] ==' '
|
|
&& sss[0]!='\0' ) {
|
|
sss++;
|
|
}
|
|
m_paint.stroke = ParseColor(sss);
|
|
}
|
|
if ((sss = strstr(content, "stroke-width:"))) {
|
|
sss += 13;
|
|
while( sss[0] ==' '
|
|
&& sss[0]!='\0' ) {
|
|
sss++;
|
|
}
|
|
m_paint.strokeWidth = ParseLength(sss);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Parse a color specification from the svg file
|
|
* @param[in] inputData Data C String with the xml definition
|
|
* @return the parsed color
|
|
*/
|
|
color_ts svg::Base::ParseColor(const char *inputData)
|
|
{
|
|
color_ts localColor;
|
|
localColor.red =1.0;
|
|
localColor.green=1.0;
|
|
localColor.blue =1.0;
|
|
localColor.alpha=1.0;
|
|
|
|
uint32_t red, green, blue;
|
|
size_t len = strlen(inputData);
|
|
|
|
if( len == 4
|
|
&& inputData[0] == '#') {
|
|
if (sscanf(inputData + 1, "%1x%1x%1x", &red, &green, &blue) == 3) {
|
|
localColor.red = (etkFloat_t)(red | red << 4) / 256.0;
|
|
localColor.green= (etkFloat_t)(green | green << 4) / 256.0;
|
|
localColor.blue = (etkFloat_t)(blue | blue << 4) / 256.0;
|
|
}
|
|
} else if( len == 7
|
|
&& inputData[0] == '#') {
|
|
if (sscanf(inputData + 1, "%2x%2x%2x", &red, &green, &blue) == 3) {
|
|
localColor.red = (etkFloat_t)(red) / 256.0;
|
|
localColor.green= (etkFloat_t)(green) / 256.0;
|
|
localColor.blue = (etkFloat_t)(blue) / 256.0;
|
|
}
|
|
} else if( 10 <= len
|
|
&& inputData[0] == 'r'
|
|
&& inputData[1] == 'g'
|
|
&& inputData[2] == 'b'
|
|
&& inputData[3] == '('
|
|
&& inputData[len - 1] == ')') {
|
|
if (sscanf(inputData + 4, "%u,%u,%u", &red, &green, &blue) == 3) {
|
|
localColor.red = (etkFloat_t)(red) / 256.0;
|
|
localColor.green= (etkFloat_t)(green) / 256.0;
|
|
localColor.blue = (etkFloat_t)(blue) / 256.0;
|
|
} else if (sscanf(inputData + 4, "%f%%,%f%%,%f%%", &localColor.red, &localColor.green, &localColor.blue) == 3) {
|
|
// nothing to do ...
|
|
}
|
|
} else if( len == 4
|
|
&& strcmp(inputData, "none") == 0) {
|
|
localColor.alpha=0.0;
|
|
} else if( 5 < len
|
|
&& inputData[0] == 'u'
|
|
&& inputData[1] == 'r'
|
|
&& inputData[2] == 'l'
|
|
&& inputData[3] == '(') {
|
|
if (inputData[4] == '#') {
|
|
// TODO : parse gradient ...
|
|
}
|
|
} else {
|
|
// TODO : Might be a named color ... need to find it ...
|
|
}
|
|
return localColor;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Parse all the element needed in the basic node
|
|
* @param[in] node standart XML node
|
|
* @return true if no problem arrived
|
|
*/
|
|
bool svg::Base::Parse(TiXmlNode * node)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
const char * svg::Base::SpacingDist(int32_t spacing)
|
|
{
|
|
static const char *tmpValue = " ";
|
|
if (spacing>20) {
|
|
spacing = 20;
|
|
}
|
|
return tmpValue + 20*4 - spacing*4;
|
|
} |