mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
loader/svg: Support hsl color format
Support parsing of hsl(hue, saturation, brightness) color type and conversion to rgb color.
This commit is contained in:
parent
712fc3cfea
commit
dea08681c0
1 changed files with 127 additions and 12 deletions
|
@ -103,15 +103,19 @@ static const char* _skipComma(const char* content)
|
|||
}
|
||||
|
||||
|
||||
static bool _parseNumber(const char** content, float* number)
|
||||
static bool _parseNumber(const char** content, const char** end, float* number)
|
||||
{
|
||||
char* end = nullptr;
|
||||
const char* _end = end ? *end : nullptr;
|
||||
|
||||
*number = strToFloat(*content, &end);
|
||||
*number = strToFloat(*content, (char**)&_end);
|
||||
//If the start of string is not number
|
||||
if ((*content) == end) return false;
|
||||
if ((*content) == _end) {
|
||||
if (end) *end = _end;
|
||||
return false;
|
||||
}
|
||||
//Skip comma if any
|
||||
*content = _skipComma(end);
|
||||
*content = _skipComma(_end);
|
||||
if (end) *end = _end;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -576,6 +580,93 @@ static constexpr struct
|
|||
};
|
||||
|
||||
|
||||
static bool _hslToRgb(float hue, float satuation, float brightness, uint8_t* red, uint8_t* green, uint8_t* blue)
|
||||
{
|
||||
if (!red || !green || !blue) return false;
|
||||
|
||||
float sv, vsf, f, p, q, t, v;
|
||||
float _red = 0, _green = 0, _blue = 0;
|
||||
uint32_t i = 0;
|
||||
|
||||
if (mathZero(satuation)) _red = _green = _blue = brightness;
|
||||
else {
|
||||
if (mathEqual(hue, 360.0)) hue = 0.0f;
|
||||
hue /= 60.0f;
|
||||
|
||||
v = (brightness <= 0.5f) ? (brightness * (1.0f + satuation)) : (brightness + satuation - (brightness * satuation));
|
||||
p = brightness + brightness - v;
|
||||
|
||||
if (!mathZero(v)) sv = (v - p) / v;
|
||||
else sv = 0;
|
||||
|
||||
i = static_cast<uint8_t>(hue);
|
||||
f = hue - i;
|
||||
|
||||
vsf = v * sv * f;
|
||||
|
||||
t = p + vsf;
|
||||
q = v - vsf;
|
||||
|
||||
switch (i) {
|
||||
case 0: {
|
||||
_red = v;
|
||||
_green = t;
|
||||
_blue = p;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
_red = q;
|
||||
_green = v;
|
||||
_blue = p;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
_red = p;
|
||||
_green = v;
|
||||
_blue = t;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
_red = p;
|
||||
_green = q;
|
||||
_blue = v;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
_red = t;
|
||||
_green = p;
|
||||
_blue = v;
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
_red = v;
|
||||
_green = p;
|
||||
_blue = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i = static_cast<uint8_t>(_red * 255.0);
|
||||
f = (_red * 255.0) - i;
|
||||
_red = (f <= 0.5) ? i : (i + 1);
|
||||
|
||||
i = static_cast<uint8_t>(_green * 255.0);
|
||||
f = (_green * 255.0) - i;
|
||||
_green = (f <= 0.5) ? i : (i + 1);
|
||||
|
||||
i = static_cast<uint8_t>(_blue * 255.0);
|
||||
f = (_blue * 255.0) - i;
|
||||
_blue = (f <= 0.5) ? i : (i + 1);
|
||||
|
||||
*red = static_cast<uint8_t>(_red);
|
||||
*green = static_cast<uint8_t>(_green);
|
||||
*blue = static_cast<uint8_t>(_blue);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char** ref)
|
||||
{
|
||||
unsigned int len = strlen(str);
|
||||
|
@ -625,6 +716,30 @@ static void _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
|
|||
} else if (ref && len >= 3 && !strncmp(str, "url", 3)) {
|
||||
if (*ref) free(*ref);
|
||||
*ref = _idFromUrl((const char*)(str + 3));
|
||||
} else if (len >= 10 && (str[0] == 'h' || str[0] == 'H') && (str[1] == 's' || str[1] == 'S') && (str[2] == 'l' || str[2] == 'L') && str[3] == '(' && str[len - 1] == ')') {
|
||||
float_t th, ts, tb;
|
||||
const char *content, *hue, *satuation, *brightness;
|
||||
content = str + 4;
|
||||
content = _skipSpace(content, nullptr);
|
||||
if (_parseNumber(&content, &hue, &th) && hue) {
|
||||
th = static_cast<uint32_t>(th) % 360;
|
||||
hue = _skipSpace(hue, nullptr);
|
||||
hue = (char*)_skipComma(hue);
|
||||
hue = _skipSpace(hue, nullptr);
|
||||
if (_parseNumber(&hue, &satuation, &ts) && satuation && *satuation == '%') {
|
||||
ts /= 100.0f;
|
||||
satuation = _skipSpace(satuation + 1, nullptr);
|
||||
satuation = (char*)_skipComma(satuation);
|
||||
satuation = _skipSpace(satuation, nullptr);
|
||||
if (_parseNumber(&satuation, &brightness, &tb) && brightness && *brightness == '%') {
|
||||
tb /= 100.0f;
|
||||
brightness = _skipSpace(brightness + 1, nullptr);
|
||||
if (brightness && brightness[0] == ')' && brightness[1] == '\0') {
|
||||
if (_hslToRgb(th, ts, tb, r, g, b)) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Handle named color
|
||||
for (unsigned int i = 0; i < (sizeof(colors) / sizeof(colors[0])); i++) {
|
||||
|
@ -854,10 +969,10 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value)
|
|||
doc->viewFlag = (doc->viewFlag | SvgViewFlag::Height);
|
||||
}
|
||||
} else if (!strcmp(key, "viewBox")) {
|
||||
if (_parseNumber(&value, &doc->vx)) {
|
||||
if (_parseNumber(&value, &doc->vy)) {
|
||||
if (_parseNumber(&value, &doc->vw)) {
|
||||
if (_parseNumber(&value, &doc->vh)) {
|
||||
if (_parseNumber(&value, nullptr, &doc->vx)) {
|
||||
if (_parseNumber(&value, nullptr, &doc->vy)) {
|
||||
if (_parseNumber(&value, nullptr, &doc->vw)) {
|
||||
if (_parseNumber(&value, nullptr, &doc->vh)) {
|
||||
doc->viewFlag = (doc->viewFlag | SvgViewFlag::Viewbox);
|
||||
loader->svgParse->global.h = doc->vh;
|
||||
}
|
||||
|
@ -1267,8 +1382,8 @@ static bool _attrParseSymbolNode(void* data, const char* key, const char* value)
|
|||
SvgSymbolNode* symbol = &(node->node.symbol);
|
||||
|
||||
if (!strcmp(key, "viewBox")) {
|
||||
if (!_parseNumber(&value, &symbol->vx) || !_parseNumber(&value, &symbol->vy)) return false;
|
||||
if (!_parseNumber(&value, &symbol->vw) || !_parseNumber(&value, &symbol->vh)) return false;
|
||||
if (!_parseNumber(&value, nullptr, &symbol->vx) || !_parseNumber(&value, nullptr, &symbol->vy)) return false;
|
||||
if (!_parseNumber(&value, nullptr, &symbol->vw) || !_parseNumber(&value, nullptr, &symbol->vh)) return false;
|
||||
symbol->hasViewBox = true;
|
||||
} else if (!strcmp(key, "width")) {
|
||||
symbol->w = _toFloat(loader->svgParse, value, SvgParserLengthType::Horizontal);
|
||||
|
@ -1616,7 +1731,7 @@ static SvgNode* _createEllipseNode(SvgLoaderData* loader, SvgNode* parent, const
|
|||
static bool _attrParsePolygonPoints(const char* str, SvgPolygonNode* polygon)
|
||||
{
|
||||
float num;
|
||||
while (_parseNumber(&str, &num)) polygon->pts.push(num);
|
||||
while (_parseNumber(&str, nullptr, &num)) polygon->pts.push(num);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue