diff --git a/.gitmodules b/.gitmodules index ce6396d4..d8c3ae83 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "Vendors/libwebp"] path = Vendors/libwebp url = https://github.com/webmproject/libwebp +[submodule "Vendors/FLAnimatedImage"] + path = Vendors/FLAnimatedImage + url = https://github.com/Flipboard/FLAnimatedImage diff --git a/Examples/SDWebImage Demo/DetailViewController.h b/Examples/SDWebImage Demo/DetailViewController.h index 77d3897e..d0e6588d 100644 --- a/Examples/SDWebImage Demo/DetailViewController.h +++ b/Examples/SDWebImage Demo/DetailViewController.h @@ -12,6 +12,4 @@ @property (strong, nonatomic) NSURL *imageURL; -@property (strong, nonatomic) IBOutlet UIImageView *imageView; - @end diff --git a/Examples/SDWebImage Demo/DetailViewController.m b/Examples/SDWebImage Demo/DetailViewController.m index 899f12de..c9df0745 100644 --- a/Examples/SDWebImage Demo/DetailViewController.m +++ b/Examples/SDWebImage Demo/DetailViewController.m @@ -8,9 +8,14 @@ #import "DetailViewController.h" #import +#import @interface DetailViewController () + +@property (strong, nonatomic) IBOutlet FLAnimatedImageView *imageView; + - (void)configureView; + @end @implementation DetailViewController diff --git a/Examples/SDWebImage Demo/MasterViewController.m b/Examples/SDWebImage Demo/MasterViewController.m index 42942932..57327de6 100644 --- a/Examples/SDWebImage Demo/MasterViewController.m +++ b/Examples/SDWebImage Demo/MasterViewController.m @@ -9,6 +9,36 @@ #import "MasterViewController.h" #import #import "DetailViewController.h" +#import +#import + + +@interface MyCustomTableViewCell : UITableViewCell + +@property (nonatomic, strong) UILabel *customTextLabel; +@property (nonatomic, strong) FLAnimatedImageView *customImageView; + +@end + + +@implementation MyCustomTableViewCell + +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { + _customImageView = [[FLAnimatedImageView alloc] initWithFrame:CGRectMake(20.0, 2.0, 60.0, 40.0)]; + [self.contentView addSubview:_customImageView]; + _customTextLabel = [[UILabel alloc] initWithFrame:CGRectMake(100.0, 12.0, 200, 20.0)]; + [self.contentView addSubview:_customTextLabel]; + + _customImageView.clipsToBounds = YES; + _customImageView.contentMode = UIViewContentModeScaleAspectFill; + } + return self; +} + +@end + + @interface MasterViewController () { NSMutableArray *_objects; @@ -38,6 +68,7 @@ _objects = [NSMutableArray arrayWithObjects: @"http://www.httpwatch.com/httpgallery/authentication/authenticatedimage/default.aspx?0.35786508303135633", // requires HTTP auth, used to demo the NTLM auth @"http://assets.sbnation.com/assets/2512203/dogflops.gif", + @"https://raw.githubusercontent.com/liyong03/YLGIFImage/master/YLGIFImageDemo/YLGIFImageDemo/joy.gif", @"http://www.ioncannon.net/wp-content/uploads/2011/06/test2.webp", @"http://www.ioncannon.net/wp-content/uploads/2011/06/test9.webp", nil]; @@ -79,19 +110,23 @@ { static NSString *CellIdentifier = @"Cell"; - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; - if (cell == nil) - { - cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; + static UIImage *placeholderImage = nil; + if (!placeholderImage) { + placeholderImage = [UIImage imageNamed:@"placeholder"]; + } + + MyCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + if (cell == nil) { + cell = [[MyCustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } - [cell.imageView setShowActivityIndicatorView:YES]; - [cell.imageView setIndicatorStyle:UIActivityIndicatorViewStyleGray]; - - cell.textLabel.text = [NSString stringWithFormat:@"Image #%ld", (long)indexPath.row]; - cell.imageView.contentMode = UIViewContentModeScaleAspectFill; - [cell.imageView sd_setImageWithURL:[NSURL URLWithString:_objects[indexPath.row]] - placeholderImage:[UIImage imageNamed:@"placeholder"] options:indexPath.row == 0 ? SDWebImageRefreshCached : 0]; + [cell.customImageView setShowActivityIndicatorView:YES]; + [cell.customImageView setIndicatorStyle:UIActivityIndicatorViewStyleGray]; + + cell.customTextLabel.text = [NSString stringWithFormat:@"Image #%ld", (long)indexPath.row]; + [cell.customImageView sd_setImageWithURL:[NSURL URLWithString:_objects[indexPath.row]] + placeholderImage:placeholderImage + options:indexPath.row == 0 ? SDWebImageRefreshCached : 0]; return cell; } diff --git a/Examples/SDWebImage Demo/en.lproj/DetailViewController.xib b/Examples/SDWebImage Demo/en.lproj/DetailViewController.xib index ccce9b18..c3e3aad5 100644 --- a/Examples/SDWebImage Demo/en.lproj/DetailViewController.xib +++ b/Examples/SDWebImage Demo/en.lproj/DetailViewController.xib @@ -1,164 +1,28 @@ - - - - 1296 - 11D50b - 2182 - 1138.32 - 568.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1181 - - - IBProxyObject - IBUIView - IBUIImageView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - - - - 274 - {320, 460} - - - _NS:9 - 1 - NO - IBCocoaTouchFramework - - - {{0, 20}, {320, 460}} - - - - 3 - MQA - - 2 - - - - IBCocoaTouchFramework - - - - - - - view - - - - 3 - - - - imageView - - - - 8 - - - - - - 0 - - - - - - 1 - - - - - - - - -1 - - - File's Owner - - - -2 - - - - - 7 - - - - - - - DetailViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 8 - - - - - DetailViewController - UIViewController - - imageView - UIImageView - - - imageView - - imageView - UIImageView - - - - IBProjectSource - ./Classes/DetailViewController.h - - - - - 0 - IBCocoaTouchFramework - - com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS - - - YES - 3 - 1181 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/SDWebImage Demo/en.lproj/MasterViewController.xib b/Examples/SDWebImage Demo/en.lproj/MasterViewController.xib index 729e0153..13abc1c6 100644 --- a/Examples/SDWebImage Demo/en.lproj/MasterViewController.xib +++ b/Examples/SDWebImage Demo/en.lproj/MasterViewController.xib @@ -1,139 +1,25 @@ - - - - 1280 - 11C25 - 1919 - 1138.11 - 566.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 916 - - - IBProxyObject - IBUITableView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - {{0, 20}, {320, 460}} - - - - 3 - MQA - - YES - - IBCocoaTouchFramework - YES - 1 - 0 - YES - 44 - 22 - 22 - - - - - - - view - - - - 3 - - - - dataSource - - - - 4 - - - - delegate - - - - 5 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 2 - - - - - - - MasterViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 5 - - - - - MasterViewController - UITableViewController - - IBProjectSource - ./Classes/MasterViewController.h - - - - - 0 - IBCocoaTouchFramework - YES - 3 - 916 - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SDWebImage.podspec b/SDWebImage.podspec index 73facd4b..5f64d5ad 100644 --- a/SDWebImage.podspec +++ b/SDWebImage.podspec @@ -35,6 +35,16 @@ Pod::Spec.new do |s| mk.dependency 'SDWebImage/Core' end + s.subspec 'GIF' do |gif| + gif.ios.deployment_target = '6.0' + gif.source_files = 'SDWebImage/FLAnimatedImage/*.{h,m}' + gif.dependency 'SDWebImage/Core' + gif.dependency 'FLAnimatedImage', '~> 1.0' + gif.xcconfig = { + 'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/FLAnimatedImage/FLAnimatedImage' + } + end + s.subspec 'WebP' do |webp| webp.source_files = 'SDWebImage/UIImage+WebP.{h,m}' webp.xcconfig = { diff --git a/SDWebImage.xcodeproj/project.pbxproj b/SDWebImage.xcodeproj/project.pbxproj index e30fc04e..477ddd7d 100644 --- a/SDWebImage.xcodeproj/project.pbxproj +++ b/SDWebImage.xcodeproj/project.pbxproj @@ -271,6 +271,24 @@ 438096731CDFC08F00DC626B /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 535699B515113E7300A4C397 /* MKAnnotationView+WebCache.m */; }; 438096741CDFC09C00DC626B /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 53EDFB911762547C00698166 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; 438096751CDFC0A100DC626B /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 53EDFB921762547C00698166 /* UIImage+WebP.m */; }; + 43CE75761CFE9427006C64D0 /* FLAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43CE75771CFE9427006C64D0 /* FLAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43CE75781CFE9427006C64D0 /* FLAnimatedImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43CE75791CFE9427006C64D0 /* FLAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE754A1CFE9427006C64D0 /* FLAnimatedImage.m */; }; + 43CE757A1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE754A1CFE9427006C64D0 /* FLAnimatedImage.m */; }; + 43CE757B1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE754A1CFE9427006C64D0 /* FLAnimatedImage.m */; }; + 43CE757C1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE754B1CFE9427006C64D0 /* FLAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43CE757D1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE754B1CFE9427006C64D0 /* FLAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43CE757E1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE754B1CFE9427006C64D0 /* FLAnimatedImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43CE757F1CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE754C1CFE9427006C64D0 /* FLAnimatedImageView.m */; }; + 43CE75801CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE754C1CFE9427006C64D0 /* FLAnimatedImageView.m */; }; + 43CE75811CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE754C1CFE9427006C64D0 /* FLAnimatedImageView.m */; }; + 43CE75D01CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75CE1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43CE75D11CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75CE1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43CE75D21CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CE75CE1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 43CE75D31CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE75CF1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m */; }; + 43CE75D41CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE75CF1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m */; }; + 43CE75D51CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 43CE75CF1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m */; }; 4A2CAE041AB4BB5400B6BC39 /* SDWebImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A2CAE181AB4BB6400B6BC39 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 53922D88148C56230056699D /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A2CAE191AB4BB6400B6BC39 /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = 5340674F167780C40042B59E /* SDWebImageCompat.m */; }; @@ -341,6 +359,12 @@ /* Begin PBXFileReference section */ 00733A4C1BC487C000A5A117 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLAnimatedImage.h; sourceTree = ""; }; + 43CE754A1CFE9427006C64D0 /* FLAnimatedImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLAnimatedImage.m; sourceTree = ""; }; + 43CE754B1CFE9427006C64D0 /* FLAnimatedImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FLAnimatedImageView.h; sourceTree = ""; }; + 43CE754C1CFE9427006C64D0 /* FLAnimatedImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLAnimatedImageView.m; sourceTree = ""; }; + 43CE75CE1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FLAnimatedImageView+WebCache.h"; sourceTree = ""; }; + 43CE75CF1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "FLAnimatedImageView+WebCache.m"; sourceTree = ""; }; 4A2CADFF1AB4BB5300B6BC39 /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4A2CAE021AB4BB5400B6BC39 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4A2CAE031AB4BB5400B6BC39 /* SDWebImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDWebImage.h; sourceTree = ""; }; @@ -487,6 +511,35 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 43CE75451CFE9427006C64D0 /* FLAnimatedImage */ = { + isa = PBXGroup; + children = ( + 43CE75481CFE9427006C64D0 /* FLAnimatedImage */, + ); + name = FLAnimatedImage; + path = Vendors/FLAnimatedImage; + sourceTree = ""; + }; + 43CE75481CFE9427006C64D0 /* FLAnimatedImage */ = { + isa = PBXGroup; + children = ( + 43CE75491CFE9427006C64D0 /* FLAnimatedImage.h */, + 43CE754A1CFE9427006C64D0 /* FLAnimatedImage.m */, + 43CE754B1CFE9427006C64D0 /* FLAnimatedImageView.h */, + 43CE754C1CFE9427006C64D0 /* FLAnimatedImageView.m */, + ); + path = FLAnimatedImage; + sourceTree = ""; + }; + 43CE75CD1CFE98B3006C64D0 /* FLAnimatedImage */ = { + isa = PBXGroup; + children = ( + 43CE75CE1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h */, + 43CE75CF1CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m */, + ); + path = FLAnimatedImage; + sourceTree = ""; + }; 4A2CAE001AB4BB5300B6BC39 /* WebImage */ = { isa = PBXGroup; children = ( @@ -528,6 +581,7 @@ 53922D71148C55820056699D /* Frameworks */ = { isa = PBXGroup; children = ( + 43CE75451CFE9427006C64D0 /* FLAnimatedImage */, DA577C121998E60B007367ED /* libwebp */, 53FB893F14D35D1A0020B787 /* CoreGraphics.framework */, 53922D72148C55820056699D /* Foundation.framework */, @@ -546,6 +600,7 @@ 53922DAA148C56470056699D /* Cache */, 53922DAC148C56DD0056699D /* Utils */, 53922DA9148C562D0056699D /* Categories */, + 43CE75CD1CFE98B3006C64D0 /* FLAnimatedImage */, ); path = SDWebImage; sourceTree = ""; @@ -758,6 +813,7 @@ 00733A6C1BC4880E00A5A117 /* UIButton+WebCache.h in Headers */, 431738DF1CDFC8A40008FEB9 /* vp8li.h in Headers */, 4317395B1CDFC8B70008FEB9 /* types.h in Headers */, + 43CE75D21CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */, 431739551CDFC8B70008FEB9 /* decode.h in Headers */, 00733A731BC4880E00A5A117 /* SDWebImage.h in Headers */, 00733A701BC4880E00A5A117 /* UIImageView+HighlightedWebCache.h in Headers */, @@ -778,8 +834,10 @@ 431738D41CDFC8A40008FEB9 /* alphai.h in Headers */, 431739581CDFC8B70008FEB9 /* format_constants.h in Headers */, 431739491CDFC8B20008FEB9 /* rescaler.h in Headers */, + 43CE75781CFE9427006C64D0 /* FLAnimatedImage.h in Headers */, 431739161CDFC8AA0008FEB9 /* yuv.h in Headers */, 00733A6E1BC4880E00A5A117 /* UIImage+MultiFormat.h in Headers */, + 43CE757E1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, 431738DD1CDFC8A40008FEB9 /* vp8i.h in Headers */, 00733A6D1BC4880E00A5A117 /* UIImage+GIF.h in Headers */, 00733A651BC4880E00A5A117 /* SDWebImageDownloader.h in Headers */, @@ -796,6 +854,7 @@ files = ( 4317394F1CDFC8B70008FEB9 /* demux.h in Headers */, 431739211CDFC8B20008FEB9 /* endian_inl.h in Headers */, + 43CE757D1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, 431739541CDFC8B70008FEB9 /* types.h in Headers */, 431738F51CDFC8AA0008FEB9 /* neon.h in Headers */, 431738C51CDFC8A30008FEB9 /* alphai.h in Headers */, @@ -809,6 +868,7 @@ 4317392F1CDFC8B20008FEB9 /* rescaler.h in Headers */, 4A2CAE181AB4BB6400B6BC39 /* SDWebImageCompat.h in Headers */, 4317391B1CDFC8B20008FEB9 /* bit_reader.h in Headers */, + 43CE75D11CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */, 4A2CAE331AB4BB7500B6BC39 /* UIImageView+HighlightedWebCache.h in Headers */, 431739521CDFC8B70008FEB9 /* mux.h in Headers */, 431738F11CDFC8AA0008FEB9 /* lossless.h in Headers */, @@ -821,6 +881,7 @@ 431739291CDFC8B20008FEB9 /* quant_levels.h in Headers */, 4317391C1CDFC8B20008FEB9 /* bit_reader_inl.h in Headers */, 4317392B1CDFC8B20008FEB9 /* quant_levels_dec.h in Headers */, + 43CE75771CFE9427006C64D0 /* FLAnimatedImage.h in Headers */, 4A2CAE2B1AB4BB7500B6BC39 /* UIButton+WebCache.h in Headers */, 4A2CAE251AB4BB7000B6BC39 /* SDWebImagePrefetcher.h in Headers */, 4A2CAE371AB4BB7500B6BC39 /* UIView+WebCacheOperation.h in Headers */, @@ -869,6 +930,7 @@ 53761318155AD0D5005750A4 /* SDWebImageCompat.h in Headers */, 431738841CDFC2580008FEB9 /* vp8li.h in Headers */, 431738C31CDFC2660008FEB9 /* types.h in Headers */, + 43CE75D01CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.h in Headers */, 431738BD1CDFC2660008FEB9 /* decode.h in Headers */, 53761319155AD0D5005750A4 /* SDWebImageDecoder.h in Headers */, 5376131A155AD0D5005750A4 /* SDWebImageDownloader.h in Headers */, @@ -889,8 +951,10 @@ 431738791CDFC2580008FEB9 /* alphai.h in Headers */, 431738C01CDFC2660008FEB9 /* format_constants.h in Headers */, 431738B81CDFC2630008FEB9 /* rescaler.h in Headers */, + 43CE75761CFE9427006C64D0 /* FLAnimatedImage.h in Headers */, 4317389F1CDFC25E0008FEB9 /* yuv.h in Headers */, 438096721CDFC08200DC626B /* MKAnnotationView+WebCache.h in Headers */, + 43CE757C1CFE9427006C64D0 /* FLAnimatedImageView.h in Headers */, 431738821CDFC2580008FEB9 /* vp8i.h in Headers */, AB615303192DA24600A2D8E9 /* UIView+WebCacheOperation.h in Headers */, A18A6CC7172DC28500419892 /* UIImage+GIF.h in Headers */, @@ -1038,6 +1102,7 @@ 431739391CDFC8B20008FEB9 /* color_cache.c in Sources */, 00733A5A1BC4880000A5A117 /* SDWebImagePrefetcher.m in Sources */, 431739031CDFC8AA0008FEB9 /* dec_mips32.c in Sources */, + 43CE75D51CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */, 4317390B1CDFC8AA0008FEB9 /* enc_sse2.c in Sources */, 00733A5B1BC4880000A5A117 /* NSData+ImageContentType.m in Sources */, 431739131CDFC8AA0008FEB9 /* upsampling_neon.c in Sources */, @@ -1074,6 +1139,7 @@ 4317393C1CDFC8B20008FEB9 /* filters.c in Sources */, 431738DA1CDFC8A40008FEB9 /* quant.c in Sources */, 00733A591BC4880000A5A117 /* SDWebImageDecoder.m in Sources */, + 43CE75811CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */, 00733A5F1BC4880000A5A117 /* UIImage+WebP.m in Sources */, 431739041CDFC8AA0008FEB9 /* dec_neon.c in Sources */, 431739441CDFC8B20008FEB9 /* quant_levels_dec.c in Sources */, @@ -1083,6 +1149,7 @@ 431739141CDFC8AA0008FEB9 /* upsampling_sse2.c in Sources */, 00733A5D1BC4880000A5A117 /* UIImage+GIF.m in Sources */, 431738DC1CDFC8A40008FEB9 /* vp8.c in Sources */, + 43CE757B1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 00733A571BC4880000A5A117 /* SDImageCache.m in Sources */, 4317394A1CDFC8B20008FEB9 /* thread.c in Sources */, 431739051CDFC8AA0008FEB9 /* dec_sse2.c in Sources */, @@ -1109,6 +1176,7 @@ 4A2CAE2E1AB4BB7500B6BC39 /* UIImage+GIF.m in Sources */, 4A2CAE321AB4BB7500B6BC39 /* UIImage+WebP.m in Sources */, 431738EC1CDFC8AA0008FEB9 /* enc_avx2.c in Sources */, + 43CE75D41CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */, 4317392E1CDFC8B20008FEB9 /* rescaler.c in Sources */, 431738E91CDFC8AA0008FEB9 /* dec_sse2.c in Sources */, 431738F71CDFC8AA0008FEB9 /* upsampling_neon.c in Sources */, @@ -1118,6 +1186,7 @@ 431738F41CDFC8AA0008FEB9 /* lossless_sse2.c in Sources */, 431738EF1CDFC8AA0008FEB9 /* enc_sse2.c in Sources */, 431739301CDFC8B20008FEB9 /* thread.c in Sources */, + 43CE757A1CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 4A2CAE361AB4BB7500B6BC39 /* UIImageView+WebCache.m in Sources */, 431739221CDFC8B20008FEB9 /* filters.c in Sources */, 431738FB1CDFC8AA0008FEB9 /* yuv_mips32.c in Sources */, @@ -1155,6 +1224,7 @@ 4A2CAE341AB4BB7500B6BC39 /* UIImageView+HighlightedWebCache.m in Sources */, 431738F81CDFC8AA0008FEB9 /* upsampling_sse2.c in Sources */, 4A2CAE201AB4BB6C00B6BC39 /* SDImageCache.m in Sources */, + 43CE75801CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */, 431738C81CDFC8A30008FEB9 /* frame.c in Sources */, 4317391A1CDFC8B20008FEB9 /* bit_reader.c in Sources */, 431738E81CDFC8AA0008FEB9 /* dec_neon.c in Sources */, @@ -1177,6 +1247,7 @@ 53761309155AD0D5005750A4 /* SDImageCache.m in Sources */, 5376130A155AD0D5005750A4 /* SDWebImageDecoder.m in Sources */, 431738911CDFC25E0008FEB9 /* enc_avx2.c in Sources */, + 43CE75D31CFE98E0006C64D0 /* FLAnimatedImageView+WebCache.m in Sources */, 431738B71CDFC2630008FEB9 /* rescaler.c in Sources */, 4317388E1CDFC25E0008FEB9 /* dec_sse2.c in Sources */, 4317389C1CDFC25E0008FEB9 /* upsampling_neon.c in Sources */, @@ -1186,6 +1257,7 @@ 431738991CDFC25E0008FEB9 /* lossless_sse2.c in Sources */, 431738941CDFC25E0008FEB9 /* enc_sse2.c in Sources */, 431738B91CDFC2630008FEB9 /* thread.c in Sources */, + 43CE75791CFE9427006C64D0 /* FLAnimatedImage.m in Sources */, 5376130B155AD0D5005750A4 /* SDWebImageDownloader.m in Sources */, 431738AB1CDFC2630008FEB9 /* filters.c in Sources */, 431738A01CDFC25E0008FEB9 /* yuv_mips32.c in Sources */, @@ -1223,6 +1295,7 @@ 53EDFB8C17623F7C00698166 /* UIImage+MultiFormat.m in Sources */, 4317389D1CDFC25E0008FEB9 /* upsampling_sse2.c in Sources */, ABBE71A818C43B4D00B75E91 /* UIImageView+HighlightedWebCache.m in Sources */, + 43CE757F1CFE9427006C64D0 /* FLAnimatedImageView.m in Sources */, 4317387C1CDFC2580008FEB9 /* frame.c in Sources */, 431738A31CDFC2630008FEB9 /* bit_reader.c in Sources */, 4317388D1CDFC25E0008FEB9 /* dec_neon.c in Sources */, diff --git a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.h b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.h new file mode 100644 index 00000000..acd4a8a6 --- /dev/null +++ b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.h @@ -0,0 +1,141 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + + +#if COCOAPODS + @import FLAnimatedImage; +#else + #import "FLAnimatedImageView.h" +#endif + +#import "SDWebImageManager.h" + + +/** + * A category for the FLAnimatedImage imageView class that hooks it to the SDWebImage system. + * Very similar to the base class category (UIImageView (WebCache)) + */ +@interface FLAnimatedImageView (WebCache) + +/** + * Get the current image URL. + * + * Note that because of the limitations of categories this property can get out of sync + * if you use setImage: directly. + */ +- (nullable NSURL *)sd_imageURL; + +/** + * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images + * The download is asynchronous and cached. + * + * @param url The url for the image. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url; + +/** + * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images + * The download is asynchronous and cached. + * Uses a placeholder until the request finishes. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder; + +/** + * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images + * The download is asynchronous and cached. + * Uses a placeholder until the request finishes. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options; + +/** + * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images + * The download is asynchronous and cached. + * Uses a placeholder until the request finishes. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images + * The download is asynchronous and cached. + * Uses a placeholder until the request finishes. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Load the image at the given url (either from cache or download) and load it in this imageView. It works with both static and dynamic images + * The download is asynchronous and cached. + * Uses a placeholder until the request finishes. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param progressBlock A block called while image is downloading + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Cancel the image load + */ +- (void)sd_cancelCurrentImageLoad; + +@end diff --git a/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m new file mode 100644 index 00000000..145ef5f2 --- /dev/null +++ b/SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m @@ -0,0 +1,119 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + + +#import "FLAnimatedImageView+WebCache.h" +#import "objc/runtime.h" +#import "UIView+WebCacheOperation.h" +#import "NSData+ImageContentType.h" +#import "FLAnimatedImage.h" +#import "UIImageView+WebCache.h" + +static char imageURLKey; + + +@implementation FLAnimatedImageView (WebCache) + +- (nullable NSURL *)sd_imageURL { + return objc_getAssociatedObject(self, &imageURLKey); +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url { + [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder { + [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_cancelCurrentImageLoad]; + objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + if (!(options & SDWebImageDelayPlaceholder)) { + dispatch_main_async_safe(^{ + self.image = placeholder; + }); + } + + if (url) { + // check if activityView is enabled or not + if ([self showActivityIndicatorView]) { + [self addActivityIndicator]; + } + + __weak __typeof(self)wself = self; + id operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + if (!wself) return; + dispatch_main_sync_safe(^{ + [wself removeActivityIndicator]; + + if (!wself) return; + if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) { + completedBlock(image, error, cacheType, url); + return; + } else if (image) { + NSString *imageContentType = [NSData sd_contentTypeForImageData:data]; + if ([imageContentType isEqualToString:@"image/gif"]) { + wself.animatedImage = [FLAnimatedImage animatedImageWithGIFData:data]; + wself.image = nil; + } else { + wself.image = image; + wself.animatedImage = nil; + } + [wself setNeedsLayout]; + } else { + if ((options & SDWebImageDelayPlaceholder)) { + wself.image = placeholder; + [wself setNeedsLayout]; + } + } + if (completedBlock && finished) { + completedBlock(image, error, cacheType, url); + } + }); + }]; + [self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"]; + } else { + dispatch_main_async_safe(^{ + [self removeActivityIndicator]; + + if (completedBlock) { + NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; + completedBlock(nil, error, SDImageCacheTypeNone, url); + } + }); + } +} + +- (void)sd_cancelCurrentImageLoad { + [self sd_cancelImageLoadOperationWithKey:@"UIImageViewImageLoad"]; +} + + +@end diff --git a/SDWebImage/MKAnnotationView+WebCache.h b/SDWebImage/MKAnnotationView+WebCache.h index fb03b0a9..5744ffd8 100644 --- a/SDWebImage/MKAnnotationView+WebCache.h +++ b/SDWebImage/MKAnnotationView+WebCache.h @@ -18,7 +18,7 @@ * Get the current image URL. * * Note that because of the limitations of categories this property can get out of sync - * if you use sd_setImage: directly. + * if you use setImage: directly. */ - (nullable NSURL *)sd_imageURL; @@ -70,7 +70,7 @@ * The fourth parameter is the original image url. */ - (void)sd_setImageWithURL:(nullable NSURL *)url - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url`, placeholder. @@ -87,7 +87,7 @@ */ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url`, placeholder and custom options. @@ -106,7 +106,7 @@ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Cancel the current download diff --git a/SDWebImage/MKAnnotationView+WebCache.m b/SDWebImage/MKAnnotationView+WebCache.m index 14ee55b8..9b69fb5b 100644 --- a/SDWebImage/MKAnnotationView+WebCache.m +++ b/SDWebImage/MKAnnotationView+WebCache.m @@ -30,18 +30,18 @@ static char imageURLKey; [self sd_setImageWithURL:url placeholderImage:placeholder options:options completed:nil]; } -- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDWebImageCompletionBlock)completedBlock { +- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:nil options:0 completed:completedBlock]; } -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDWebImageCompletionBlock)completedBlock { +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:placeholder options:0 completed:completedBlock]; } - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - completed:(nullable SDWebImageCompletionBlock)completedBlock { + completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_cancelCurrentImageLoad]; objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); @@ -49,7 +49,7 @@ static char imageURLKey; if (url) { __weak __typeof(self)wself = self; - id operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + id operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { if (!wself) return; dispatch_main_sync_safe(^{ __strong MKAnnotationView *sself = wself; diff --git a/SDWebImage/SDImageCache.h b/SDWebImage/SDImageCache.h index 02441614..a470ef8d 100644 --- a/SDWebImage/SDImageCache.h +++ b/SDWebImage/SDImageCache.h @@ -24,7 +24,7 @@ typedef NS_ENUM(NSInteger, SDImageCacheType) { SDImageCacheTypeMemory }; -typedef void(^SDWebImageQueryCompletedBlock)(UIImage * _Nullable image, SDImageCacheType cacheType); +typedef void(^SDCacheQueryCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType); typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache); @@ -148,7 +148,7 @@ typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger tot * * @param key The unique key used to store the wanted image */ -- (nullable NSOperation *)queryDiskCacheForKey:(nullable NSString *)key done:(nullable SDWebImageQueryCompletedBlock)doneBlock; +- (nullable NSOperation *)queryDiskCacheForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock; /** * Query the memory cache synchronously. diff --git a/SDWebImage/SDImageCache.m b/SDWebImage/SDImageCache.m index 8087ee0c..f49e3819 100644 --- a/SDWebImage/SDImageCache.m +++ b/SDWebImage/SDImageCache.m @@ -10,6 +10,7 @@ #import "SDWebImageDecoder.h" #import "UIImage+MultiFormat.h" #import +#import "UIImage+GIF.h" // See https://github.com/rs/SDWebImage/pull/1141 for discussion @interface AutoPurgeCache : NSCache @@ -384,20 +385,24 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { return SDScaledImageForKey(key, image); } -- (nullable NSOperation *)queryDiskCacheForKey:(nullable NSString *)key done:(nullable SDWebImageQueryCompletedBlock)doneBlock { +- (nullable NSOperation *)queryDiskCacheForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock { if (!doneBlock) { return nil; } if (!key) { - doneBlock(nil, SDImageCacheTypeNone); + doneBlock(nil, nil, SDImageCacheTypeNone); return nil; } // First check the in-memory cache... UIImage *image = [self imageFromMemoryCacheForKey:key]; if (image) { - doneBlock(image, SDImageCacheTypeMemory); + NSData *diskData = nil; + if ([image isGIF]) { + diskData = [self diskImageDataBySearchingAllPathsForKey:key]; + } + doneBlock(image, diskData, SDImageCacheTypeMemory); return nil; } @@ -408,6 +413,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } @autoreleasepool { + NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key]; UIImage *diskImage = [self diskImageForKey:key]; if (diskImage && self.shouldCacheImagesInMemory) { NSUInteger cost = SDCacheCostForImage(diskImage); @@ -415,7 +421,7 @@ FOUNDATION_STATIC_INLINE NSUInteger SDCacheCostForImage(UIImage *image) { } dispatch_async(dispatch_get_main_queue(), ^{ - doneBlock(diskImage, SDImageCacheTypeDisk); + doneBlock(diskImage, diskData, SDImageCacheTypeDisk); }); } }); diff --git a/SDWebImage/SDWebImageManager.h b/SDWebImage/SDWebImageManager.h index 84d4fabe..19b45d6c 100644 --- a/SDWebImage/SDWebImageManager.h +++ b/SDWebImage/SDWebImageManager.h @@ -90,9 +90,9 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { SDWebImageAvoidAutoSetImage = 1 << 11 }; -typedef void(^SDWebImageCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL); +typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL); -typedef void(^SDWebImageCompletionWithFinishedBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL); +typedef void(^SDInternalCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL); typedef NSString * _Nullable (^SDWebImageCacheKeyFilterBlock)(NSURL * _Nullable url); @@ -197,22 +197,24 @@ SDWebImageManager *manager = [SDWebImageManager sharedManager]; * * This parameter is required. * - * This block has no return value and takes the requested UIImage as first parameter. - * In case of error the image parameter is nil and the second parameter may contain an NSError. + * This block has no return value and takes the requested UIImage as first parameter and the NSData representation as second parameter. + * In case of error the image parameter is nil and the third parameter may contain an NSError. * - * The third parameter is an `SDImageCacheType` enum indicating if the image was retrieved from the local cache + * The forth parameter is an `SDImageCacheType` enum indicating if the image was retrieved from the local cache * or from the memory cache or from the network. * - * The last parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is + * The fith parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is * downloading. This block is thus called repeatedly with a partial image. When image is fully downloaded, the * block is called a last time with the full image and the last parameter set to YES. * + * The last parameter is the original image URL + * * @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation */ - (nullable id )loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDWebImageCompletionWithFinishedBlock)completedBlock; + completed:(nullable SDInternalCompletionBlock)completedBlock; /** * Saves image to cache for given URL diff --git a/SDWebImage/SDWebImageManager.m b/SDWebImage/SDWebImageManager.m index 9e283e82..1f8f00ab 100644 --- a/SDWebImage/SDWebImageManager.m +++ b/SDWebImage/SDWebImageManager.m @@ -115,7 +115,7 @@ - (id )loadImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDWebImageCompletionWithFinishedBlock)completedBlock { + completed:(nullable SDInternalCompletionBlock)completedBlock { // Invoking this method without a completedBlock is pointless NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead"); @@ -143,7 +143,7 @@ if (url.absoluteString.length == 0 || (!(options & SDWebImageRetryFailed) && isFailedUrl)) { dispatch_main_sync_safe(^{ NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil]; - completedBlock(nil, error, SDImageCacheTypeNone, YES, url); + completedBlock(nil, nil, error, SDImageCacheTypeNone, YES, url); }); return operation; } @@ -153,7 +153,7 @@ } NSString *key = [self cacheKeyForURL:url]; - operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType) { + operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) { if (operation.isCancelled) { @synchronized (self.runningOperations) { [self.runningOperations removeObject:operation]; @@ -162,12 +162,12 @@ return; } - if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) { - if (image && options & SDWebImageRefreshCached) { + if ((!cachedImage || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url])) { + if (cachedImage && options & SDWebImageRefreshCached) { dispatch_main_sync_safe(^{ // If image was found in the cache but SDWebImageRefreshCached is provided, notify about the cached image // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server. - completedBlock(image, nil, cacheType, YES, url); + completedBlock(cachedImage, cachedData, nil, cacheType, YES, url); }); } @@ -180,23 +180,22 @@ if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies; if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates; if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority; - if (image && options & SDWebImageRefreshCached) { + if (cachedImage && options & SDWebImageRefreshCached) { // force progressive off if image already cached but forced refreshing downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload; // ignore image read from NSURLCache if image if cached but force refreshing downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse; } - id subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) { + id subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { __strong __typeof(weakOperation) strongOperation = weakOperation; if (!strongOperation || strongOperation.isCancelled) { // Do nothing if the operation was cancelled // See #699 for more details // if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data - } - else if (error) { + } else if (error) { dispatch_main_sync_safe(^{ if (strongOperation && !strongOperation.isCancelled) { - completedBlock(nil, error, SDImageCacheTypeNone, finished, url); + completedBlock(nil, nil, error, SDImageCacheTypeNone, finished, url); } }); @@ -221,33 +220,31 @@ BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly); - if (options & SDWebImageRefreshCached && image && !downloadedImage) { + if (options & SDWebImageRefreshCached && cachedImage && !downloadedImage) { // Image refresh hit the NSURLCache cache, do not call the completion block - } - else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) { + } else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url]; if (transformedImage && finished) { BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; - [self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:(imageWasTransformed ? nil : data) forKey:key toDisk:cacheOnDisk]; + [self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:(imageWasTransformed ? nil : downloadedData) forKey:key toDisk:cacheOnDisk]; } dispatch_main_sync_safe(^{ if (strongOperation && !strongOperation.isCancelled) { - completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url); + completedBlock(transformedImage, downloadedData, nil, SDImageCacheTypeNone, finished, url); } }); }); - } - else { + } else { if (downloadedImage && finished) { - [self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:data forKey:key toDisk:cacheOnDisk]; + [self.imageCache storeImage:downloadedImage recalculateFromImage:NO imageData:downloadedData forKey:key toDisk:cacheOnDisk]; } dispatch_main_sync_safe(^{ if (strongOperation && !strongOperation.isCancelled) { - completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished, url); + completedBlock(downloadedImage, downloadedData, nil, SDImageCacheTypeNone, finished, url); } }); } @@ -271,24 +268,22 @@ } } }; - } - else if (image) { + } else if (cachedImage) { dispatch_main_sync_safe(^{ __strong __typeof(weakOperation) strongOperation = weakOperation; if (strongOperation && !strongOperation.isCancelled) { - completedBlock(image, nil, cacheType, YES, url); + completedBlock(cachedImage, cachedData, nil, cacheType, YES, url); } }); @synchronized (self.runningOperations) { [self.runningOperations removeObject:operation]; } - } - else { + } else { // Image not in cache and download disallowed by delegate dispatch_main_sync_safe(^{ __strong __typeof(weakOperation) strongOperation = weakOperation; if (strongOperation && !weakOperation.isCancelled) { - completedBlock(nil, nil, SDImageCacheTypeNone, YES, url); + completedBlock(nil, nil, nil, SDImageCacheTypeNone, YES, url); } }); @synchronized (self.runningOperations) { diff --git a/SDWebImage/SDWebImagePrefetcher.m b/SDWebImage/SDWebImagePrefetcher.m index 596aefd3..c9cb06ef 100644 --- a/SDWebImage/SDWebImagePrefetcher.m +++ b/SDWebImage/SDWebImagePrefetcher.m @@ -57,7 +57,7 @@ - (void)startPrefetchingAtIndex:(NSUInteger)index { if (index >= self.prefetchURLs.count) return; self.requestedCount++; - [self.manager loadImageWithURL:self.prefetchURLs[index] options:self.options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + [self.manager loadImageWithURL:self.prefetchURLs[index] options:self.options progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { if (!finished) return; self.finishedCount++; diff --git a/SDWebImage/UIButton+WebCache.h b/SDWebImage/UIButton+WebCache.h index bad09d71..122c29dc 100644 --- a/SDWebImage/UIButton+WebCache.h +++ b/SDWebImage/UIButton+WebCache.h @@ -81,7 +81,7 @@ */ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url`, placeholder. @@ -100,7 +100,7 @@ - (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url`, placeholder and custom options. @@ -121,7 +121,7 @@ forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the backgroundImageView `image` with an `url`. @@ -178,7 +178,7 @@ */ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the backgroundImageView `image` with an `url`, placeholder. @@ -197,7 +197,7 @@ - (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the backgroundImageView `image` with an `url`, placeholder and custom options. @@ -217,7 +217,7 @@ forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Cancel the current image download diff --git a/SDWebImage/UIButton+WebCache.m b/SDWebImage/UIButton+WebCache.m index 329c24e9..84b9c5d2 100644 --- a/SDWebImage/UIButton+WebCache.m +++ b/SDWebImage/UIButton+WebCache.m @@ -42,11 +42,11 @@ typedef NSMutableDictionary SDStateImageURLDictionary; [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil]; } -- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDWebImageCompletionBlock)completedBlock { +- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url forState:state placeholderImage:nil options:0 completed:completedBlock]; } -- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDWebImageCompletionBlock)completedBlock { +- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock]; } @@ -54,8 +54,7 @@ typedef NSMutableDictionary SDStateImageURLDictionary; forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - completed:(nullable SDWebImageCompletionBlock)completedBlock { - + completed:(nullable SDExternalCompletionBlock)completedBlock { [self setImage:placeholder forState:state]; [self sd_cancelImageLoadForState:state]; @@ -75,7 +74,7 @@ typedef NSMutableDictionary SDStateImageURLDictionary; self.imageURLStorage[@(state)] = url; __weak __typeof(self)wself = self; - id operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + id operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { if (!wself) return; dispatch_main_sync_safe(^{ __strong UIButton *sself = wself; @@ -108,11 +107,11 @@ typedef NSMutableDictionary SDStateImageURLDictionary; [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil]; } -- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDWebImageCompletionBlock)completedBlock { +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:completedBlock]; } -- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDWebImageCompletionBlock)completedBlock { +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock]; } @@ -120,14 +119,14 @@ typedef NSMutableDictionary SDStateImageURLDictionary; forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - completed:(nullable SDWebImageCompletionBlock)completedBlock { + completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_cancelBackgroundImageLoadForState:state]; [self setBackgroundImage:placeholder forState:state]; if (url) { __weak __typeof(self)wself = self; - id operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + id operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { if (!wself) return; dispatch_main_sync_safe(^{ __strong UIButton *sself = wself; diff --git a/SDWebImage/UIImage+GIF.h b/SDWebImage/UIImage+GIF.h index 216d90e1..63cb856d 100755 --- a/SDWebImage/UIImage+GIF.h +++ b/SDWebImage/UIImage+GIF.h @@ -11,10 +11,14 @@ @interface UIImage (GIF) -+ (UIImage *)sd_animatedGIFNamed:(NSString *)name; - +/** + * Compatibility method - creates an animated UIImage from an NSData, it will only contain the 1st frame image + */ + (UIImage *)sd_animatedGIFWithData:(NSData *)data; -- (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size; +/** + * Checks if an UIImage instance is a GIF. Will use the `images` array + */ +- (BOOL)isGIF; @end diff --git a/SDWebImage/UIImage+GIF.m b/SDWebImage/UIImage+GIF.m index 3f236d77..37c5130b 100755 --- a/SDWebImage/UIImage+GIF.m +++ b/SDWebImage/UIImage+GIF.m @@ -9,6 +9,7 @@ #import "UIImage+GIF.h" #import +#import "objc/runtime.h" @implementation UIImage (GIF) @@ -21,142 +22,26 @@ size_t count = CGImageSourceGetCount(source); - UIImage *animatedImage; + UIImage *staticImage; if (count <= 1) { - 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); - if (!image) { - continue; - } - - duration += [self sd_frameDurationAtIndex:i source:source]; - - [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]; + staticImage = [[UIImage alloc] initWithData:data]; + } else { + // we will only retrieve the 1st frame. the full GIF support is available via the FLAnimatedImageView category. + // this here is only code to allow drawing animated images as static ones + CGImageRef CGImage = CGImageSourceCreateImageAtIndex(source, 0, NULL); + UIImage *frameImage = [UIImage imageWithCGImage:CGImage scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]; + staticImage = [UIImage animatedImageWithImages:@[frameImage] duration:0.0f]; + CGImageRelease(CGImage); } CFRelease(source); - return animatedImage; + return staticImage; } -+ (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source { - float frameDuration = 0.1f; - CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil); - NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties; - NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary]; - - NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime]; - if (delayTimeUnclampedProp) { - frameDuration = delayTimeUnclampedProp.floatValue; - } - else { - - NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime]; - if (delayTimeProp) { - frameDuration = delayTimeProp.floatValue; - } - } - - // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. - // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify - // a duration of <= 10 ms. See and - // for more information. - - if (frameDuration < 0.011f) { - frameDuration = 0.100f; - } - - CFRelease(cfFrameProperties); - return frameDuration; -} - -+ (UIImage *)sd_animatedGIFNamed:(NSString *)name { - CGFloat scale = [UIScreen mainScreen].scale; - - if (scale > 1.0f) { - NSString *retinaPath = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"gif"]; - - NSData *data = [NSData dataWithContentsOfFile:retinaPath]; - - if (data) { - return [UIImage sd_animatedGIFWithData:data]; - } - - NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; - - data = [NSData dataWithContentsOfFile:path]; - - if (data) { - return [UIImage sd_animatedGIFWithData:data]; - } - - return [UIImage imageNamed:name]; - } - else { - NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; - - NSData *data = [NSData dataWithContentsOfFile:path]; - - if (data) { - return [UIImage sd_animatedGIFWithData:data]; - } - - return [UIImage imageNamed:name]; - } -} - -- (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size { - if (CGSizeEqualToSize(self.size, size) || CGSizeEqualToSize(size, CGSizeZero)) { - return self; - } - - CGSize scaledSize = size; - CGPoint thumbnailPoint = CGPointZero; - - CGFloat widthFactor = size.width / self.size.width; - CGFloat heightFactor = size.height / self.size.height; - CGFloat scaleFactor = (widthFactor > heightFactor) ? widthFactor : heightFactor; - scaledSize.width = self.size.width * scaleFactor; - scaledSize.height = self.size.height * scaleFactor; - - if (widthFactor > heightFactor) { - thumbnailPoint.y = (size.height - scaledSize.height) * 0.5; - } - else if (widthFactor < heightFactor) { - thumbnailPoint.x = (size.width - scaledSize.width) * 0.5; - } - - NSMutableArray *scaledImages = [NSMutableArray array]; - - for (UIImage *image in self.images) { - UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); - - [image drawInRect:CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledSize.width, scaledSize.height)]; - UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); - - [scaledImages addObject:newImage]; - - UIGraphicsEndImageContext(); - } - - return [UIImage animatedImageWithImages:scaledImages duration:self.duration]; +- (BOOL)isGIF { + return (self.images != nil); } @end diff --git a/SDWebImage/UIImageView+HighlightedWebCache.h b/SDWebImage/UIImageView+HighlightedWebCache.h index dfbc1817..d97b4f04 100644 --- a/SDWebImage/UIImageView+HighlightedWebCache.h +++ b/SDWebImage/UIImageView+HighlightedWebCache.h @@ -48,7 +48,7 @@ * The fourth parameter is the original image url. */ - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `highlightedImage` with an `url` and custom options. @@ -65,7 +65,7 @@ */ - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `highlightedImage` with an `url` and custom options. @@ -84,7 +84,7 @@ - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Cancel the current download diff --git a/SDWebImage/UIImageView+HighlightedWebCache.m b/SDWebImage/UIImageView+HighlightedWebCache.m index ea94438f..dbc3374a 100644 --- a/SDWebImage/UIImageView+HighlightedWebCache.m +++ b/SDWebImage/UIImageView+HighlightedWebCache.m @@ -21,40 +21,39 @@ [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:nil]; } -- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url completed:(nullable SDWebImageCompletionBlock)completedBlock { +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:completedBlock]; } -- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options completed:(nullable SDWebImageCompletionBlock)completedBlock { +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:completedBlock]; } - (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDWebImageCompletionBlock)completedBlock { + completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_cancelCurrentHighlightedImageLoad]; if (url) { __weak __typeof(self)wself = self; - id operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + id operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { if (!wself) return; - dispatch_main_sync_safe (^ - { - if (!wself) return; - if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) - { - completedBlock(image, error, cacheType, url); - return; - } - else if (image) { - wself.highlightedImage = image; - [wself setNeedsLayout]; - } - if (completedBlock && finished) { - completedBlock(image, error, cacheType, url); - } - }); + dispatch_main_sync_safe (^{ + if (!wself) return; + if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) + { + completedBlock(image, error, cacheType, url); + return; + } + else if (image) { + wself.highlightedImage = image; + [wself setNeedsLayout]; + } + if (completedBlock && finished) { + completedBlock(image, error, cacheType, url); + } + }); }]; [self sd_setImageLoadOperation:operation forKey:UIImageViewHighlightedWebCacheOperationKey]; } else { diff --git a/SDWebImage/UIImageView+WebCache.h b/SDWebImage/UIImageView+WebCache.h index 46ec8663..85ca2eda 100644 --- a/SDWebImage/UIImageView+WebCache.h +++ b/SDWebImage/UIImageView+WebCache.h @@ -48,7 +48,7 @@ * Get the current image URL. * * Note that because of the limitations of categories this property can get out of sync - * if you use sd_setImage: directly. + * if you use setImage: directly. */ - (nullable NSURL *)sd_imageURL; @@ -99,7 +99,7 @@ * The fourth parameter is the original image url. */ - (void)sd_setImageWithURL:(nullable NSURL *)url - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url`, placeholder. @@ -116,7 +116,7 @@ */ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url`, placeholder and custom options. @@ -135,7 +135,7 @@ - (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url`, placeholder and custom options. @@ -156,7 +156,7 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Set the imageView `image` with an `url` and optionally a placeholder image. @@ -177,7 +177,7 @@ placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDWebImageCompletionBlock)completedBlock; + completed:(nullable SDExternalCompletionBlock)completedBlock; /** * Download an array of images and starts them in an animation loop @@ -205,4 +205,9 @@ */ - (void)setIndicatorStyle:(UIActivityIndicatorViewStyle)style; +- (BOOL)showActivityIndicatorView; +- (void)addActivityIndicator; +- (void)removeActivityIndicator; + + @end diff --git a/SDWebImage/UIImageView+WebCache.m b/SDWebImage/UIImageView+WebCache.m index 1ff6f0eb..a9286606 100644 --- a/SDWebImage/UIImageView+WebCache.m +++ b/SDWebImage/UIImageView+WebCache.m @@ -29,15 +29,15 @@ static char TAG_ACTIVITY_SHOW; [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; } -- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDWebImageCompletionBlock)completedBlock { +- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; } -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDWebImageCompletionBlock)completedBlock { +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock]; } -- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDWebImageCompletionBlock)completedBlock { +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; } @@ -45,7 +45,7 @@ static char TAG_ACTIVITY_SHOW; placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDWebImageCompletionBlock)completedBlock { + completed:(nullable SDExternalCompletionBlock)completedBlock { [self sd_cancelCurrentImageLoad]; objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); @@ -63,7 +63,7 @@ static char TAG_ACTIVITY_SHOW; } __weak __typeof(self)wself = self; - id operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + id operation = [SDWebImageManager.sharedManager loadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { [wself removeActivityIndicator]; if (!wself) return; dispatch_main_sync_safe(^{ @@ -103,7 +103,7 @@ static char TAG_ACTIVITY_SHOW; placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock - completed:(nullable SDWebImageCompletionBlock)completedBlock { + completed:(nullable SDExternalCompletionBlock)completedBlock { NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:url]; UIImage *lastPreviousCachedImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:key]; @@ -121,7 +121,7 @@ static char TAG_ACTIVITY_SHOW; NSMutableArray> *operationsArray = [[NSMutableArray alloc] init]; for (NSURL *logoImageURL in arrayOfURLs) { - id operation = [SDWebImageManager.sharedManager loadImageWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + id operation = [SDWebImageManager.sharedManager loadImageWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { if (!wself) return; dispatch_main_sync_safe(^{ __strong UIImageView *sself = wself; @@ -163,11 +163,11 @@ static char TAG_ACTIVITY_SHOW; objc_setAssociatedObject(self, &TAG_ACTIVITY_INDICATOR, activityIndicator, OBJC_ASSOCIATION_RETAIN); } -- (void)setShowActivityIndicatorView:(BOOL)show{ +- (void)setShowActivityIndicatorView:(BOOL)show { objc_setAssociatedObject(self, &TAG_ACTIVITY_SHOW, @(show), OBJC_ASSOCIATION_RETAIN); } -- (BOOL)showActivityIndicatorView{ +- (BOOL)showActivityIndicatorView { return [objc_getAssociatedObject(self, &TAG_ACTIVITY_SHOW) boolValue]; } diff --git a/Tests/Tests/SDImageCacheTests.m b/Tests/Tests/SDImageCacheTests.m index 5a546498..f4f066b6 100644 --- a/Tests/Tests/SDImageCacheTests.m +++ b/Tests/Tests/SDImageCacheTests.m @@ -100,7 +100,7 @@ NSString *kImageTestKey = @"TestImageKey.jpg"; //- (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock; UIImage *imageForTesting = [self imageForTesting]; [self.sharedImageCache storeImage:imageForTesting forKey:kImageTestKey]; - NSOperation *operation = [self.sharedImageCache queryDiskCacheForKey:kImageTestKey done:^(UIImage *image, SDImageCacheType cacheType) { + NSOperation *operation = [self.sharedImageCache queryDiskCacheForKey:kImageTestKey done:^(UIImage *image, NSData *data, SDImageCacheType cacheType) { expect(image).to.equal(imageForTesting); }]; expect(operation).toNot.beNil; diff --git a/Tests/Tests/SDWebImageDownloaderTests.m b/Tests/Tests/SDWebImageDownloaderTests.m index 04273565..f7b7641a 100644 --- a/Tests/Tests/SDWebImageDownloaderTests.m +++ b/Tests/Tests/SDWebImageDownloaderTests.m @@ -36,7 +36,7 @@ - (void)testThatDownloadingSameURLTwiceAndCancellingFirstWorks { XCTestExpectation *expectation = [self expectationWithDescription:@"Correct image downloads"]; - NSURL *imageURL = [NSURL URLWithString:@"http://static2.dmcdn.net/static/video/656/177/44771656:jpeg_preview_small.jpg?20120509154705"]; + NSURL *imageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage000.jpg"]; id token1 = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:imageURL options:0 diff --git a/Tests/Tests/SDWebImageManagerTests.m b/Tests/Tests/SDWebImageManagerTests.m index 65176c11..aeb00426 100644 --- a/Tests/Tests/SDWebImageManagerTests.m +++ b/Tests/Tests/SDWebImageManagerTests.m @@ -40,7 +40,10 @@ static int64_t kAsyncTestTimeout = 5; NSURL *originalImageURL = [NSURL URLWithString:@"http://s3.amazonaws.com/fast-image-cache/demo-images/FICDDemoImage000.jpg"]; - [[SDWebImageManager sharedManager] loadImageWithURL:originalImageURL options:SDWebImageRefreshCached progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + [[SDWebImageManager sharedManager] loadImageWithURL:originalImageURL + options:SDWebImageRefreshCached + progress:nil + completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { expect(image).toNot.beNil(); expect(error).to.beNil(); expect(originalImageURL).to.equal(imageURL); @@ -57,7 +60,10 @@ static int64_t kAsyncTestTimeout = 5; NSURL *originalImageURL = [NSURL URLWithString:@"http://static2.dmcdn.net/static/video/656/177/44771656:jpeg_preview_small.png"]; - [[SDWebImageManager sharedManager] loadImageWithURL:originalImageURL options:SDWebImageRefreshCached progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + [[SDWebImageManager sharedManager] loadImageWithURL:originalImageURL + options:SDWebImageRefreshCached + progress:nil + completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { expect(image).to.beNil(); expect(error).toNot.beNil(); expect(originalImageURL).to.equal(imageURL); diff --git a/Vendors/FLAnimatedImage b/Vendors/FLAnimatedImage new file mode 160000 index 00000000..25307796 --- /dev/null +++ b/Vendors/FLAnimatedImage @@ -0,0 +1 @@ +Subproject commit 25307796cfcf66cb5b98774e050e93f64e0f2cde