diff --git a/Pod/Classes/PINAnimatedImage.h b/Pod/Classes/PINAnimatedImage.h index 644a072..7d62cee 100644 --- a/Pod/Classes/PINAnimatedImage.h +++ b/Pod/Classes/PINAnimatedImage.h @@ -57,7 +57,7 @@ extern const NSTimeInterval kPINAnimatedImageDisplayRefreshRate; /** Called when the cover image of an animatedImage is ready. */ -typedef void(^PINAnimatedImageInfoReady)(PINImage *coverImage); +typedef void(^PINAnimatedImageInfoReady)(PINImage *firstImage); /** @@ -99,23 +99,23 @@ typedef void(^PINAnimatedImageInfoReady)(PINImage *coverImage); @property (nonatomic, assign, readwrite) PINAnimatedImageStatus status; /** - A helper function which references status to check if the coverImage is ready. + A helper function which references status to check if the firstImage is ready. */ -@property (nonatomic, readonly) BOOL coverImageReady; +@property (nonatomic, readonly) BOOL firstImageReady; /** A helper function which references status to check if playback is ready. */ @property (nonatomic, readonly) BOOL playbackReady; /** The first frame / cover image of the animated image. - @warning Access to this property before status == PINAnimatedImageStatusInfoProcessed is undefined. You can check coverImageReady too. + @warning Access to this property before status == PINAnimatedImageStatusInfoProcessed is undefined. You can check firstImageReady too. */ -@property (nonatomic, readonly) PINImage *coverImage; +@property (nonatomic, readonly) PINImage *firstImage; /** The total duration of one loop of playback. @warning Access to this property before status == PINAnimatedImageStatusInfoProcessed is undefined. */ -@property (nonatomic, readonly) CFTimeInterval totalDuration; +@property (nonatomic, readonly) CFTimeInterval combinedDurations; /** The number of frames to play per second * display refresh rate (defined as 60 which appears to be true on iOS). You probably want to set this value on a displayLink. @@ -142,13 +142,13 @@ typedef void(^PINAnimatedImageInfoReady)(PINImage *coverImage); @param index The index of the frame to retrieve. @warning Access to this property before status == PINAnimatedImageStatusInfoProcessed is undefined. */ -- (CGImageRef)imageAtIndex:(NSUInteger)index; +- (CGImageRef)imageForIndex:(NSUInteger)index; /** The duration of the frame of the passed in index. @param index The index of the frame to retrieve the duration it should be shown for. @warning Access to this property before status == PINAnimatedImageStatusInfoProcessed is undefined. */ -- (CFTimeInterval)durationAtIndex:(NSUInteger)index; +- (CFTimeInterval)durationForIndex:(NSUInteger)index; /** Clears out the strong references to any memory maps that are being held. */ diff --git a/Pod/Classes/PINAnimatedImage.m b/Pod/Classes/PINAnimatedImage.m index 8f9837e..31a05f1 100644 --- a/Pod/Classes/PINAnimatedImage.m +++ b/Pod/Classes/PINAnimatedImage.m @@ -52,13 +52,13 @@ const Float32 kPINAnimatedImageMinimumDuration = 1 / kPINAnimatedImageDisplayRef NSAssert(animatedImageData != nil, @"animatedImageData must not be nil."); - [[PINAnimatedImageManager sharedManager] animatedPathForImageData:animatedImageData infoCompletion:^(PINImage *coverImage, PINSharedAnimatedImage *shared) { + [[PINAnimatedImageManager sharedManager] animatedPathForImageData:animatedImageData infoCompletion:^(PINImage *firstImage, PINSharedAnimatedImage *shared) { self.sharedAnimatedImage = shared; self.infoCompleted = YES; [_completionLock lockWithBlock:^{ if (_infoCompletion) { - _infoCompletion(coverImage); + _infoCompletion(firstImage); _infoCompletion = nil; } }]; @@ -110,9 +110,9 @@ const Float32 kPINAnimatedImageMinimumDuration = 1 / kPINAnimatedImageDisplayRef }]; } -- (PINImage *)coverImageWithMemoryMap:(NSData *)memoryMap width:(UInt32)width height:(UInt32)height bitsPerPixel:(UInt32)bitsPerPixel bitmapInfo:(CGBitmapInfo)bitmapInfo +- (PINImage *)firstImageWithMemoryMap:(NSData *)memoryMap width:(UInt32)width height:(UInt32)height bitsPerPixel:(UInt32)bitsPerPixel bitmapInfo:(CGBitmapInfo)bitmapInfo { - CGImageRef imageRef = [[self class] imageAtIndex:0 inMemoryMap:memoryMap width:width height:height bitsPerPixel:bitsPerPixel bitmapInfo:bitmapInfo]; + CGImageRef imageRef = [[self class] imageForIndex:0 inMemoryMap:memoryMap width:width height:height bitsPerPixel:bitsPerPixel bitmapInfo:bitmapInfo]; #if PIN_TARGET_IOS return [UIImage imageWithCGImage:imageRef]; #elif PIN_TARGET_MAC @@ -127,7 +127,7 @@ void releaseData(void *data, const void *imageData, size_t size) CFRelease(data); } -- (CGImageRef)imageAtIndex:(NSUInteger)index inSharedImageFiles:(NSArray *)imageFiles width:(UInt32)width height:(UInt32)height bitsPerPixel:(UInt32)bitsPerPixel bitmapInfo:(CGBitmapInfo)bitmapInfo +- (CGImageRef)imageForIndex:(NSUInteger)index inSharedImageFiles:(NSArray *)imageFiles width:(UInt32)width height:(UInt32)height bitsPerPixel:(UInt32)bitsPerPixel bitmapInfo:(CGBitmapInfo)bitmapInfo { if (self.status == PINAnimatedImageStatusError) { return nil; @@ -146,7 +146,7 @@ void releaseData(void *data, const void *imageData, size_t size) }]; }); }]; - return [[self class] imageAtIndex:index inMemoryMap:memoryMappedData width:width height:height bitsPerPixel:bitsPerPixel bitmapInfo:bitmapInfo]; + return [[self class] imageForIndex:index inMemoryMap:memoryMappedData width:width height:height bitsPerPixel:bitsPerPixel bitmapInfo:bitmapInfo]; } else { index -= imageFile.frameCount; } @@ -155,12 +155,12 @@ void releaseData(void *data, const void *imageData, size_t size) return nil; } -- (CFTimeInterval)durationAtIndex:(NSUInteger)index +- (CFTimeInterval)durationForIndex:(NSUInteger)index { return self.durations[index]; } -+ (CGImageRef)imageAtIndex:(NSUInteger)index inMemoryMap:(NSData *)memoryMap width:(UInt32)width height:(UInt32)height bitsPerPixel:(UInt32)bitsPerPixel bitmapInfo:(CGBitmapInfo)bitmapInfo ++ (CGImageRef)imageForIndex:(NSUInteger)index inMemoryMap:(NSData *)memoryMap width:(UInt32)width height:(UInt32)height bitsPerPixel:(UInt32)bitsPerPixel bitmapInfo:(CGBitmapInfo)bitmapInfo { if (memoryMap == nil) { return nil; @@ -242,13 +242,13 @@ void releaseData(void *data, const void *imageData, size_t size) } //durations should be a buffer of size Float32 * frameCount -+ (Float32 *)createDurations:(Float32 *)durations fromMemoryMap:(NSData *)memoryMap frameCount:(UInt32)frameCount frameSize:(NSUInteger)frameSize totalDuration:(nonnull CFTimeInterval *)totalDuration ++ (Float32 *)createDurations:(Float32 *)durations fromMemoryMap:(NSData *)memoryMap frameCount:(UInt32)frameCount frameSize:(NSUInteger)frameSize combinedDurations:(nonnull CFTimeInterval *)combinedDurations { - *totalDuration = 0; + *combinedDurations = 0; [memoryMap getBytes:&durations range:NSMakeRange(22, sizeof(Float32) * frameCount)]; for (NSUInteger idx = 0; idx < frameCount; idx++) { - *totalDuration += durations[idx]; + *combinedDurations += durations[idx]; } return durations; @@ -260,10 +260,10 @@ void releaseData(void *data, const void *imageData, size_t size) return self.sharedAnimatedImage.durations; } -- (CFTimeInterval)totalDuration +- (CFTimeInterval)combinedDurations { NSAssert([self infoReady], @"info must be ready"); - return self.sharedAnimatedImage.totalDuration; + return self.sharedAnimatedImage.combinedDurations; } - (size_t)loopCount @@ -303,9 +303,9 @@ void releaseData(void *data, const void *imageData, size_t size) return self.sharedAnimatedImage.status; } -- (CGImageRef)imageAtIndex:(NSUInteger)index +- (CGImageRef)imageForIndex:(NSUInteger)index { - return [self imageAtIndex:index + return [self imageForIndex:index inSharedImageFiles:self.sharedAnimatedImage.maps width:(UInt32)self.sharedAnimatedImage.width height:(UInt32)self.sharedAnimatedImage.height @@ -313,10 +313,10 @@ void releaseData(void *data, const void *imageData, size_t size) bitmapInfo:self.sharedAnimatedImage.bitmapInfo]; } -- (PINImage *)coverImage +- (PINImage *)firstImage { - NSAssert(self.coverImageReady, @"cover image must be ready."); - return self.sharedAnimatedImage.coverImage; + NSAssert(self.firstImageReady, @"cover image must be ready."); + return self.sharedAnimatedImage.firstImage; } - (BOOL)infoReady @@ -324,7 +324,7 @@ void releaseData(void *data, const void *imageData, size_t size) return self.infoCompleted; } -- (BOOL)coverImageReady +- (BOOL)firstImageReady { return self.status == PINAnimatedImageStatusInfoProcessed || self.status == PINAnimatedImageStatusFirstFileProcessed || self.status == PINAnimatedImageStatusProcessed; } @@ -391,7 +391,7 @@ static NSUInteger gcd(NSUInteger a, NSUInteger b) - (instancetype)init { if (self = [super init]) { - _coverImageLock = [[PINRemoteLock alloc] initWithName:@"PINSharedAnimatedImage cover image lock"]; + _firstImageLock = [[PINRemoteLock alloc] initWithName:@"PINSharedAnimatedImage cover image lock"]; _completions = @[]; _infoCompletions = @[]; _maps = @[]; @@ -399,16 +399,16 @@ static NSUInteger gcd(NSUInteger a, NSUInteger b) return self; } -- (void)setInfoProcessedWithCoverImage:(PINImage *)coverImage UUID:(NSUUID *)UUID durations:(Float32 *)durations totalDuration:(CFTimeInterval)totalDuration loopCount:(size_t)loopCount frameCount:(size_t)frameCount width:(size_t)width height:(size_t)height bitsPerPixel:(size_t)bitsPerPixel bitmapInfo:(CGBitmapInfo)bitmapInfo +- (void)setInfoProcessedWithFirstImage:(PINImage *)firstImage UUID:(NSUUID *)UUID durations:(Float32 *)durations combinedDurations:(CFTimeInterval)combinedDurations loopCount:(size_t)loopCount frameCount:(size_t)frameCount width:(size_t)width height:(size_t)height bitsPerPixel:(size_t)bitsPerPixel bitmapInfo:(CGBitmapInfo)bitmapInfo { NSAssert(_status == PINAnimatedImageStatusUnprocessed, @"Status should be unprocessed."); - [_coverImageLock lockWithBlock:^{ - _coverImage = coverImage; + [_firstImageLock lockWithBlock:^{ + _firstImage = firstImage; }]; _UUID = UUID; _durations = (Float32 *)malloc(sizeof(Float32) * frameCount); memcpy(_durations, durations, sizeof(Float32) * frameCount); - _totalDuration = totalDuration; + _combinedDurations = combinedDurations; _loopCount = loopCount; _frameCount = frameCount; _width = width; @@ -441,24 +441,24 @@ static NSUInteger gcd(NSUInteger a, NSUInteger b) free(_durations); } -- (PINImage *)coverImage +- (PINImage *)firstImage { - __block PINImage *coverImage = nil; - [_coverImageLock lockWithBlock:^{ - if (_coverImage == nil) { - CGImageRef imageRef = [PINAnimatedImage imageAtIndex:0 inMemoryMap:self.maps[0].memoryMappedData width:(UInt32)self.width height:(UInt32)self.height bitsPerPixel:(UInt32)self.bitsPerPixel bitmapInfo:self.bitmapInfo]; + __block PINImage *firstImage = nil; + [_firstImageLock lockWithBlock:^{ + if (_firstImage == nil) { + CGImageRef imageRef = [PINAnimatedImage imageForIndex:0 inMemoryMap:self.maps[0].memoryMappedData width:(UInt32)self.width height:(UInt32)self.height bitsPerPixel:(UInt32)self.bitsPerPixel bitmapInfo:self.bitmapInfo]; #if PIN_TARGET_IOS - coverImage = [UIImage imageWithCGImage:imageRef]; + firstImage = [UIImage imageWithCGImage:imageRef]; #elif PIN_TARGET_MAC - coverImage = [[NSImage alloc] initWithCGImage:imageRef size:CGSizeMake(self.width, self.height)]; + firstImage = [[NSImage alloc] initWithCGImage:imageRef size:CGSizeMake(self.width, self.height)]; #endif - _coverImage = coverImage; + _firstImage = firstImage; } else { - coverImage = _coverImage; + firstImage = _firstImage; } }]; - return coverImage; + return firstImage; } @end diff --git a/Pod/Classes/PINAnimatedImageManager.h b/Pod/Classes/PINAnimatedImageManager.h index 0e7cff3..51e4fa0 100644 --- a/Pod/Classes/PINAnimatedImageManager.h +++ b/Pod/Classes/PINAnimatedImageManager.h @@ -15,7 +15,7 @@ @class PINSharedAnimatedImage; @class PINSharedAnimatedImageFile; -typedef void(^PINAnimatedImageSharedReady)(PINImage *coverImage, PINSharedAnimatedImage *shared); +typedef void(^PINAnimatedImageSharedReady)(PINImage *firstImage, PINSharedAnimatedImage *shared); typedef void(^PINAnimatedImageDecodedPath)(BOOL finished, NSString *path, NSError *error); @interface PINAnimatedImageManager : NSObject @@ -30,7 +30,7 @@ typedef void(^PINAnimatedImageDecodedPath)(BOOL finished, NSString *path, NSErro @interface PINSharedAnimatedImage : NSObject { - PINRemoteLock *_coverImageLock; + PINRemoteLock *_firstImageLock; } //This is intentionally atomic. PINAnimatedImageManager must be able to add entries @@ -39,16 +39,16 @@ typedef void(^PINAnimatedImageDecodedPath)(BOOL finished, NSString *path, NSErro @property (nonatomic, strong, readwrite) NSArray *completions; @property (nonatomic, strong, readwrite) NSArray *infoCompletions; -@property (nonatomic, weak, readwrite) PINImage *coverImage; +@property (nonatomic, weak, readwrite) PINImage *firstImage; //intentionally atomic @property (atomic, strong, readwrite) NSError *error; @property (atomic, assign, readwrite) PINAnimatedImageStatus status; -- (void)setInfoProcessedWithCoverImage:(PINImage *)coverImage +- (void)setInfoProcessedWithFirstImage:(PINImage *)firstImage UUID:(NSUUID *)UUID durations:(Float32 *)durations - totalDuration:(CFTimeInterval)totalDuration + combinedDurations:(CFTimeInterval)combinedDurations loopCount:(size_t)loopCount frameCount:(size_t)frameCount width:(size_t)width @@ -58,7 +58,7 @@ typedef void(^PINAnimatedImageDecodedPath)(BOOL finished, NSString *path, NSErro @property (nonatomic, readonly) NSUUID *UUID; @property (nonatomic, readonly) Float32 *durations; -@property (nonatomic, readonly) CFTimeInterval totalDuration; +@property (nonatomic, readonly) CFTimeInterval combinedDurations; @property (nonatomic, readonly) size_t loopCount; @property (nonatomic, readonly) size_t frameCount; @property (nonatomic, readonly) size_t width; diff --git a/Pod/Classes/PINAnimatedImageManager.m b/Pod/Classes/PINAnimatedImageManager.m index 166df60..0ab83d6 100644 --- a/Pod/Classes/PINAnimatedImageManager.m +++ b/Pod/Classes/PINAnimatedImageManager.m @@ -20,10 +20,10 @@ static const NSUInteger maxFileSize = 50000000; //max file size in bytes static const Float32 maxFileDuration = 1; //max duration of a file in seconds -typedef void(^PINAnimatedImageInfoProcessed)(PINImage *coverImage, NSUUID *UUID, Float32 *durations, CFTimeInterval totalDuration, size_t loopCount, size_t frameCount, size_t width, size_t height, size_t bitsPerPixel, UInt32 bitmapInfo); +typedef void(^PINAnimatedImageInfoProcessed)(PINImage *firstImage, NSUUID *UUID, Float32 *durations, CFTimeInterval combinedDurations, size_t loopCount, size_t frameCount, size_t width, size_t height, size_t bitsPerPixel, UInt32 bitmapInfo); -BOOL PINStatusCoverImageCompleted(PINAnimatedImageStatus status); -BOOL PINStatusCoverImageCompleted(PINAnimatedImageStatus status) { +BOOL PINStatusFirstImageCompleted(PINAnimatedImageStatus status); +BOOL PINStatusFirstImageCompleted(PINAnimatedImageStatus status) { return status == PINAnimatedImageStatusInfoProcessed || status == PINAnimatedImageStatusFirstFileProcessed || status == PINAnimatedImageStatusProcessed; } @@ -124,18 +124,18 @@ static dispatch_once_t startupCleanupOnce; startProcessing = YES; } - if (PINStatusCoverImageCompleted(sharedAnimatedImage.status)) { + if (PINStatusFirstImageCompleted(sharedAnimatedImage.status)) { //Info is already processed, call infoCompletion immediately if (infoCompletion) { - infoCompletion(sharedAnimatedImage.coverImage, sharedAnimatedImage); + infoCompletion(sharedAnimatedImage.firstImage, sharedAnimatedImage); } } else { //Add infoCompletion to sharedAnimatedImage if (infoCompletion) { //Since ASSharedAnimatedImages are stored weakly in our map, we need a strong reference in completions - PINAnimatedImageSharedReady capturingInfoCompletion = ^(PINImage *coverImage, PINSharedAnimatedImage *newShared) { + PINAnimatedImageSharedReady capturingInfoCompletion = ^(PINImage *firstImage, PINSharedAnimatedImage *newShared) { __unused PINSharedAnimatedImage *strongShared = sharedAnimatedImage; - infoCompletion(coverImage, newShared); + infoCompletion(firstImage, newShared); }; sharedAnimatedImage.infoCompletions = [sharedAnimatedImage.infoCompletions arrayByAddingObject:capturingInfoCompletion]; } @@ -166,18 +166,18 @@ static dispatch_once_t startupCleanupOnce; if (startProcessing) { dispatch_async(self.serialProcessingQueue, ^{ - [[self class] processAnimatedImage:animatedImageData temporaryDirectory:[PINAnimatedImageManager temporaryDirectory] infoCompletion:^(PINImage *coverImage, NSUUID *UUID, Float32 *durations, CFTimeInterval totalDuration, size_t loopCount, size_t frameCount, size_t width, size_t height, size_t bitsPerPixel, UInt32 bitmapInfo) { + [[self class] processAnimatedImage:animatedImageData temporaryDirectory:[PINAnimatedImageManager temporaryDirectory] infoCompletion:^(PINImage *firstImage, NSUUID *UUID, Float32 *durations, CFTimeInterval combinedDurations, size_t loopCount, size_t frameCount, size_t width, size_t height, size_t bitsPerPixel, UInt32 bitmapInfo) { __block NSArray *infoCompletions = nil; __block PINSharedAnimatedImage *sharedAnimatedImage = nil; [_lock lockWithBlock:^{ sharedAnimatedImage = [self.animatedImages objectForKey:animatedImageData]; - [sharedAnimatedImage setInfoProcessedWithCoverImage:coverImage UUID:UUID durations:durations totalDuration:totalDuration loopCount:loopCount frameCount:frameCount width:width height:height bitsPerPixel:bitsPerPixel bitmapInfo:bitmapInfo]; + [sharedAnimatedImage setInfoProcessedWithFirstImage:firstImage UUID:UUID durations:durations combinedDurations:combinedDurations loopCount:loopCount frameCount:frameCount width:width height:height bitsPerPixel:bitsPerPixel bitmapInfo:bitmapInfo]; infoCompletions = sharedAnimatedImage.infoCompletions; sharedAnimatedImage.infoCompletions = @[]; }]; for (PINAnimatedImageSharedReady infoCompletion in infoCompletions) { - infoCompletion(coverImage, sharedAnimatedImage); + infoCompletion(firstImage, sharedAnimatedImage); } } decodedPath:^(BOOL finished, NSString *path, NSError *error) { __block NSArray *completions = nil; @@ -279,8 +279,8 @@ ERROR;}) \ Float32 fileDuration = 0; NSUInteger fileSize = 0; durations = (Float32 *)malloc(sizeof(Float32) * frameCount); - CFTimeInterval totalDuration = 0; - PINImage *coverImage = nil; + CFTimeInterval combinedDurations = 0; + PINImage *firstImage = nil; //Gather header file info for (NSUInteger frameIdx = 0; frameIdx < frameCount; frameIdx++) { @@ -299,20 +299,20 @@ ERROR;}) \ bitsPerPixel = (UInt32)CGImageGetBitsPerPixel(frameImage); #if PIN_TARGET_IOS - coverImage = [UIImage imageWithCGImage:frameImage]; + firstImage = [UIImage imageWithCGImage:frameImage]; #elif PIN_TARGET_MAC - coverImage = [[NSImage alloc] initWithCGImage:frameImage size:CGSizeMake(width, height)]; + firstImage = [[NSImage alloc] initWithCGImage:frameImage size:CGSizeMake(width, height)]; #endif CGImageRelease(frameImage); } - Float32 duration = [[self class] frameDurationAtIndex:frameIdx source:imageSource]; + Float32 duration = [[self class] frameDurationForIndex:frameIdx source:imageSource]; durations[frameIdx] = duration; - totalDuration += duration; + combinedDurations += duration; } if (PROCESSING_ERROR == nil) { - //Get size, write file header get coverImage + //Get size, write file header get firstImage dispatch_group_async(diskGroup, diskWriteQueue, ^{ NSError *fileHeaderError = [self writeFileHeader:fileHandle width:width height:height bitsPerPixel:bitsPerPixel loopCount:loopCount frameCount:frameCount bitmapInfo:bitmapInfo durations:durations]; HANDLE_PROCESSING_ERROR(fileHeaderError); @@ -320,7 +320,7 @@ ERROR;}) \ [fileHandle closeFile]; PINLog(@"notifying info"); - infoCompletion(coverImage, UUID, durations, totalDuration, loopCount, frameCount, width, height, bitsPerPixel, bitmapInfo); + infoCompletion(firstImage, UUID, durations, combinedDurations, loopCount, frameCount, width, height, bitsPerPixel, bitmapInfo); } }); fileCount = 1; @@ -443,7 +443,7 @@ ERROR;}) \ } //http://stackoverflow.com/questions/16964366/delaytime-or-unclampeddelaytime-for-gifs -+ (Float32)frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source ++ (Float32)frameDurationForIndex:(NSUInteger)index source:(CGImageSourceRef)source { Float32 frameDuration = kPINAnimatedImageDefaultDuration; NSDictionary *frameProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(source, index, nil);