From 7b8e401c83760b6a8c2a2b802b0829dd1fb5a3cf Mon Sep 17 00:00:00 2001 From: Yury Popov Date: Wed, 13 May 2015 17:46:43 +0300 Subject: [PATCH] fill-opacity & gradients support --- pxSVG/pxSVGObject.h | 2 + pxSVG/pxSVGObject.m | 9 +- pxSVG/pxSVGRenderPath.m | 180 +++++++++++++++++++++++++++++++--------- 3 files changed, 152 insertions(+), 39 deletions(-) diff --git a/pxSVG/pxSVGObject.h b/pxSVG/pxSVGObject.h index 8301eb0..3ce4217 100644 --- a/pxSVG/pxSVGObject.h +++ b/pxSVG/pxSVGObject.h @@ -16,8 +16,10 @@ @property NSString *id; @property NSArray *animations; @property UIColor *fillColor; +@property NSString *fillDef; @property UIColor *strokeColor; @property CGFloat strokeWidth; @property CGFloat opacity; +@property CGFloat fillOpacity; @property CATransform3D transform; @end diff --git a/pxSVG/pxSVGObject.m b/pxSVG/pxSVGObject.m index 1dd55b6..653f71b 100644 --- a/pxSVG/pxSVGObject.m +++ b/pxSVG/pxSVGObject.m @@ -103,11 +103,18 @@ - (void)loadAttributes:(NSDictionary *)attributes } } self.id = [ma objectForKey:@"id"]; - self.fillColor = [self.class colorWithSVGColor:[ma objectForKey:@"fill"]]; + if ([[ma objectForKey:@"fill"] hasPrefix:@"url("]) { + NSString *u = [[ma objectForKey:@"fill"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + u = [[u substringWithRange:NSMakeRange(3, u.length-4)] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\n\r\t ()#"]]; + self.fillDef = u; + } else self.fillColor = [self.class colorWithSVGColor:[ma objectForKey:@"fill"]]; self.strokeColor = [self.class colorWithSVGColor:[ma objectForKey:@"stroke"]]; self.strokeWidth = [ma objectForKey:@"stroke-width"]?[[ma objectForKey:@"stroke-width"] doubleValue]:NAN; self.transform = [self.class transformFromString:[ma objectForKey:@"transform"]]; self.opacity = [ma objectForKey:@"opacity"]?[[ma objectForKey:@"opacity"] doubleValue]:1; + CGFloat a = NAN; + if (self.fillColor) [self.fillColor getWhite:nil alpha:&a]; + self.fillOpacity = [ma objectForKey:@"fill-opacity"]?[[ma objectForKey:@"fill-opacity"] doubleValue]:a; } - (void)setSubnodes:(NSArray *)subnodes { } @end diff --git a/pxSVG/pxSVGRenderPath.m b/pxSVG/pxSVGRenderPath.m index b34da00..31bb029 100644 --- a/pxSVG/pxSVGRenderPath.m +++ b/pxSVG/pxSVGRenderPath.m @@ -10,6 +10,16 @@ #import "pxSVGGroup.h" #import "pxSVGPath.h" +@interface pxSVGGradient : NSObject +@property CGGradientRef gradient; +@property NSArray *colors; +@property NSArray *locations; +@property CGPoint startPoint, endPoint; +@end + +@implementation pxSVGGradient +@end + @interface pxSVGRenderPath () @property NSMutableDictionary *defs; @property pxSVGObject *root; @@ -73,6 +83,106 @@ - (CGRect) objBounds:(pxSVGObject*)obj } return CGRectNull; } +- (pxSVGObject*)reuseObjectWithAttributes:(NSDictionary*)attributes +{ + NSString *href = [attributes objectForKey:@"xlink:href"]; + if (!href) href = [attributes objectForKey:@"href"]; + if (!href) return nil; + href = [href substringFromIndex:1]; + pxSVGObject *oobj = [self.defs objectForKey:href], *obj; + if (!oobj) return nil; + obj = [oobj.class new]; + obj.fillColor = oobj.fillColor; + obj.fillDef = oobj.fillDef; + obj.strokeColor = oobj.strokeColor; + obj.strokeWidth = oobj.strokeWidth; + obj.opacity = oobj.opacity; + obj.fillOpacity = oobj.fillOpacity; + if ([oobj respondsToSelector:@selector(d)]) + [(id)obj setD:[(id)oobj d]]; + if ([oobj respondsToSelector:@selector(subnodes)]) + [(id)obj setSubnodes:[(id)oobj subnodes]]; + CATransform3D tr = oobj.transform; + if ([attributes objectForKey:@"x"]) tr = CATransform3DTranslate(tr, [[attributes objectForKey:@"x"] doubleValue], 0, 0); + if ([attributes objectForKey:@"y"]) tr = CATransform3DTranslate(tr, 0, [[attributes objectForKey:@"y"] doubleValue], 0); + if ([attributes objectForKey:@"width"]) { + CGFloat ow = [self objBounds:oobj].size.width, w = [[attributes objectForKey:@"width"] doubleValue]; + tr = CATransform3DScale(tr, ow/w, 1, 1); + } + if ([attributes objectForKey:@"height"]) { + CGFloat oh = [self objBounds:oobj].size.width, h = [[attributes objectForKey:@"height"] doubleValue]; + tr = CATransform3DScale(tr, 1, oh/h, 1); + } + if ([attributes objectForKey:@"transform"]) tr = CATransform3DConcat(tr, [pxSVGObject transformFromString:[attributes objectForKey:@"transform"]]); + obj.transform = tr; + obj.animations = oobj.animations; + return obj; +} +- (void)parseLinearGradient:(pxXMLNode*)node +{ + NSString *gid = [node.attributes objectForKey:@"id"]; + if (!gid) return; + NSString *href = [node.attributes objectForKey:@"xlink:href"]; + if (!href) href = [node.attributes objectForKey:@"href"]; + CGGradientRef gr; + CGPoint sp = CGPointZero, ep = (CGPoint){INFINITY,INFINITY}; + NSMutableArray *cls, *locs; + if (href) { + href = [href substringFromIndex:1]; + pxSVGGradient *g = [self.defs objectForKey:href]; + if (![g isKindOfClass:[pxSVGGradient class]]) return; + gr = g.gradient; + sp = g.startPoint; + ep = g.endPoint; + cls = (id)g.colors; + locs = (id)g.locations; + } else { + cls = [NSMutableArray new], locs = [NSMutableArray new]; + CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); + for (pxXMLNode *s in node.childNodes) { + if (![s.tagName isEqualToString:@"stop"]) { + NSLog(@"Unknown gradient node: %@",s); + } + NSMutableDictionary *ma = [s.attributes mutableCopy]; + if ([s.attributes objectForKey:@"style"]) { + for (NSString *ss in [[s.attributes objectForKey:@"style"] componentsSeparatedByString:@";"]) { + NSUInteger sep = [ss rangeOfString:@":"].location; + if (sep == NSNotFound) continue; + NSString *k = [[ss substringToIndex:sep] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + NSString *v = [[ss substringFromIndex:sep+1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + [ma setObject:v forKey:k]; + } + } + if ([ma objectForKey:@"stop-color"] && [ma objectForKey:@"offset"]) { + UIColor *cl = [pxSVGObject colorWithSVGColor:[ma objectForKey:@"stop-color"]]; + if ([ma objectForKey:@"stop-opacity"]) + cl = [cl colorWithAlphaComponent:[[ma objectForKey:@"stop-opacity"] doubleValue]]; + [cls addObject:(__bridge id)cl.CGColor]; + [locs addObject:@([[ma objectForKey:@"offset"] doubleValue])]; + } + } + CGFloat *locs_a = CFAllocatorAllocate(CFAllocatorGetDefault(), (sizeof(CGFloat)*locs.count), 0); + for (NSUInteger i=0; i