460 lines
12 KiB
Objective-C
460 lines
12 KiB
Objective-C
//
|
|
// SVGUtils.m
|
|
// SVGKit
|
|
//
|
|
// Copyright Matt Rajca 2010-2011. All rights reserved.
|
|
//
|
|
|
|
#import "SVGUtils.h"
|
|
#import "SVGKDefine_Private.h"
|
|
|
|
#define MAX_ACCUM 64
|
|
#define NUM_COLORS 148
|
|
|
|
|
|
SVGColor ColorValueWithName (const char *name);
|
|
|
|
static const char *gColorNames[NUM_COLORS] = {
|
|
"aliceblue",
|
|
"antiquewhite",
|
|
"aqua",
|
|
"aquamarine",
|
|
"azure",
|
|
"beige",
|
|
"bisque",
|
|
"black",
|
|
"blanchedalmond",
|
|
"blue",
|
|
"blueviolet",
|
|
"brown",
|
|
"burlywood",
|
|
"cadetblue",
|
|
"chartreuse",
|
|
"chocolate",
|
|
"coral",
|
|
"cornflowerblue",
|
|
"cornsilk",
|
|
"crimson",
|
|
"cyan",
|
|
"darkblue",
|
|
"darkcyan",
|
|
"darkgoldenrod",
|
|
"darkgray",
|
|
"darkgreen",
|
|
"darkgrey",
|
|
"darkkhaki",
|
|
"darkmagenta",
|
|
"darkolivegreen",
|
|
"darkorange",
|
|
"darkorchid",
|
|
"darkred",
|
|
"darksalmon",
|
|
"darkseagreen",
|
|
"darkslateblue",
|
|
"darkslategray",
|
|
"darkslategrey",
|
|
"darkturquoise",
|
|
"darkviolet",
|
|
"deeppink",
|
|
"deepskyblue",
|
|
"dimgray",
|
|
"dimgrey",
|
|
"dodgerblue",
|
|
"firebrick",
|
|
"floralwhite",
|
|
"forestgreen",
|
|
"fuchsia",
|
|
"gainsboro",
|
|
"ghostwhite",
|
|
"gold",
|
|
"goldenrod",
|
|
"gray",
|
|
"green",
|
|
"greenyellow",
|
|
"grey",
|
|
"honeydew",
|
|
"hotpink",
|
|
"indianred",
|
|
"indigo",
|
|
"ivory",
|
|
"khaki",
|
|
"lavender",
|
|
"lavenderblush",
|
|
"lawngreen",
|
|
"lemonchiffon",
|
|
"lightblue",
|
|
"lightcoral",
|
|
"lightcyan",
|
|
"lightgoldenrodyellow",
|
|
"lightgray",
|
|
"lightgreen",
|
|
"lightgrey",
|
|
"lightpink",
|
|
"lightsalmon",
|
|
"lightseagreen",
|
|
"lightskyblue",
|
|
"lightslategray",
|
|
"lightslategrey",
|
|
"lightsteelblue",
|
|
"lightyellow",
|
|
"lime",
|
|
"limegreen",
|
|
"linen",
|
|
"magenta",
|
|
"maroon",
|
|
"mediumaquamarine",
|
|
"mediumblue",
|
|
"mediumorchid",
|
|
"mediumpurple",
|
|
"mediumseagreen",
|
|
"mediumslateblue",
|
|
"mediumspringgreen",
|
|
"mediumturquoise",
|
|
"mediumvioletred",
|
|
"midnightblue",
|
|
"mintcream",
|
|
"mistyrose",
|
|
"moccasin",
|
|
"navajowhite",
|
|
"navy",
|
|
"oldlace",
|
|
"olive",
|
|
"olivedrab",
|
|
"orange",
|
|
"orangered",
|
|
"orchid",
|
|
"palegoldenrod",
|
|
"palegreen",
|
|
"paleturquoise",
|
|
"palevioletred",
|
|
"papayawhip",
|
|
"peachpuff",
|
|
"peru",
|
|
"pink",
|
|
"plum",
|
|
"powderblue",
|
|
"purple",
|
|
"red",
|
|
"rosybrown",
|
|
"royalblue",
|
|
"saddlebrown",
|
|
"salmon",
|
|
"sandybrown",
|
|
"seagreen",
|
|
"seashell",
|
|
"sienna",
|
|
"silver",
|
|
"skyblue",
|
|
"slateblue",
|
|
"slategray",
|
|
"slategrey",
|
|
"snow",
|
|
"springgreen",
|
|
"steelblue",
|
|
"tan",
|
|
"teal",
|
|
"thistle",
|
|
"tomato",
|
|
"turquoise",
|
|
"violet",
|
|
"wheat",
|
|
"white",
|
|
"whitesmoke",
|
|
"yellow",
|
|
"yellowgreen",
|
|
// CSS Color
|
|
"transparent"
|
|
};
|
|
|
|
static const SVGColor gColorValues[NUM_COLORS] = {
|
|
(SVGColor) { 240,248,255,255 }, (SVGColor) { 250,235,215,255 },
|
|
(SVGColor) { 0,255,255,255 }, (SVGColor) { 127,255,212,255 },
|
|
(SVGColor) { 240,255,255,255 }, (SVGColor) { 245,245,220,255 },
|
|
(SVGColor) { 255,228,196,255 }, (SVGColor) { 0,0,0,255 },
|
|
(SVGColor) { 255,235,205,255 }, (SVGColor) { 0,0,255,255 },
|
|
(SVGColor) { 138,43,226,255 }, (SVGColor) { 165,42,42,255 },
|
|
(SVGColor) { 222,184,135,255 }, (SVGColor) { 95,158,160,255 },
|
|
(SVGColor) { 127,255,0,255 }, (SVGColor) { 210,105,30,255 },
|
|
(SVGColor) { 255,127,80,255 }, (SVGColor) { 100,149,237,255 },
|
|
(SVGColor) { 255,248,220,255 }, (SVGColor) { 220,20,60,255 },
|
|
(SVGColor) { 0,255,255,255 }, (SVGColor) { 0,0,139,255 },
|
|
(SVGColor) { 0,139,139,255 }, (SVGColor) { 184,134,11,255 },
|
|
(SVGColor) { 169,169,169,255 }, (SVGColor) { 0,100,0,255 },
|
|
(SVGColor) { 169,169,169,255 }, (SVGColor) { 189,183,107,255 },
|
|
(SVGColor) { 139,0,139,255 }, (SVGColor) { 85,107,47,255 },
|
|
(SVGColor) { 255,140,0,255 }, (SVGColor) { 153,50,204,255 },
|
|
(SVGColor) { 139,0,0,255 }, (SVGColor) { 233,150,122,255 },
|
|
(SVGColor) { 143,188,143,255 }, (SVGColor) { 72,61,139,255 },
|
|
(SVGColor) { 47,79,79,255 }, (SVGColor) { 47,79,79,255 },
|
|
(SVGColor) { 0,206,209,255 }, (SVGColor) { 148,0,211,255 },
|
|
(SVGColor) { 255,20,147,255 }, (SVGColor) { 0,191,255,255 },
|
|
(SVGColor) { 105,105,105,255 }, (SVGColor) { 105,105,105,255 },
|
|
(SVGColor) { 30,144,255,255 }, (SVGColor) { 178,34,34,255 },
|
|
(SVGColor) { 255,250,240,255 }, (SVGColor) { 34,139,34,255 },
|
|
(SVGColor) { 255,0,255,255 }, (SVGColor) { 220,220,220,255 },
|
|
(SVGColor) { 248,248,255,255 }, (SVGColor) { 255,215,0,255 },
|
|
(SVGColor) { 218,165,32,255 }, (SVGColor) { 128,128,128,255 },
|
|
(SVGColor) { 0,128,0,255 }, (SVGColor) { 173,255,47,255 },
|
|
(SVGColor) { 128,128,128,255 }, (SVGColor) { 240,255,240,255 },
|
|
(SVGColor) { 255,105,180,255 }, (SVGColor) { 205,92,92,255 },
|
|
(SVGColor) { 75,0,130,255 }, (SVGColor) { 255,255,240,255 },
|
|
(SVGColor) { 240,230,140,255 }, (SVGColor) { 230,230,250,255 },
|
|
(SVGColor) { 255,240,245,255 }, (SVGColor) { 124,252,0,255 },
|
|
(SVGColor) { 255,250,205,255 }, (SVGColor) { 173,216,230,255 },
|
|
(SVGColor) { 240,128,128,255 }, (SVGColor) { 224,255,255,255 },
|
|
(SVGColor) { 250,250,210,255 }, (SVGColor) { 211,211,211,255 },
|
|
(SVGColor) { 144,238,144,255 }, (SVGColor) { 211,211,211,255 },
|
|
(SVGColor) { 255,182,193,255 }, (SVGColor) { 255,160,122,255 },
|
|
(SVGColor) { 32,178,170,255 }, (SVGColor) { 135,206,250,255 },
|
|
(SVGColor) { 119,136,153,255 }, (SVGColor) { 119,136,153,255 },
|
|
(SVGColor) { 176,196,222,255 }, (SVGColor) { 255,255,224,255 },
|
|
(SVGColor) { 0,255,0,255 }, (SVGColor) { 50,205,50,255 },
|
|
(SVGColor) { 250,240,230,255 }, (SVGColor) { 255,0,255,255 },
|
|
(SVGColor) { 128,0,0,255 }, (SVGColor) { 102,205,170,255 },
|
|
(SVGColor) { 0,0,205,255 }, (SVGColor) { 186,85,211,255 },
|
|
(SVGColor) { 147,112,219,255 }, (SVGColor) { 60,179,113,255 },
|
|
(SVGColor) { 123,104,238,255 }, (SVGColor) { 0,250,154,255 },
|
|
(SVGColor) { 72,209,204,255 }, (SVGColor) { 199,21,133,255 },
|
|
(SVGColor) { 25,25,112,255 }, (SVGColor) { 245,255,250,255 },
|
|
(SVGColor) { 255,228,225,255 }, (SVGColor) { 255,228,181,255 },
|
|
(SVGColor) { 255,222,173,255 }, (SVGColor) { 0,0,128,255 },
|
|
(SVGColor) { 253,245,230,255 }, (SVGColor) { 128,128,0,255 },
|
|
(SVGColor) { 107,142,35,255 }, (SVGColor) { 255,165,0,255 },
|
|
(SVGColor) { 255,69,0,255 }, (SVGColor) { 218,112,214,255 },
|
|
(SVGColor) { 238,232,170,255 }, (SVGColor) { 152,251,152,255 },
|
|
(SVGColor) { 175,238,238,255 }, (SVGColor) { 219,112,147,255 },
|
|
(SVGColor) { 255,239,213,255 }, (SVGColor) { 255,218,185,255 },
|
|
(SVGColor) { 205,133,63,255 }, (SVGColor) { 255,192,203,255 },
|
|
(SVGColor) { 221,160,221,255 }, (SVGColor) { 176,224,230,255 },
|
|
(SVGColor) { 128,0,128,255 }, (SVGColor) { 255,0,0,255 },
|
|
(SVGColor) { 188,143,143,255 }, (SVGColor) { 65,105,225,255 },
|
|
(SVGColor) { 139,69,19,255 }, (SVGColor) { 250,128,114,255 },
|
|
(SVGColor) { 244,164,96,255 }, (SVGColor) { 46,139,87,255 },
|
|
(SVGColor) { 255,245,238,255 }, (SVGColor) { 160,82,45,255 },
|
|
(SVGColor) { 192,192,192,255 }, (SVGColor) { 135,206,235,255 },
|
|
(SVGColor) { 106,90,205,255 }, (SVGColor) { 112,128,144,255 },
|
|
(SVGColor) { 112,128,144,255 }, (SVGColor) { 255,250,250,255 },
|
|
(SVGColor) { 0,255,127,255 }, (SVGColor) { 70,130,180,255 },
|
|
(SVGColor) { 210,180,140,255 }, (SVGColor) { 0,128,128,255 },
|
|
(SVGColor) { 216,191,216,255 }, (SVGColor) { 255,99,71,255 },
|
|
(SVGColor) { 64,224,208,255 }, (SVGColor) { 238,130,238,255 },
|
|
(SVGColor) { 245,222,179,255 }, (SVGColor) { 255,255,255,255 },
|
|
(SVGColor) { 245,245,245,255 }, (SVGColor) { 255,255,0,255 },
|
|
(SVGColor) { 154,205,50,255 },
|
|
// CSS Color
|
|
(SVGColor) { 0, 0, 0, 0}
|
|
};
|
|
|
|
SVGColor ColorValueWithName (const char *name) {
|
|
int idx = -1;
|
|
|
|
for (int n = 0; n < NUM_COLORS; n++) {
|
|
if (!strcmp(gColorNames[n], name)) {
|
|
idx = n;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (idx == -1) {
|
|
return SVGColorMake(0, 0, 0, 255); // black
|
|
}
|
|
|
|
return gColorValues[idx];
|
|
}
|
|
|
|
SVGColor SVGColorMake (uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
|
SVGColor color = { .r = r, .g = g, .b = b, .a = a };
|
|
return color;
|
|
}
|
|
|
|
typedef enum {
|
|
PhaseNone = 0,
|
|
PhaseRGB,
|
|
PhaseRGBA
|
|
} Phase;
|
|
|
|
SVGColor SVGColorFromString (const char *string) {
|
|
NSCAssert(string != NULL, @"NullPointerException: you gave us a null pointer, very bad thing to do...");
|
|
SVGColor color;
|
|
bzero(&color, sizeof(color));
|
|
|
|
color.a = 0xFF;
|
|
|
|
if (!strncmp(string, "rgb(", 4) || !strncmp(string, "rgba(", 5)) {
|
|
size_t len = strlen(string);
|
|
|
|
char accum[MAX_ACCUM];
|
|
bzero(accum, MAX_ACCUM);
|
|
|
|
int accumIdx = 0, currComponent = 0;
|
|
Phase phase = PhaseNone;
|
|
|
|
for (size_t n = 0; n < len; n++) {
|
|
char c = string[n];
|
|
|
|
if (c == '\n' || c == '\t' || c == ' ') {
|
|
continue;
|
|
}
|
|
|
|
if (!strcmp(accum, "rgba(")) {
|
|
phase = PhaseRGBA;
|
|
bzero(accum, MAX_ACCUM);
|
|
accumIdx = 0;
|
|
} else if (!strcmp(accum, "rgb(")) {
|
|
phase = PhaseRGB;
|
|
bzero(accum, MAX_ACCUM);
|
|
accumIdx = 0;
|
|
}
|
|
|
|
if (phase == PhaseRGB || phase == PhaseRGBA) {
|
|
if (c == ',') {
|
|
if (currComponent == 0) {
|
|
color.r = atoi(accum);
|
|
currComponent++;
|
|
}
|
|
else if (currComponent == 1) {
|
|
color.g = atoi(accum);
|
|
currComponent++;
|
|
}
|
|
else if (phase == PhaseRGBA && currComponent == 2) {
|
|
color.b = atoi(accum);
|
|
currComponent++;
|
|
}
|
|
bzero(accum, MAX_ACCUM);
|
|
accumIdx = 0;
|
|
|
|
continue;
|
|
}
|
|
else if (c == ')' && currComponent == 2) {
|
|
color.b = atoi(accum);
|
|
break;
|
|
}
|
|
else if (c == ')' && currComponent == 3) {
|
|
color.a = (uint8_t)lround(atof(accum) * 255.0f);
|
|
break;
|
|
}
|
|
}
|
|
|
|
accum[accumIdx++] = c;
|
|
}
|
|
}
|
|
else if (!strncmp(string, "#", 1)) {
|
|
const char *hexString = string + 1;
|
|
|
|
if (strlen(hexString) == 6)
|
|
{
|
|
char r[3], g[3], b[3];
|
|
r[2] = g[2] = b[2] = '\0';
|
|
|
|
strncpy(r, hexString, 2);
|
|
strncpy(g, hexString + 2, 2);
|
|
strncpy(b, hexString + 4, 2);
|
|
|
|
color.r = strtol(r, NULL, 16);
|
|
color.g = strtol(g, NULL, 16);
|
|
color.b = strtol(b, NULL, 16);
|
|
}
|
|
else if( strlen(hexString) == 3 )
|
|
{
|
|
char r[2], g[2], b[2];
|
|
r[1] = g[1] = b[1] = '\0';
|
|
|
|
strncpy(r, hexString, 1);
|
|
strncpy(g, hexString + 1, 1);
|
|
strncpy(b, hexString + 2, 1);
|
|
|
|
color.r = strtol(r, NULL, 16);
|
|
color.g = strtol(g, NULL, 16);
|
|
color.b = strtol(b, NULL, 16);
|
|
|
|
/** because 3-digit hex notation "F" means "FF" ... "1" means "11" ... etc */
|
|
color.r += color.r * 16;
|
|
color.g += color.g * 16;
|
|
color.b += color.b * 16;
|
|
}
|
|
else
|
|
{
|
|
color = SVGColorMake(0, 0, 0, 255);
|
|
}
|
|
|
|
}
|
|
else {
|
|
color = ColorValueWithName(string);
|
|
}
|
|
|
|
return color;
|
|
}
|
|
|
|
CGFloat SVGPercentageFromString (const char *string) {
|
|
size_t len = strlen(string);
|
|
|
|
if (string[len-1] != '%') {
|
|
SVGKitLogWarn(@"Invalid percentage: %s", string);
|
|
return -1;
|
|
}
|
|
|
|
return atoi(string) / 100.0f;
|
|
}
|
|
|
|
CGMutablePathRef createPathFromPointsInString (const char *string, boolean_t close) {
|
|
CGMutablePathRef path = CGPathCreateMutable();
|
|
|
|
size_t len = strlen(string);
|
|
|
|
char accum[MAX_ACCUM];
|
|
bzero(accum, MAX_ACCUM);
|
|
|
|
int accumIdx = 0, currComponent = 0;
|
|
|
|
for (size_t n = 0; n <= len; n++) {
|
|
char c = string[n];
|
|
|
|
if (c == '\n' || c == '\t' || c == ' ' || c == ',' || c == '\0') {
|
|
accum[accumIdx] = '\0';
|
|
|
|
static float x, y;
|
|
|
|
if (currComponent == 0 && accumIdx != 0) {
|
|
sscanf( accum, "%g", &x );
|
|
currComponent++;
|
|
}
|
|
else if (currComponent == 1) {
|
|
|
|
sscanf( accum, "%g", &y );
|
|
|
|
if (CGPathIsEmpty(path)) {
|
|
CGPathMoveToPoint(path, NULL, x, y);
|
|
}
|
|
else {
|
|
CGPathAddLineToPoint(path, NULL, x, y);
|
|
}
|
|
|
|
currComponent = 0;
|
|
}
|
|
|
|
bzero(accum, MAX_ACCUM);
|
|
accumIdx = 0;
|
|
}
|
|
else if (isdigit(c) || c == '-' || c == '.') { // is digit or decimal separator OR A MINUS SIGN!!! ?
|
|
accum[accumIdx++] = c;
|
|
}
|
|
}
|
|
|
|
if (close) {
|
|
CGPathCloseSubpath(path);
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
CGColorRef CGColorWithSVGColor (SVGColor color) {
|
|
CGColorRef outColor = NULL;
|
|
|
|
outColor = [UIColor colorWithRed:RGB_N(color.r)
|
|
green:RGB_N(color.g)
|
|
blue:RGB_N(color.b)
|
|
alpha:RGB_N(color.a)].CGColor;
|
|
|
|
return outColor;
|
|
}
|