New file |
| | |
| | | // |
| | | // YYFrameImage.m |
| | | // YYImage <https://github.com/ibireme/YYImage> |
| | | // |
| | | // Created by ibireme on 14/12/9. |
| | | // Copyright (c) 2015 ibireme. |
| | | // |
| | | // This source code is licensed under the MIT-style license found in the |
| | | // LICENSE file in the root directory of this source tree. |
| | | // |
| | | |
| | | #import "YYFrameImage.h" |
| | | #import "YYImageCoder.h" |
| | | |
| | | |
| | | /** |
| | | Return the path scale. |
| | | |
| | | e.g. |
| | | <table> |
| | | <tr><th>Path </th><th>Scale </th></tr> |
| | | <tr><td>"icon.png" </td><td>1 </td></tr> |
| | | <tr><td>"icon@2x.png" </td><td>2 </td></tr> |
| | | <tr><td>"icon@2.5x.png" </td><td>2.5 </td></tr> |
| | | <tr><td>"icon@2x" </td><td>1 </td></tr> |
| | | <tr><td>"icon@2x..png" </td><td>1 </td></tr> |
| | | <tr><td>"icon@2x.png/" </td><td>1 </td></tr> |
| | | </table> |
| | | */ |
| | | static CGFloat _NSStringPathScale(NSString *string) { |
| | | if (string.length == 0 || [string hasSuffix:@"/"]) return 1; |
| | | NSString *name = string.stringByDeletingPathExtension; |
| | | __block CGFloat scale = 1; |
| | | |
| | | NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines error:nil]; |
| | | [pattern enumerateMatchesInString:name options:kNilOptions range:NSMakeRange(0, name.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { |
| | | if (result.range.location >= 3) { |
| | | scale = [string substringWithRange:NSMakeRange(result.range.location + 1, result.range.length - 2)].doubleValue; |
| | | } |
| | | }]; |
| | | |
| | | return scale; |
| | | } |
| | | |
| | | |
| | | |
| | | @implementation YYFrameImage { |
| | | NSUInteger _loopCount; |
| | | NSUInteger _oneFrameBytes; |
| | | NSArray *_imagePaths; |
| | | NSArray *_imageDatas; |
| | | NSArray *_frameDurations; |
| | | } |
| | | |
| | | - (instancetype)initWithImagePaths:(NSArray *)paths oneFrameDuration:(NSTimeInterval)oneFrameDuration loopCount:(NSUInteger)loopCount { |
| | | NSMutableArray *durations = [NSMutableArray new]; |
| | | for (int i = 0, max = (int)paths.count; i < max; i++) { |
| | | [durations addObject:@(oneFrameDuration)]; |
| | | } |
| | | return [self initWithImagePaths:paths frameDurations:durations loopCount:loopCount]; |
| | | } |
| | | |
| | | - (instancetype)initWithImagePaths:(NSArray *)paths frameDurations:(NSArray *)frameDurations loopCount:(NSUInteger)loopCount { |
| | | if (paths.count == 0) return nil; |
| | | if (paths.count != frameDurations.count) return nil; |
| | | |
| | | NSString *firstPath = paths[0]; |
| | | NSData *firstData = [NSData dataWithContentsOfFile:firstPath]; |
| | | CGFloat scale = _NSStringPathScale(firstPath); |
| | | UIImage *firstCG = [[[UIImage alloc] initWithData:firstData] yy_imageByDecoded]; |
| | | self = [self initWithCGImage:firstCG.CGImage scale:scale orientation:UIImageOrientationUp]; |
| | | if (!self) return nil; |
| | | long frameByte = CGImageGetBytesPerRow(firstCG.CGImage) * CGImageGetHeight(firstCG.CGImage); |
| | | _oneFrameBytes = (NSUInteger)frameByte; |
| | | _imagePaths = paths.copy; |
| | | _frameDurations = frameDurations.copy; |
| | | _loopCount = loopCount; |
| | | |
| | | return self; |
| | | } |
| | | |
| | | - (instancetype)initWithImageDataArray:(NSArray *)dataArray oneFrameDuration:(NSTimeInterval)oneFrameDuration loopCount:(NSUInteger)loopCount { |
| | | NSMutableArray *durations = [NSMutableArray new]; |
| | | for (int i = 0, max = (int)dataArray.count; i < max; i++) { |
| | | [durations addObject:@(oneFrameDuration)]; |
| | | } |
| | | return [self initWithImageDataArray:dataArray frameDurations:durations loopCount:loopCount]; |
| | | } |
| | | |
| | | - (instancetype)initWithImageDataArray:(NSArray *)dataArray frameDurations:(NSArray *)frameDurations loopCount:(NSUInteger)loopCount { |
| | | if (dataArray.count == 0) return nil; |
| | | if (dataArray.count != frameDurations.count) return nil; |
| | | |
| | | NSData *firstData = dataArray[0]; |
| | | CGFloat scale = [UIScreen mainScreen].scale; |
| | | UIImage *firstCG = [[[UIImage alloc] initWithData:firstData] yy_imageByDecoded]; |
| | | self = [self initWithCGImage:firstCG.CGImage scale:scale orientation:UIImageOrientationUp]; |
| | | if (!self) return nil; |
| | | long frameByte = CGImageGetBytesPerRow(firstCG.CGImage) * CGImageGetHeight(firstCG.CGImage); |
| | | _oneFrameBytes = (NSUInteger)frameByte; |
| | | _imageDatas = dataArray.copy; |
| | | _frameDurations = frameDurations.copy; |
| | | _loopCount = loopCount; |
| | | |
| | | return self; |
| | | } |
| | | |
| | | #pragma mark - YYAnimtedImage |
| | | |
| | | - (NSUInteger)animatedImageFrameCount { |
| | | if (_imagePaths) { |
| | | return _imagePaths.count; |
| | | } else if (_imageDatas) { |
| | | return _imageDatas.count; |
| | | } else { |
| | | return 1; |
| | | } |
| | | } |
| | | |
| | | - (NSUInteger)animatedImageLoopCount { |
| | | return _loopCount; |
| | | } |
| | | |
| | | - (NSUInteger)animatedImageBytesPerFrame { |
| | | return _oneFrameBytes; |
| | | } |
| | | |
| | | - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { |
| | | if (_imagePaths) { |
| | | if (index >= _imagePaths.count) return nil; |
| | | NSString *path = _imagePaths[index]; |
| | | CGFloat scale = _NSStringPathScale(path); |
| | | NSData *data = [NSData dataWithContentsOfFile:path]; |
| | | return [[UIImage imageWithData:data scale:scale] yy_imageByDecoded]; |
| | | } else if (_imageDatas) { |
| | | if (index >= _imageDatas.count) return nil; |
| | | NSData *data = _imageDatas[index]; |
| | | return [[UIImage imageWithData:data scale:[UIScreen mainScreen].scale] yy_imageByDecoded]; |
| | | } else { |
| | | return index == 0 ? self : nil; |
| | | } |
| | | } |
| | | |
| | | - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { |
| | | if (index >= _frameDurations.count) return 0; |
| | | NSNumber *num = _frameDurations[index]; |
| | | return [num doubleValue]; |
| | | } |
| | | |
| | | @end |