207 lines
6.7 KiB
Objective-C

//
// LOTLayer.m
// LottieAnimator
//
// Created by Brandon Withrow on 12/14/15.
// Copyright © 2015 Brandon Withrow. All rights reserved.
//
#import "LOTLayer.h"
#import "LOTAsset.h"
#import "LOTAssetGroup.h"
#import "LOTAnimatableColorValue.h"
#import "LOTAnimatablePointValue.h"
#import "LOTAnimatableNumberValue.h"
#import "LOTAnimatableScaleValue.h"
#import "LOTShapeGroup.h"
#import "LOTComposition.h"
#import "LOTHelpers.h"
#import "LOTMask.h"
#import "LOTHelpers.h"
@implementation LOTLayer
- (instancetype)initWithJSON:(NSDictionary *)jsonDictionary
withCompBounds:(CGRect)compBounds
withFramerate:(NSNumber *)framerate
withAssetGroup:(LOTAssetGroup *)assetGroup {
self = [super init];
if (self) {
[self _mapFromJSON:jsonDictionary
withCompBounds:compBounds
withFramerate:framerate
withAssetGroup:assetGroup];
}
return self;
}
- (void)_mapFromJSON:(NSDictionary *)jsonDictionary
withCompBounds:(CGRect)compBounds
withFramerate:(NSNumber *)framerate
withAssetGroup:(LOTAssetGroup *)assetGroup{
_parentCompBounds = compBounds;
_layerName = [jsonDictionary[@"nm"] copy];
_layerID = [jsonDictionary[@"ind"] copy];
NSNumber *layerType = jsonDictionary[@"ty"];
_layerType = layerType.integerValue;
if (jsonDictionary[@"refId"]) {
_referenceID = [jsonDictionary[@"refId"] copy];
}
_parentID = [jsonDictionary[@"parent"] copy];
_inFrame = [jsonDictionary[@"ip"] copy];
_outFrame = [jsonDictionary[@"op"] copy];
_framerate = framerate;
if (_layerType == LOTLayerTypePrecomp) {
_layerHeight = [jsonDictionary[@"h"] copy];
_layerWidth = [jsonDictionary[@"w"] copy];
[assetGroup buildAssetNamed:_referenceID
withBounds:CGRectMake(0, 0, _layerWidth.floatValue, _layerHeight.floatValue)
andFramerate:_framerate];
} else if (_layerType == LOTLayerTypeImage) {
[assetGroup buildAssetNamed:_referenceID
withBounds:CGRectZero
andFramerate:_framerate];
_imageAsset = [assetGroup assetModelForID:_referenceID];
_layerWidth = [_imageAsset.assetWidth copy];
_layerHeight = [_imageAsset.assetHeight copy];
} else if (_layerType == LOTLayerTypeSolid) {
_layerWidth = jsonDictionary[@"sw"];
_layerHeight = jsonDictionary[@"sh"];
NSString *solidColor = jsonDictionary[@"sc"];
_solidColor = [UIColor LOT_colorWithHexString:solidColor];
} else {
_layerWidth = @(compBounds.size.width);
_layerHeight = @(compBounds.size.height);
}
_layerBounds = CGRectMake(0, 0, _layerWidth.floatValue, _layerHeight.floatValue);
NSDictionary *ks = jsonDictionary[@"ks"];
NSDictionary *opacity = ks[@"o"];
if (opacity) {
_opacity = [[LOTAnimatableNumberValue alloc] initWithNumberValues:opacity frameRate:_framerate];
[_opacity remapValuesFromMin:@0 fromMax:@100 toMin:@0 toMax:@1];
}
NSDictionary *rotation = ks[@"r"];
if (rotation == nil) {
rotation = ks[@"rz"];
}
if (rotation) {
_rotation = [[LOTAnimatableNumberValue alloc] initWithNumberValues:rotation frameRate:_framerate];
[_rotation remapValueWithBlock:^CGFloat(CGFloat inValue) {
return LOT_DegreesToRadians(inValue);
}];
}
NSDictionary *position = ks[@"p"];
if ([position[@"s"] boolValue]) {
// Separate dimensions
_positionX = [[LOTAnimatableNumberValue alloc] initWithNumberValues:position[@"x"] frameRate:_framerate];
_positionY = [[LOTAnimatableNumberValue alloc] initWithNumberValues:position[@"y"] frameRate:_framerate];
} else {
_position = [[LOTAnimatablePointValue alloc] initWithPointValues:position frameRate:_framerate];
}
NSDictionary *anchor = ks[@"a"];
if (anchor) {
_anchor = [[LOTAnimatablePointValue alloc] initWithPointValues:anchor frameRate:_framerate];
[_anchor remapPointsFromBounds:_layerBounds toBounds:CGRectMake(0, 0, 1, 1)];
_anchor.usePathAnimation = NO;
}
NSDictionary *scale = ks[@"s"];
if (scale) {
_scale = [[LOTAnimatableScaleValue alloc] initWithScaleValues:scale frameRate:_framerate];
}
_matteType = [jsonDictionary[@"tt"] integerValue];
NSMutableArray *masks = [NSMutableArray array];
for (NSDictionary *maskJSON in jsonDictionary[@"masksProperties"]) {
LOTMask *mask = [[LOTMask alloc] initWithJSON:maskJSON frameRate:_framerate];
[masks addObject:mask];
}
_masks = masks.count ? masks : nil;
NSMutableArray *shapes = [NSMutableArray array];
for (NSDictionary *shapeJSON in jsonDictionary[@"shapes"]) {
id shapeItem = [LOTShapeGroup shapeItemWithJSON:shapeJSON frameRate:_framerate compBounds:_layerBounds];
if (shapeItem) {
[shapes addObject:shapeItem];
}
}
_shapes = shapes;
NSArray *effects = jsonDictionary[@"ef"];
if (effects.count > 0) {
NSDictionary *effectNames = @{ @0: @"slider",
@1: @"angle",
@2: @"color",
@3: @"point",
@4: @"checkbox",
@5: @"group",
@6: @"noValue",
@7: @"dropDown",
@9: @"customValue",
@10: @"layerIndex",
@20: @"tint",
@21: @"fill" };
for (NSDictionary *effect in effects) {
NSNumber *typeNumber = effect[@"ty"];
NSString *name = effect[@"nm"];
NSString *internalName = effect[@"mn"];
NSString *typeString = effectNames[typeNumber];
if (typeString) {
NSLog(@"%s: Warning: %@ effect not supported: %@ / %@", __PRETTY_FUNCTION__, typeString, internalName, name);
}
}
}
_hasInAnimation = _inFrame.integerValue > 0;
NSMutableArray *keys = [NSMutableArray array];
NSMutableArray *keyTimes = [NSMutableArray array];
CGFloat layerLength = _outFrame.integerValue;
_layerDuration = (layerLength / _framerate.floatValue);
if (_hasInAnimation) {
[keys addObject:@1];
[keyTimes addObject:@0];
[keys addObject:@0];
CGFloat inTime = _inFrame.floatValue / layerLength;
[keyTimes addObject:@(inTime)];
} else {
[keys addObject:@0];
[keyTimes addObject:@0];
}
[keys addObject:@1];
[keyTimes addObject:@1];
_inOutKeyTimes = keyTimes;
_inOutKeyframes = keys;
}
- (NSString*)description {
NSMutableString *text = [[super description] mutableCopy];
[text appendFormat:@" %@ id: %d pid: %d frames: %d-%d", _layerName, (int)_layerID.integerValue, (int)_parentID.integerValue,
(int)_inFrame.integerValue, (int)_outFrame.integerValue];
return text;
}
@end