SVGAVectorLayer.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. //
  2. // SVGAVectorLayer.m
  3. // SVGAPlayer
  4. //
  5. // Created by 崔明辉 on 2017/2/20.
  6. // Copyright © 2017年 UED Center. All rights reserved.
  7. //
  8. #import "SVGAVectorLayer.h"
  9. #import "SVGABezierPath.h"
  10. #import "SVGAVideoSpriteFrameEntity.h"
  11. #import "Svga.pbobjc.h"
  12. @interface SVGAVectorLayer ()
  13. @property (nonatomic, strong) NSArray<SVGAVideoSpriteFrameEntity *> *frames;
  14. @property (nonatomic, assign) NSInteger drawedFrame;
  15. @property (nonatomic, strong) NSDictionary *keepFrameCache;
  16. @end
  17. @implementation SVGAVectorLayer
  18. - (instancetype)initWithFrames:(NSArray *)frames {
  19. self = [super init];
  20. if (self) {
  21. self.backgroundColor = [UIColor clearColor].CGColor;
  22. self.masksToBounds = NO;
  23. _frames = frames;
  24. _keepFrameCache = [NSMutableDictionary dictionary];
  25. [self resetKeepFrameCache];
  26. [self stepToFrame:0];
  27. }
  28. return self;
  29. }
  30. - (void)resetKeepFrameCache {
  31. __block NSInteger lastKeep = 0;
  32. __block NSMutableDictionary *keepFrameCache = [NSMutableDictionary dictionary];
  33. [self.frames enumerateObjectsUsingBlock:^(SVGAVideoSpriteFrameEntity * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  34. if (![self isKeepFrame:obj]) {
  35. lastKeep = idx;
  36. }
  37. else {
  38. [keepFrameCache setObject:@(lastKeep) forKey:@(idx)];
  39. }
  40. }];
  41. self.keepFrameCache = [keepFrameCache copy];
  42. }
  43. - (void)stepToFrame:(NSInteger)frame {
  44. if (frame < self.frames.count) {
  45. [self drawFrame:frame];
  46. }
  47. }
  48. - (BOOL)isKeepFrame:(SVGAVideoSpriteFrameEntity *)frameItem {
  49. if (frameItem.shapes.count == 0) {
  50. return NO;
  51. }
  52. else if ([frameItem.shapes.firstObject isKindOfClass:[NSDictionary class]]) {
  53. return [frameItem.shapes.firstObject[@"type"] isKindOfClass:[NSString class]] &&
  54. [frameItem.shapes.firstObject[@"type"] isEqualToString:@"keep"];
  55. }
  56. else if ([frameItem.shapes.firstObject isKindOfClass:[SVGAProtoShapeEntity class]]) {
  57. return [(SVGAProtoShapeEntity *)frameItem.shapes.firstObject type] == SVGAProtoShapeEntity_ShapeType_Keep;
  58. }
  59. else {
  60. return NO;
  61. }
  62. }
  63. - (NSInteger)requestKeepFrame:(NSInteger)frame {
  64. if ([self.keepFrameCache objectForKey:@(frame)] != nil) {
  65. return [[self.keepFrameCache objectForKey:@(frame)] integerValue];
  66. }
  67. return NSNotFound;
  68. }
  69. - (void)drawFrame:(NSInteger)frame {
  70. if (frame < self.frames.count) {
  71. SVGAVideoSpriteFrameEntity *frameItem = self.frames[frame];
  72. if ([self isKeepFrame:frameItem]) {
  73. if (self.drawedFrame == [self requestKeepFrame:frame]) {
  74. return;
  75. }
  76. }
  77. while(self.sublayers.count) [self.sublayers.firstObject removeFromSuperlayer];
  78. for (NSDictionary *shape in frameItem.shapes) {
  79. if ([shape isKindOfClass:[NSDictionary class]]) {
  80. if ([shape[@"type"] isKindOfClass:[NSString class]]) {
  81. if ([shape[@"type"] isEqualToString:@"shape"]) {
  82. [self addSublayer:[self createCurveLayer:shape]];
  83. }
  84. else if ([shape[@"type"] isEqualToString:@"ellipse"]) {
  85. [self addSublayer:[self createEllipseLayer:shape]];
  86. }
  87. else if ([shape[@"type"] isEqualToString:@"rect"]) {
  88. [self addSublayer:[self createRectLayer:shape]];
  89. }
  90. }
  91. }
  92. else if ([shape isKindOfClass:[SVGAProtoShapeEntity class]]) {
  93. SVGAProtoShapeEntity *shapeItem = (id)shape;
  94. if (shapeItem.type == SVGAProtoShapeEntity_ShapeType_Shape) {
  95. [self addSublayer:[self createCurveLayerWithProto:shapeItem]];
  96. }
  97. else if (shapeItem.type == SVGAProtoShapeEntity_ShapeType_Ellipse) {
  98. [self addSublayer:[self createEllipseLayerWithProto:shapeItem]];
  99. }
  100. else if (shapeItem.type == SVGAProtoShapeEntity_ShapeType_Rect) {
  101. [self addSublayer:[self createRectLayerWithProto:shapeItem]];
  102. }
  103. }
  104. }
  105. self.drawedFrame = frame;
  106. }
  107. }
  108. - (CALayer *)createCurveLayer:(NSDictionary *)shape {
  109. SVGABezierPath *bezierPath = [SVGABezierPath new];
  110. if ([shape[@"args"] isKindOfClass:[NSDictionary class]]) {
  111. if ([shape[@"args"][@"d"] isKindOfClass:[NSString class]]) {
  112. [bezierPath setValues:shape[@"args"][@"d"]];
  113. }
  114. }
  115. CAShapeLayer *shapeLayer = [bezierPath createLayer];
  116. [self resetStyles:shapeLayer shape:shape];
  117. [self resetTransform:shapeLayer shape:shape];
  118. return shapeLayer;
  119. }
  120. - (CALayer *)createCurveLayerWithProto:(SVGAProtoShapeEntity *)shape {
  121. SVGABezierPath *bezierPath = [SVGABezierPath new];
  122. if (shape.argsOneOfCase == SVGAProtoShapeEntity_Args_OneOfCase_Shape) {
  123. if ([shape.shape.d isKindOfClass:[NSString class]] && shape.shape.d.length > 0) {
  124. [bezierPath setValues:shape.shape.d];
  125. }
  126. }
  127. CAShapeLayer *shapeLayer = [bezierPath createLayer];
  128. [self resetStyles:shapeLayer protoShape:shape];
  129. [self resetTransform:shapeLayer protoShape:shape];
  130. return shapeLayer;
  131. }
  132. - (CALayer *)createEllipseLayer:(NSDictionary *)shape {
  133. UIBezierPath *bezierPath;
  134. if ([shape[@"args"] isKindOfClass:[NSDictionary class]]) {
  135. if ([shape[@"args"][@"x"] isKindOfClass:[NSNumber class]] &&
  136. [shape[@"args"][@"y"] isKindOfClass:[NSNumber class]] &&
  137. [shape[@"args"][@"radiusX"] isKindOfClass:[NSNumber class]] &&
  138. [shape[@"args"][@"radiusY"] isKindOfClass:[NSNumber class]]) {
  139. CGFloat x = [shape[@"args"][@"x"] floatValue];
  140. CGFloat y = [shape[@"args"][@"y"] floatValue];
  141. CGFloat rx = [shape[@"args"][@"radiusX"] floatValue];
  142. CGFloat ry = [shape[@"args"][@"radiusY"] floatValue];
  143. bezierPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(x - rx, y - ry, rx * 2, ry * 2)];
  144. }
  145. }
  146. if (bezierPath != nil) {
  147. CAShapeLayer *shapeLayer = [CAShapeLayer layer];
  148. [shapeLayer setPath:[bezierPath CGPath]];
  149. [self resetStyles:shapeLayer shape:shape];
  150. [self resetTransform:shapeLayer shape:shape];
  151. return shapeLayer;
  152. }
  153. else {
  154. return [CALayer layer];
  155. }
  156. }
  157. - (CALayer *)createEllipseLayerWithProto:(SVGAProtoShapeEntity *)shape {
  158. UIBezierPath *bezierPath;
  159. if (shape.argsOneOfCase == SVGAProtoShapeEntity_Args_OneOfCase_Ellipse) {
  160. bezierPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(shape.ellipse.x - shape.ellipse.radiusX,
  161. shape.ellipse.y - shape.ellipse.radiusY,
  162. shape.ellipse.radiusX * 2,
  163. shape.ellipse.radiusY * 2)];
  164. }
  165. if (bezierPath != nil) {
  166. CAShapeLayer *shapeLayer = [CAShapeLayer layer];
  167. [shapeLayer setPath:[bezierPath CGPath]];
  168. [self resetStyles:shapeLayer protoShape:shape];
  169. [self resetTransform:shapeLayer protoShape:shape];
  170. return shapeLayer;
  171. }
  172. else {
  173. return [CALayer layer];
  174. }
  175. }
  176. - (CALayer *)createRectLayer:(NSDictionary *)shape {
  177. UIBezierPath *bezierPath;
  178. if ([shape[@"args"] isKindOfClass:[NSDictionary class]]) {
  179. if ([shape[@"args"][@"x"] isKindOfClass:[NSNumber class]] &&
  180. [shape[@"args"][@"y"] isKindOfClass:[NSNumber class]] &&
  181. [shape[@"args"][@"width"] isKindOfClass:[NSNumber class]] &&
  182. [shape[@"args"][@"height"] isKindOfClass:[NSNumber class]] &&
  183. [shape[@"args"][@"cornerRadius"] isKindOfClass:[NSNumber class]]) {
  184. CGFloat x = [shape[@"args"][@"x"] floatValue];
  185. CGFloat y = [shape[@"args"][@"y"] floatValue];
  186. CGFloat width = [shape[@"args"][@"width"] floatValue];
  187. CGFloat height = [shape[@"args"][@"height"] floatValue];
  188. CGFloat cornerRadius = [shape[@"args"][@"cornerRadius"] floatValue];
  189. bezierPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(x, y, width, height) cornerRadius:cornerRadius];
  190. }
  191. }
  192. if (bezierPath != nil) {
  193. CAShapeLayer *shapeLayer = [CAShapeLayer layer];
  194. [shapeLayer setPath:[bezierPath CGPath]];
  195. [self resetStyles:shapeLayer shape:shape];
  196. [self resetTransform:shapeLayer shape:shape];
  197. return shapeLayer;
  198. }
  199. else {
  200. return [CALayer layer];
  201. }
  202. }
  203. - (CALayer *)createRectLayerWithProto:(SVGAProtoShapeEntity *)shape {
  204. UIBezierPath *bezierPath;
  205. if (shape.argsOneOfCase == SVGAProtoShapeEntity_Args_OneOfCase_Rect) {
  206. bezierPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(shape.rect.x, shape.rect.y, shape.rect.width, shape.rect.height)
  207. cornerRadius:shape.rect.cornerRadius];
  208. }
  209. if (bezierPath != nil) {
  210. CAShapeLayer *shapeLayer = [CAShapeLayer layer];
  211. [shapeLayer setPath:[bezierPath CGPath]];
  212. [self resetStyles:shapeLayer protoShape:shape];
  213. [self resetTransform:shapeLayer protoShape:shape];
  214. return shapeLayer;
  215. }
  216. else {
  217. return [CALayer layer];
  218. }
  219. }
  220. - (void)resetStyles:(CAShapeLayer *)shapeLayer shape:(NSDictionary *)shape {
  221. shapeLayer.masksToBounds = NO;
  222. shapeLayer.backgroundColor = [UIColor clearColor].CGColor;
  223. if ([shape[@"styles"] isKindOfClass:[NSDictionary class]]) {
  224. if ([shape[@"styles"][@"fill"] isKindOfClass:[NSArray class]]) {
  225. NSArray *colorArray = shape[@"styles"][@"fill"];
  226. if ([colorArray count] == 4 &&
  227. [colorArray[0] isKindOfClass:[NSNumber class]] &&
  228. [colorArray[1] isKindOfClass:[NSNumber class]] &&
  229. [colorArray[2] isKindOfClass:[NSNumber class]] &&
  230. [colorArray[3] isKindOfClass:[NSNumber class]]) {
  231. shapeLayer.fillColor = [UIColor colorWithRed:[colorArray[0] floatValue]
  232. green:[colorArray[1] floatValue]
  233. blue:[colorArray[2] floatValue]
  234. alpha:[colorArray[3] floatValue]].CGColor;
  235. }
  236. }
  237. else {
  238. shapeLayer.fillColor = [UIColor clearColor].CGColor;
  239. }
  240. if ([shape[@"styles"][@"stroke"] isKindOfClass:[NSArray class]]) {
  241. NSArray *colorArray = shape[@"styles"][@"stroke"];
  242. if ([colorArray count] == 4 &&
  243. [colorArray[0] isKindOfClass:[NSNumber class]] &&
  244. [colorArray[1] isKindOfClass:[NSNumber class]] &&
  245. [colorArray[2] isKindOfClass:[NSNumber class]] &&
  246. [colorArray[3] isKindOfClass:[NSNumber class]]) {
  247. shapeLayer.strokeColor = [UIColor colorWithRed:[colorArray[0] floatValue]
  248. green:[colorArray[1] floatValue]
  249. blue:[colorArray[2] floatValue]
  250. alpha:[colorArray[3] floatValue]].CGColor;
  251. }
  252. }
  253. if ([shape[@"styles"][@"strokeWidth"] isKindOfClass:[NSNumber class]]) {
  254. shapeLayer.lineWidth = [shape[@"styles"][@"strokeWidth"] floatValue];
  255. }
  256. if ([shape[@"styles"][@"lineCap"] isKindOfClass:[NSString class]]) {
  257. shapeLayer.lineCap = shape[@"styles"][@"lineCap"];
  258. }
  259. if ([shape[@"styles"][@"lineJoin"] isKindOfClass:[NSString class]]) {
  260. shapeLayer.lineJoin = shape[@"styles"][@"lineJoin"];
  261. }
  262. if ([shape[@"styles"][@"lineDash"] isKindOfClass:[NSArray class]]) {
  263. BOOL accept = YES;
  264. for (id obj in shape[@"styles"][@"lineDash"]) {
  265. if (![obj isKindOfClass:[NSNumber class]]) {
  266. accept = NO;
  267. }
  268. }
  269. if (accept) {
  270. if ([shape[@"styles"][@"lineDash"] count] == 3) {
  271. shapeLayer.lineDashPhase = [shape[@"styles"][@"lineDash"][2] floatValue];
  272. shapeLayer.lineDashPattern = @[
  273. ([shape[@"styles"][@"lineDash"][0] floatValue] < 1.0 ? @(1.0) : shape[@"styles"][@"lineDash"][0]),
  274. ([shape[@"styles"][@"lineDash"][1] floatValue] < 0.1 ? @(0.1) : shape[@"styles"][@"lineDash"][1])
  275. ];
  276. }
  277. }
  278. }
  279. if ([shape[@"styles"][@"miterLimit"] isKindOfClass:[NSNumber class]]) {
  280. shapeLayer.miterLimit = [shape[@"styles"][@"miterLimit"] floatValue];
  281. }
  282. }
  283. }
  284. - (void)resetStyles:(CAShapeLayer *)shapeLayer protoShape:(SVGAProtoShapeEntity *)protoShape {
  285. shapeLayer.masksToBounds = NO;
  286. shapeLayer.backgroundColor = [UIColor clearColor].CGColor;
  287. if (protoShape.hasStyles) {
  288. if (protoShape.styles.hasFill) {
  289. shapeLayer.fillColor = [UIColor colorWithRed:protoShape.styles.fill.r
  290. green:protoShape.styles.fill.g
  291. blue:protoShape.styles.fill.b
  292. alpha:protoShape.styles.fill.a].CGColor;
  293. }
  294. else {
  295. shapeLayer.fillColor = [UIColor clearColor].CGColor;
  296. }
  297. if (protoShape.styles.hasStroke) {
  298. shapeLayer.strokeColor = [UIColor colorWithRed:protoShape.styles.stroke.r
  299. green:protoShape.styles.stroke.g
  300. blue:protoShape.styles.stroke.b
  301. alpha:protoShape.styles.stroke.a].CGColor;
  302. }
  303. shapeLayer.lineWidth = protoShape.styles.strokeWidth;
  304. switch (protoShape.styles.lineCap) {
  305. case SVGAProtoShapeEntity_ShapeStyle_LineCap_LineCapButt:
  306. shapeLayer.lineCap = @"butt";
  307. break;
  308. case SVGAProtoShapeEntity_ShapeStyle_LineCap_LineCapRound:
  309. shapeLayer.lineCap = @"round";
  310. break;
  311. case SVGAProtoShapeEntity_ShapeStyle_LineCap_LineCapSquare:
  312. shapeLayer.lineCap = @"square";
  313. break;
  314. default:
  315. break;
  316. }
  317. switch (protoShape.styles.lineJoin) {
  318. case SVGAProtoShapeEntity_ShapeStyle_LineJoin_LineJoinRound:
  319. shapeLayer.lineJoin = @"round";
  320. break;
  321. case SVGAProtoShapeEntity_ShapeStyle_LineJoin_LineJoinMiter:
  322. shapeLayer.lineJoin = @"miter";
  323. break;
  324. case SVGAProtoShapeEntity_ShapeStyle_LineJoin_LineJoinBevel:
  325. shapeLayer.lineJoin = @"bevel";
  326. break;
  327. default:
  328. break;
  329. }
  330. shapeLayer.lineDashPhase = protoShape.styles.lineDashIii;
  331. if (protoShape.styles.lineDashI > 0.0 || protoShape.styles.lineDashIi > 0.0) {
  332. shapeLayer.lineDashPattern = @[
  333. (protoShape.styles.lineDashI < 1.0 ? @(1.0) : @(protoShape.styles.lineDashI)),
  334. (protoShape.styles.lineDashIi < 0.1 ? @(0.1) : @(protoShape.styles.lineDashIi))
  335. ];
  336. }
  337. shapeLayer.miterLimit = protoShape.styles.miterLimit;
  338. }
  339. }
  340. - (void)resetTransform:(CAShapeLayer *)shapeLayer shape:(NSDictionary *)shape {
  341. if ([shape[@"transform"] isKindOfClass:[NSDictionary class]]) {
  342. if ([shape[@"transform"][@"a"] isKindOfClass:[NSNumber class]] &&
  343. [shape[@"transform"][@"b"] isKindOfClass:[NSNumber class]] &&
  344. [shape[@"transform"][@"c"] isKindOfClass:[NSNumber class]] &&
  345. [shape[@"transform"][@"d"] isKindOfClass:[NSNumber class]] &&
  346. [shape[@"transform"][@"tx"] isKindOfClass:[NSNumber class]] &&
  347. [shape[@"transform"][@"ty"] isKindOfClass:[NSNumber class]]) {
  348. shapeLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransformMake([shape[@"transform"][@"a"] floatValue],
  349. [shape[@"transform"][@"b"] floatValue],
  350. [shape[@"transform"][@"c"] floatValue],
  351. [shape[@"transform"][@"d"] floatValue],
  352. [shape[@"transform"][@"tx"] floatValue],
  353. [shape[@"transform"][@"ty"] floatValue])
  354. );
  355. }
  356. }
  357. }
  358. - (void)resetTransform:(CAShapeLayer *)shapeLayer protoShape:(SVGAProtoShapeEntity *)protoShape {
  359. if (protoShape.hasTransform) {
  360. shapeLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransformMake((CGFloat)protoShape.transform.a,
  361. (CGFloat)protoShape.transform.b,
  362. (CGFloat)protoShape.transform.c,
  363. (CGFloat)protoShape.transform.d,
  364. (CGFloat)protoShape.transform.tx,
  365. (CGFloat)protoShape.transform.ty)
  366. );
  367. }
  368. }
  369. @end