diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index f74b9928..97ea8a4c 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -67,6 +67,10 @@ 5376131E155AD0D5005750A4 /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D91148C56230056699D /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5376131F155AD0D5005750A4 /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D93148C56230056699D /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; 53761320155AD0D5005750A4 /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D95148C56230056699D /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 53EDFB8A17623F7C00698166 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */; }; + 53EDFB8B17623F7C00698166 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */; }; + 53EDFB8C17623F7C00698166 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */; }; + 53EDFB8D17623F7C00698166 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */; }; A18A6CC7172DC28500419892 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; }; A18A6CC8172DC28500419892 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = A18A6CC5172DC28500419892 /* UIImage+GIF.h */; }; A18A6CC9172DC28500419892 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = A18A6CC6172DC28500419892 /* UIImage+GIF.m */; }; @@ -112,6 +116,8 @@ 53922D94148C56230056699D /* UIButton+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIButton+WebCache.m"; path = "SDWebImage/UIButton+WebCache.m"; sourceTree = SOURCE_ROOT; }; 53922D95148C56230056699D /* UIImageView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIImageView+WebCache.h"; path = "SDWebImage/UIImageView+WebCache.h"; sourceTree = SOURCE_ROOT; }; 53922D96148C56230056699D /* UIImageView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+WebCache.m"; path = "SDWebImage/UIImageView+WebCache.m"; sourceTree = SOURCE_ROOT; }; + 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+MultiFormat.h"; sourceTree = ""; }; + 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+MultiFormat.m"; sourceTree = ""; }; 53FB893F14D35D1A0020B787 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 53FB894814D35E9E0020B787 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; A18A6CC5172DC28500419892 /* UIImage+GIF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+GIF.h"; sourceTree = ""; }; @@ -190,14 +196,16 @@ 53922DA9148C562D0056699D /* Categories */ = { isa = PBXGroup; children = ( - 535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */, - 535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */, + 53EDFB8817623F7C00698166 /* UIImage+MultiFormat.h */, + 53EDFB8917623F7C00698166 /* UIImage+MultiFormat.m */, A18A6CCB172DC33A00419892 /* NSData+GIF.h */, A18A6CCC172DC33A00419892 /* NSData+GIF.m */, - 53922D93148C56230056699D /* UIButton+WebCache.h */, - 53922D94148C56230056699D /* UIButton+WebCache.m */, A18A6CC5172DC28500419892 /* UIImage+GIF.h */, A18A6CC6172DC28500419892 /* UIImage+GIF.m */, + 535699B415113E7300A4C397 /* MKAnnotationView+WebCache.h */, + 535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */, + 53922D93148C56230056699D /* UIButton+WebCache.h */, + 53922D94148C56230056699D /* UIButton+WebCache.m */, 53922D95148C56230056699D /* UIImageView+WebCache.h */, 53922D96148C56230056699D /* UIImageView+WebCache.m */, ); @@ -257,6 +265,7 @@ 530E49EB16464C7F002868E7 /* SDWebImageDownloaderOperation.h in Headers */, A18A6CC8172DC28500419892 /* UIImage+GIF.h in Headers */, A18A6CCE172DC33A00419892 /* NSData+GIF.h in Headers */, + 53EDFB8B17623F7C00698166 /* UIImage+MultiFormat.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -276,6 +285,7 @@ 530E49EA16464C7C002868E7 /* SDWebImageDownloaderOperation.h in Headers */, A18A6CC7172DC28500419892 /* UIImage+GIF.h in Headers */, A18A6CCD172DC33A00419892 /* NSData+GIF.h in Headers */, + 53EDFB8A17623F7C00698166 /* UIImage+MultiFormat.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -392,6 +402,7 @@ 530E49ED16464C84002868E7 /* SDWebImageDownloaderOperation.m in Sources */, A18A6CCA172DC28500419892 /* UIImage+GIF.m in Sources */, A18A6CD0172DC33A00419892 /* NSData+GIF.m in Sources */, + 53EDFB8D17623F7C00698166 /* UIImage+MultiFormat.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -410,6 +421,7 @@ 53406750167780C40042B59E /* SDWebImageCompat.m in Sources */, A18A6CC9172DC28500419892 /* UIImage+GIF.m in Sources */, A18A6CCF172DC33A00419892 /* NSData+GIF.m in Sources */, + 53EDFB8C17623F7C00698166 /* UIImage+MultiFormat.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index a926b11b..22e37148 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -8,7 +8,7 @@ #import "SDImageCache.h" #import "SDWebImageDecoder.h" -#import "UIImage+GIF.h" +#import "UIImage+MultiFormat.h" #import #import #import @@ -226,17 +226,10 @@ static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week NSData *data = [self diskImageDataBySearchingAllPathsForKey:key]; if (data) { - if ([data sd_isGIF]) - { - UIImage *image = [UIImage sd_animatedGIFWithData:data]; - return [self scaledImageForKey:key image:image]; - } - else - { - UIImage *image = [[UIImage alloc] initWithData:data]; - UIImage *scaledImage = [self scaledImageForKey:key image:image]; - return [UIImage decodedImageWithImage:scaledImage]; - } + UIImage *image = [UIImage sd_imageWithData:data]; + image = [self scaledImageForKey:key image:image]; + image = [UIImage decodedImageWithImage:image]; + return image; } else { diff --git a/SDWebImage/SDWebImageDecoder.m b/SDWebImage/SDWebImageDecoder.m index fe70fd93..6e904d3a 100644 --- a/SDWebImage/SDWebImageDecoder.m +++ b/SDWebImage/SDWebImageDecoder.m @@ -13,7 +13,13 @@ @implementation UIImage (ForceDecode) + (UIImage *)decodedImageWithImage:(UIImage *)image -{ +{ + if (image.images) + { + // Do not decode animated images + return image; + } + CGImageRef imageRef = image.CGImage; CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); CGRect imageRect = (CGRect){.origin = CGPointZero, .size = imageSize}; diff --git a/SDWebImage/SDWebImageDownloaderOperation.m b/SDWebImage/SDWebImageDownloaderOperation.m index d8b56098..df394ab7 100644 --- a/SDWebImage/SDWebImageDownloaderOperation.m +++ b/SDWebImage/SDWebImageDownloaderOperation.m @@ -8,7 +8,7 @@ #import "SDWebImageDownloaderOperation.h" #import "SDWebImageDecoder.h" -#import "UIImage+GIF.h" +#import "UIImage+MultiFormat.h" #import @interface SDWebImageDownloaderOperation () @@ -273,21 +273,13 @@ } else { - BOOL isImageGIF = [self.imageData sd_isGIF]; - UIImage *image; - if (isImageGIF) - { - image = [UIImage sd_animatedGIFWithData:self.imageData]; - } - else - { - image = [[UIImage alloc] initWithData:self.imageData]; - } + UIImage *image = [UIImage sd_imageWithData:self.imageData]; image = [self scaledImageForKey:self.request.URL.absoluteString image:image]; - if (!isImageGIF) { + if (!image.images) // Do not force decod animated GIFs + { image = [UIImage decodedImageWithImage:image]; } diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 068fa61e..ebe945dc 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -156,12 +156,12 @@ { // Image refresh hit the NSURLCache cache, do not call the completion block } - else if (downloadedImage && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) + // NOTE: We don't call transformDownloadedImage delegate method on animated images as most transformation code would mangle it + else if (downloadedImage && !downloadedImage.images && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ - { - BOOL isImageGIF = [data sd_isGIF]; - UIImage *transformedImage = isImageGIF ? downloadedImage : [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url]; + { + UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url]; dispatch_async(dispatch_get_main_queue(), ^ { diff --git a/SDWebImage/UIImage+GIF.m b/SDWebImage/UIImage+GIF.m index fd1d8e43..d19fa412 100755 --- a/SDWebImage/UIImage+GIF.m +++ b/SDWebImage/UIImage+GIF.m @@ -21,30 +21,42 @@ CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); size_t count = CGImageSourceGetCount(source); - NSMutableArray *images = [NSMutableArray array]; - - NSTimeInterval duration = 0.0f; - - for (size_t i = 0; i < count; i++) + + UIImage *animatedImage; + + if (count <= 1) { - CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL); - - NSDictionary *frameProperties = CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(source, i, NULL)); - duration += [[[frameProperties objectForKey:(NSString*)kCGImagePropertyGIFDictionary] objectForKey:(NSString*)kCGImagePropertyGIFDelayTime] doubleValue]; - - [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]]; - - CGImageRelease(image); + animatedImage = [[UIImage alloc] initWithData:data]; } - + else + { + NSMutableArray *images = [NSMutableArray array]; + + NSTimeInterval duration = 0.0f; + + for (size_t i = 0; i < count; i++) + { + CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL); + + NSDictionary *frameProperties = CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(source, i, NULL)); + duration += [[[frameProperties objectForKey:(NSString*)kCGImagePropertyGIFDictionary] objectForKey:(NSString*)kCGImagePropertyGIFDelayTime] doubleValue]; + + [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]]; + + CGImageRelease(image); + } + + if (!duration) + { + duration = (1.0f/10.0f)*count; + } + + animatedImage = [UIImage animatedImageWithImages:images duration:duration]; + } + CFRelease(source); - - if (!duration) - { - duration = (1.0f/10.0f)*count; - } - - return [UIImage animatedImageWithImages:images duration:duration]; + + return animatedImage; } + (UIImage *)sd_animatedGIFNamed:(NSString *)name diff --git a/SDWebImage/UIImage+MultiFormat.h b/SDWebImage/UIImage+MultiFormat.h new file mode 100644 index 00000000..186ebc0a --- /dev/null +++ b/SDWebImage/UIImage+MultiFormat.h @@ -0,0 +1,15 @@ +// +// UIImage+MultiFormat.h +// SDWebImage +// +// Created by Olivier Poitrey on 07/06/13. +// Copyright (c) 2013 Dailymotion. All rights reserved. +// + +#import + +@interface UIImage (MultiFormat) + ++ (UIImage *)sd_imageWithData:(NSData *)data; + +@end diff --git a/SDWebImage/UIImage+MultiFormat.m b/SDWebImage/UIImage+MultiFormat.m new file mode 100644 index 00000000..1863f1c1 --- /dev/null +++ b/SDWebImage/UIImage+MultiFormat.m @@ -0,0 +1,30 @@ +// +// UIImage+MultiFormat.m +// SDWebImage +// +// Created by Olivier Poitrey on 07/06/13. +// Copyright (c) 2013 Dailymotion. All rights reserved. +// + +#import "UIImage+MultiFormat.h" +#import "UIImage+GIF.h" + +@implementation UIImage (MultiFormat) + ++ (UIImage *)sd_imageWithData:(NSData *)data +{ + UIImage *image; + + if ([data sd_isGIF]) + { + image = [UIImage sd_animatedGIFWithData:data]; + } + else + { + image = [[UIImage alloc] initWithData:data]; + } + + return image; +} + +@end