├── AnimatedGIFImageSerialization.podspec ├── AnimatedGIFImageSerialization.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── AnimatedGIFImageSerialization ├── AnimatedGIFImageSerialization.h └── AnimatedGIFImageSerialization.m ├── Example ├── Animated GIF Example.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── Animated GIF Example │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json │ ├── Info.plist │ ├── Prefix.pch │ ├── animated.gif │ ├── en.lproj │ └── InfoPlist.strings │ └── main.m ├── LICENSE └── README.md /AnimatedGIFImageSerialization.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'AnimatedGIFImageSerialization' 3 | s.version = '0.2.3' 4 | s.license = 'MIT' 5 | s.summary = 'Decodes UIImage sequences from Animated GIFs.' 6 | s.homepage = 'https://github.com/mattt/AnimatedGIFImageSerialization' 7 | s.social_media_url = 'https://twitter.com/mattt' 8 | s.authors = { 'Mattt' => 'm@mattt.me' } 9 | s.source = { git: 'https://github.com/mattt/AnimatedGIFImageSerialization.git', tag: s.version } 10 | s.source_files = 'AnimatedGIFImageSerialization' 11 | s.requires_arc = true 12 | 13 | s.ios.frameworks = 'MobileCoreServices', 'ImageIO', 'CoreGraphics' 14 | s.ios.deployment_target = '5.0' 15 | end 16 | -------------------------------------------------------------------------------- /AnimatedGIFImageSerialization.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 9 | 10 | 12 | 13 | 14 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /AnimatedGIFImageSerialization.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AnimatedGIFImageSerialization/AnimatedGIFImageSerialization.h: -------------------------------------------------------------------------------- 1 | // AnimatedGIFImageSerialization.h 2 | // 3 | // Copyright (c) 2014 – 2019 Mattt (http://mat.tt/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | @import Foundation; 24 | 25 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 26 | 27 | @import UIKit; 28 | 29 | NS_ASSUME_NONNULL_BEGIN 30 | 31 | /** 32 | 33 | */ 34 | extern __attribute__((overloadable)) UIImage * _Nullable UIImageWithAnimatedGIFData(NSData *data); 35 | 36 | /** 37 | 38 | */ 39 | extern __attribute__((overloadable)) UIImage * _Nullable UIImageWithAnimatedGIFData(NSData *data, CGFloat scale, NSTimeInterval duration, NSError * __autoreleasing *error); 40 | 41 | #pragma mark - 42 | 43 | /** 44 | 45 | */ 46 | extern __attribute__((overloadable)) NSData * _Nullable UIImageAnimatedGIFRepresentation(UIImage *image); 47 | 48 | /** 49 | 50 | */ 51 | extern __attribute__((overloadable)) NSData * _Nullable UIImageAnimatedGIFRepresentation(UIImage *image, NSTimeInterval duration, NSUInteger loopCount, NSError * __autoreleasing *error); 52 | 53 | #pragma mark - 54 | 55 | /** 56 | 57 | */ 58 | @interface AnimatedGIFImageSerialization : NSObject 59 | 60 | /// @name Creating an Animated GIF 61 | 62 | /** 63 | 64 | */ 65 | + (UIImage * _Nullable)imageWithData:(NSData *)data 66 | error:(NSError * __autoreleasing *)error; 67 | 68 | /** 69 | 70 | */ 71 | + (UIImage * _Nullable)imageWithData:(NSData *)data 72 | scale:(CGFloat)scale 73 | duration:(NSTimeInterval)duration 74 | error:(NSError * __autoreleasing *)error; 75 | 76 | /// @name Creating Animated Gif Data 77 | 78 | /** 79 | 80 | */ 81 | + (NSData * _Nullable)animatedGIFDataWithImage:(UIImage *)image 82 | error:(NSError * __autoreleasing *)error; 83 | 84 | /** 85 | 86 | */ 87 | + (NSData * _Nullable)animatedGIFDataWithImage:(UIImage *)image 88 | duration:(NSTimeInterval)duration 89 | loopCount:(NSUInteger)loopCount 90 | error:(NSError * __autoreleasing *)error; 91 | 92 | @end 93 | 94 | /** 95 | 96 | */ 97 | extern NSString * const AnimatedGIFImageErrorDomain; 98 | 99 | NS_ASSUME_NONNULL_END 100 | 101 | #endif 102 | 103 | -------------------------------------------------------------------------------- /AnimatedGIFImageSerialization/AnimatedGIFImageSerialization.m: -------------------------------------------------------------------------------- 1 | // AnimatedGIFImageSerialization.m 2 | // 3 | // Copyright (c) 2014 – 2019 Mattt (http://mat.tt/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "AnimatedGIFImageSerialization.h" 24 | 25 | @import ImageIO; 26 | @import MobileCoreServices; 27 | 28 | NS_ASSUME_NONNULL_BEGIN 29 | 30 | typedef NS_ENUM(NSInteger, AnimatedGifScreenType) { 31 | AnimatedGifScreenType480h = 480, // iPhone 1, 2, 3, 4, 4s 32 | AnimatedGifScreenType568h = 568, // iPhone 5, iPhone 5s 33 | AnimatedGifScreenType667h = 667, // iPhone 6 34 | AnimatedGifScreenType736h = 736, // iPhone 6+ 35 | AnimatedGifScreenTypeUnknown = 0 36 | }; 37 | 38 | static NSString * const AnimatedGifScreenTypeSuffix480h = @""; 39 | static NSString * const AnimatedGifScreenTypeSuffix568h = @"-568h"; 40 | static NSString * const AnimatedGifScreenTypeSuffix667h = @"-667h"; 41 | static NSString * const AnimatedGifScreenTypeSuffix736h = @"-736h"; 42 | 43 | NSString * const AnimatedGIFImageErrorDomain = @"com.compuserve.gif.image.error"; 44 | 45 | __attribute__((overloadable)) UIImage * _Nullable UIImageWithAnimatedGIFData(NSData *data) { 46 | return UIImageWithAnimatedGIFData(data, [[UIScreen mainScreen] scale], 0.0, nil); 47 | } 48 | 49 | __attribute__((overloadable)) UIImage * _Nullable UIImageWithAnimatedGIFData(NSData *data, CGFloat scale, NSTimeInterval duration, NSError * __autoreleasing *error) { 50 | if (!data) { 51 | return nil; 52 | } 53 | 54 | NSMutableDictionary *mutableOptions = [NSMutableDictionary dictionary]; 55 | mutableOptions[(__bridge NSString *)kCGImageSourceShouldCache] = @(YES); 56 | mutableOptions[(__bridge NSString *)kCGImageSourceTypeIdentifierHint] = (__bridge NSString *)kUTTypeGIF; 57 | 58 | CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)mutableOptions); 59 | 60 | size_t numberOfFrames = CGImageSourceGetCount(imageSource); 61 | NSMutableArray *mutableImages = [NSMutableArray arrayWithCapacity:numberOfFrames]; 62 | 63 | NSTimeInterval calculatedDuration = 0.0; 64 | for (size_t idx = 0; idx < numberOfFrames; idx++) { 65 | CGImageRef imageRef = CGImageSourceCreateImageAtIndex(imageSource, idx, (__bridge CFDictionaryRef)mutableOptions); 66 | 67 | NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imageSource, idx, NULL); 68 | NSDictionary *gifProperties = properties[(__bridge NSString *)kCGImagePropertyGIFDictionary]; 69 | 70 | NSNumber *delay = gifProperties[(__bridge NSString *)kCGImagePropertyGIFUnclampedDelayTime]; 71 | if (!delay) { 72 | delay = gifProperties[(__bridge NSString *)kCGImagePropertyGIFDelayTime]; 73 | } 74 | 75 | calculatedDuration += [delay doubleValue]; 76 | 77 | [mutableImages addObject:[UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]]; 78 | 79 | CGImageRelease(imageRef); 80 | } 81 | 82 | CFRelease(imageSource); 83 | 84 | if (numberOfFrames == 1) { 85 | return [mutableImages firstObject]; 86 | } else { 87 | return [UIImage animatedImageWithImages:mutableImages duration:(duration <= 0.0 ? calculatedDuration : duration)]; 88 | } 89 | } 90 | 91 | static BOOL AnimatedGifDataIsValid(NSData *data) { 92 | if (data.length > 4) { 93 | const unsigned char * bytes = [data bytes]; 94 | 95 | return bytes[0] == 0x47 && bytes[1] == 0x49 && bytes[2] == 0x46; 96 | } 97 | 98 | return NO; 99 | } 100 | 101 | __attribute__((overloadable)) NSData * _Nullable UIImageAnimatedGIFRepresentation(UIImage *image) { 102 | return UIImageAnimatedGIFRepresentation(image, 0.0, 0, nil); 103 | } 104 | 105 | __attribute__((overloadable)) NSData * _Nullable UIImageAnimatedGIFRepresentation(UIImage *image, NSTimeInterval duration, NSUInteger loopCount, NSError * __autoreleasing *error) { 106 | if (!image) { 107 | return nil; 108 | } 109 | 110 | NSArray *images = image.images; 111 | if (!images) { 112 | images = @[image]; 113 | } 114 | 115 | NSDictionary *userInfo = nil; 116 | { 117 | size_t frameCount = images.count; 118 | NSTimeInterval frameDuration = (duration <= 0.0 ? image.duration / frameCount : duration / frameCount); 119 | NSUInteger frameDelayCentiseconds = (NSUInteger)lrint(frameDuration * 100); 120 | NSDictionary *frameProperties = @{ 121 | (__bridge NSString *)kCGImagePropertyGIFDictionary: @{ 122 | (__bridge NSString *)kCGImagePropertyGIFDelayTime: @(frameDelayCentiseconds) 123 | } 124 | }; 125 | 126 | NSMutableData *mutableData = [NSMutableData data]; 127 | CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)mutableData, kUTTypeGIF, frameCount, NULL); 128 | 129 | NSDictionary *imageProperties = @{ (__bridge NSString *)kCGImagePropertyGIFDictionary: @{ 130 | (__bridge NSString *)kCGImagePropertyGIFLoopCount: @(loopCount) 131 | } 132 | }; 133 | CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)imageProperties); 134 | 135 | for (size_t idx = 0; idx < images.count; idx++) { 136 | CGImageRef _Nullable cgimage = [images[idx] CGImage]; 137 | if (cgimage) { 138 | CGImageDestinationAddImage(destination, (CGImageRef _Nonnull)cgimage, (__bridge CFDictionaryRef)frameProperties); 139 | } 140 | } 141 | 142 | BOOL success = CGImageDestinationFinalize(destination); 143 | CFRelease(destination); 144 | 145 | if (!success) { 146 | userInfo = @{ 147 | NSLocalizedDescriptionKey: NSLocalizedString(@"Could not finalize image destination", nil) 148 | }; 149 | 150 | goto _error; 151 | } 152 | 153 | return [NSData dataWithData:mutableData]; 154 | } 155 | _error: { 156 | if (error) { 157 | *error = [[NSError alloc] initWithDomain:AnimatedGIFImageErrorDomain code:-1 userInfo:userInfo]; 158 | } 159 | 160 | return nil; 161 | } 162 | } 163 | 164 | @implementation AnimatedGIFImageSerialization 165 | 166 | + (UIImage * _Nullable)imageWithData:(NSData *)data 167 | error:(NSError * __autoreleasing *)error 168 | { 169 | return [self imageWithData:data scale:1.0 duration:0.0 error:error]; 170 | } 171 | 172 | + (UIImage * _Nullable)imageWithData:(NSData *)data 173 | scale:(CGFloat)scale 174 | duration:(NSTimeInterval)duration 175 | error:(NSError * __autoreleasing *)error 176 | { 177 | return UIImageWithAnimatedGIFData(data, scale, duration, error); 178 | } 179 | 180 | #pragma mark - 181 | 182 | + (NSData * _Nullable)animatedGIFDataWithImage:(UIImage *)image 183 | error:(NSError * __autoreleasing *)error 184 | { 185 | return [self animatedGIFDataWithImage:image duration:0.0 loopCount:0 error:error]; 186 | } 187 | 188 | + (NSData * _Nullable)animatedGIFDataWithImage:(UIImage *)image 189 | duration:(NSTimeInterval)duration 190 | loopCount:(NSUInteger)loopCount 191 | error:(NSError *__autoreleasing *)error 192 | { 193 | return UIImageAnimatedGIFRepresentation(image, duration, loopCount, error); 194 | } 195 | 196 | @end 197 | 198 | NS_ASSUME_NONNULL_END 199 | 200 | #pragma mark - 201 | 202 | #ifndef ANIMATED_GIF_NO_UIIMAGE_INITIALIZER_SWIZZLING 203 | @import ObjectiveC.runtime; 204 | 205 | static inline void animated_gif_swizzleSelector(Class class, SEL originalSelector, SEL swizzledSelector) { 206 | Method originalMethod = class_getInstanceMethod(class, originalSelector); 207 | Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); 208 | if (class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) { 209 | class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); 210 | } else { 211 | method_exchangeImplementations(originalMethod, swizzledMethod); 212 | } 213 | } 214 | 215 | @interface UIImage (_AnimatedGIFImageSerialization) 216 | @end 217 | 218 | @implementation UIImage (_AnimatedGIFImageSerialization) 219 | 220 | + (void)load { 221 | static dispatch_once_t onceToken; 222 | dispatch_once(&onceToken, ^{ 223 | @autoreleasepool { 224 | animated_gif_swizzleSelector(object_getClass((id)self), @selector(imageNamed:), @selector(animated_gif_imageNamed:)); 225 | animated_gif_swizzleSelector(object_getClass((id)self), @selector(imageWithData:), @selector(animated_gif_imageWithData:)); 226 | animated_gif_swizzleSelector(object_getClass((id)self), @selector(imageWithData:scale:), @selector(animated_gif_imageWithData:scale:)); 227 | animated_gif_swizzleSelector(object_getClass((id)self), @selector(imageWithContentsOfFile:), @selector(animated_gif_imageWithContentsOfFile:)); 228 | animated_gif_swizzleSelector(self, @selector(initWithContentsOfFile:), @selector(animated_gif_initWithContentsOfFile:)); 229 | animated_gif_swizzleSelector(self, @selector(initWithData:), @selector(animated_gif_initWithData:)); 230 | animated_gif_swizzleSelector(self, @selector(initWithData:scale:), @selector(animated_gif_initWithData:scale:)); 231 | } 232 | }); 233 | } 234 | 235 | #pragma mark - 236 | 237 | NS_ASSUME_NONNULL_BEGIN 238 | 239 | + (UIImage * _Nullable)animated_gif_imageNamed:(NSString *)name __attribute__((objc_method_family(new))) { 240 | CGFloat scale = [[UIScreen mainScreen] scale]; 241 | CGRect screenBounds = [[UIScreen mainScreen] bounds]; 242 | 243 | NSString *ratioSuffix = @""; 244 | switch ((NSUInteger)screenBounds.size.height) { 245 | case AnimatedGifScreenType480h: 246 | ratioSuffix = AnimatedGifScreenTypeSuffix480h; 247 | break; 248 | case AnimatedGifScreenType568h: 249 | ratioSuffix = AnimatedGifScreenTypeSuffix568h; 250 | break; 251 | case AnimatedGifScreenType667h: 252 | ratioSuffix = AnimatedGifScreenTypeSuffix667h; 253 | break; 254 | case AnimatedGifScreenType736h: 255 | ratioSuffix = AnimatedGifScreenTypeSuffix736h; 256 | break; 257 | } 258 | 259 | NSString *scaleSuffix = @""; 260 | if (scale >= 3) { 261 | scaleSuffix = @"@3x"; 262 | } else if (scale >= 2) { 263 | scaleSuffix = @"@2x"; 264 | } 265 | 266 | NSString * _Nullable path = nil; 267 | if (!path) { 268 | // e.g. animated-568h@2x.gif 269 | NSString *nameWithRatioAndScale = [[[name stringByDeletingPathExtension] stringByAppendingString:ratioSuffix] stringByAppendingString:scaleSuffix]; 270 | path = [[NSBundle mainBundle] pathForResource:nameWithRatioAndScale ofType:[name pathExtension]]; 271 | } 272 | 273 | if (!path) { 274 | // e.g. animated@2x.gif 275 | NSString *nameWithRatio = [[[name stringByDeletingPathExtension] stringByAppendingString:scaleSuffix] stringByAppendingPathExtension:[name pathExtension]]; 276 | path = [[NSBundle mainBundle] pathForResource:nameWithRatio ofType:[name pathExtension]]; 277 | } 278 | 279 | if (!path) { 280 | // e.g. animated.gif 281 | path = [[NSBundle mainBundle] pathForResource:[name stringByDeletingPathExtension] ofType:[name pathExtension]]; 282 | } 283 | 284 | if (path) { 285 | NSData *data = [NSData dataWithContentsOfFile:(NSString * _Nonnull)path]; 286 | if (AnimatedGifDataIsValid(data)) { 287 | return UIImageWithAnimatedGIFData(data); 288 | } 289 | } 290 | 291 | return [self animated_gif_imageNamed:name]; 292 | } 293 | 294 | + (UIImage * _Nullable)animated_gif_imageWithContentsOfFile:(NSString *)path { 295 | if (path) { 296 | NSData *data = [NSData dataWithContentsOfFile:path]; 297 | if (AnimatedGifDataIsValid(data)) { 298 | if ([[path stringByDeletingPathExtension] hasSuffix:@"@3x"]) { 299 | return UIImageWithAnimatedGIFData(data, 3.0, 0.0, nil); 300 | } else if ([[path stringByDeletingPathExtension] hasSuffix:@"@2x"]) { 301 | return UIImageWithAnimatedGIFData(data, 2.0, 0.0, nil); 302 | } else { 303 | return UIImageWithAnimatedGIFData(data); 304 | } 305 | } 306 | } 307 | 308 | return [self animated_gif_imageWithContentsOfFile:path]; 309 | } 310 | 311 | + (UIImage * _Nullable)animated_gif_imageWithData:(NSData *)data { 312 | if (AnimatedGifDataIsValid(data)) { 313 | return UIImageWithAnimatedGIFData(data); 314 | } 315 | 316 | return [self animated_gif_imageWithData:data]; 317 | } 318 | 319 | + (UIImage * _Nullable)animated_gif_imageWithData:(NSData *)data 320 | scale:(CGFloat)scale { 321 | if (AnimatedGifDataIsValid(data)) { 322 | return UIImageWithAnimatedGIFData(data, scale, 0.0, nil); 323 | } 324 | 325 | return [self animated_gif_imageWithData:data scale:scale]; 326 | } 327 | 328 | #pragma mark - 329 | 330 | - (instancetype)animated_gif_initWithContentsOfFile:(NSString *)path __attribute__((objc_method_family(init))) { 331 | NSData *data = [NSData dataWithContentsOfFile:path]; 332 | if (AnimatedGifDataIsValid(data)) { 333 | if ([[path stringByDeletingPathExtension] hasSuffix:@"@3x"]) { 334 | return UIImageWithAnimatedGIFData(data, 3.0, 0.0, nil); 335 | } else if ([[path stringByDeletingPathExtension] hasSuffix:@"@2x"]) { 336 | return UIImageWithAnimatedGIFData(data, 2.0, 0.0, nil); 337 | } else { 338 | return UIImageWithAnimatedGIFData(data); 339 | } 340 | } 341 | 342 | return [self animated_gif_initWithContentsOfFile:path]; 343 | } 344 | 345 | - (instancetype)animated_gif_initWithData:(NSData *)data __attribute__((objc_method_family(init))) { 346 | if (AnimatedGifDataIsValid(data)) { 347 | return UIImageWithAnimatedGIFData(data); 348 | } 349 | 350 | return [self animated_gif_initWithData:data]; 351 | } 352 | 353 | - (instancetype)animated_gif_initWithData:(NSData *)data 354 | scale:(CGFloat)scale __attribute__((objc_method_family(init))) 355 | { 356 | if (AnimatedGifDataIsValid(data)) { 357 | return UIImageWithAnimatedGIFData(data, scale, 0.0, nil); 358 | } 359 | 360 | return [self animated_gif_initWithData:data scale:scale]; 361 | } 362 | 363 | @end 364 | 365 | NS_ASSUME_NONNULL_END 366 | 367 | #endif 368 | -------------------------------------------------------------------------------- /Example/Animated GIF Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | F82E75AF18ABDC4E002D596E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F82E75AE18ABDC4E002D596E /* Foundation.framework */; }; 11 | F82E75B118ABDC4E002D596E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F82E75B018ABDC4E002D596E /* CoreGraphics.framework */; }; 12 | F82E75B318ABDC4E002D596E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F82E75B218ABDC4E002D596E /* UIKit.framework */; }; 13 | F82E75B918ABDC4E002D596E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F82E75B718ABDC4E002D596E /* InfoPlist.strings */; }; 14 | F82E75BB18ABDC4E002D596E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F82E75BA18ABDC4E002D596E /* main.m */; }; 15 | F82E75BF18ABDC4E002D596E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F82E75BE18ABDC4E002D596E /* AppDelegate.m */; }; 16 | F82E75C118ABDC4E002D596E /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F82E75C018ABDC4E002D596E /* Images.xcassets */; }; 17 | F83E7E5F18E1FCA900309F89 /* AnimatedGIFImageSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = F83E7E5E18E1FCA900309F89 /* AnimatedGIFImageSerialization.m */; }; 18 | F862CE2518E1EFF000DC750D /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F862CE2418E1EFF000DC750D /* ImageIO.framework */; }; 19 | F862CE2718E1F53800DC750D /* animated.gif in Resources */ = {isa = PBXBuildFile; fileRef = F862CE2618E1F53800DC750D /* animated.gif */; }; 20 | F862CE2918E1F7AB00DC750D /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F862CE2818E1F7AB00DC750D /* MobileCoreServices.framework */; }; 21 | /* End PBXBuildFile section */ 22 | 23 | /* Begin PBXFileReference section */ 24 | F82E75AB18ABDC4E002D596E /* Animated GIF.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Animated GIF.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | F82E75AE18ABDC4E002D596E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 26 | F82E75B018ABDC4E002D596E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 27 | F82E75B218ABDC4E002D596E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 28 | F82E75B618ABDC4E002D596E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 29 | F82E75B818ABDC4E002D596E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 30 | F82E75BA18ABDC4E002D596E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 31 | F82E75BC18ABDC4E002D596E /* Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = ""; }; 32 | F82E75BD18ABDC4E002D596E /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 33 | F82E75BE18ABDC4E002D596E /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 34 | F82E75C018ABDC4E002D596E /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 35 | F83E7E5D18E1FCA900309F89 /* AnimatedGIFImageSerialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AnimatedGIFImageSerialization.h; sourceTree = ""; }; 36 | F83E7E5E18E1FCA900309F89 /* AnimatedGIFImageSerialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AnimatedGIFImageSerialization.m; sourceTree = ""; }; 37 | F862CE2418E1EFF000DC750D /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; 38 | F862CE2618E1F53800DC750D /* animated.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = animated.gif; sourceTree = ""; }; 39 | F862CE2818E1F7AB00DC750D /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; 40 | /* End PBXFileReference section */ 41 | 42 | /* Begin PBXFrameworksBuildPhase section */ 43 | F82E75A818ABDC4E002D596E /* Frameworks */ = { 44 | isa = PBXFrameworksBuildPhase; 45 | buildActionMask = 2147483647; 46 | files = ( 47 | F862CE2918E1F7AB00DC750D /* MobileCoreServices.framework in Frameworks */, 48 | F862CE2518E1EFF000DC750D /* ImageIO.framework in Frameworks */, 49 | F82E75B118ABDC4E002D596E /* CoreGraphics.framework in Frameworks */, 50 | F82E75B318ABDC4E002D596E /* UIKit.framework in Frameworks */, 51 | F82E75AF18ABDC4E002D596E /* Foundation.framework in Frameworks */, 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | F82E75A218ABDC4E002D596E = { 59 | isa = PBXGroup; 60 | children = ( 61 | F82E75B418ABDC4E002D596E /* Animated GIF Example */, 62 | F82E75AD18ABDC4E002D596E /* Frameworks */, 63 | F82E75AC18ABDC4E002D596E /* Products */, 64 | F82E75DD18ABDC57002D596E /* Vendor */, 65 | ); 66 | sourceTree = ""; 67 | }; 68 | F82E75AC18ABDC4E002D596E /* Products */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | F82E75AB18ABDC4E002D596E /* Animated GIF.app */, 72 | ); 73 | name = Products; 74 | sourceTree = ""; 75 | }; 76 | F82E75AD18ABDC4E002D596E /* Frameworks */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | F862CE2818E1F7AB00DC750D /* MobileCoreServices.framework */, 80 | F862CE2418E1EFF000DC750D /* ImageIO.framework */, 81 | F82E75AE18ABDC4E002D596E /* Foundation.framework */, 82 | F82E75B018ABDC4E002D596E /* CoreGraphics.framework */, 83 | F82E75B218ABDC4E002D596E /* UIKit.framework */, 84 | ); 85 | name = Frameworks; 86 | sourceTree = ""; 87 | }; 88 | F82E75B418ABDC4E002D596E /* Animated GIF Example */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | F82E75BD18ABDC4E002D596E /* AppDelegate.h */, 92 | F82E75BE18ABDC4E002D596E /* AppDelegate.m */, 93 | F82E75C018ABDC4E002D596E /* Images.xcassets */, 94 | F82E75B518ABDC4E002D596E /* Supporting Files */, 95 | ); 96 | path = "Animated GIF Example"; 97 | sourceTree = ""; 98 | }; 99 | F82E75B518ABDC4E002D596E /* Supporting Files */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | F82E75B618ABDC4E002D596E /* Info.plist */, 103 | F82E75B718ABDC4E002D596E /* InfoPlist.strings */, 104 | F82E75BA18ABDC4E002D596E /* main.m */, 105 | F82E75BC18ABDC4E002D596E /* Prefix.pch */, 106 | F862CE2618E1F53800DC750D /* animated.gif */, 107 | ); 108 | name = "Supporting Files"; 109 | sourceTree = ""; 110 | }; 111 | F82E75DD18ABDC57002D596E /* Vendor */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | F83E7E5C18E1FCA900309F89 /* AnimatedGIFImageSerialization */, 115 | ); 116 | name = Vendor; 117 | path = ../WebPImageSerialization; 118 | sourceTree = ""; 119 | }; 120 | F83E7E5C18E1FCA900309F89 /* AnimatedGIFImageSerialization */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | F83E7E5D18E1FCA900309F89 /* AnimatedGIFImageSerialization.h */, 124 | F83E7E5E18E1FCA900309F89 /* AnimatedGIFImageSerialization.m */, 125 | ); 126 | name = AnimatedGIFImageSerialization; 127 | path = ../AnimatedGIFImageSerialization; 128 | sourceTree = ""; 129 | }; 130 | /* End PBXGroup section */ 131 | 132 | /* Begin PBXNativeTarget section */ 133 | F82E75AA18ABDC4E002D596E /* Animated GIF Example */ = { 134 | isa = PBXNativeTarget; 135 | buildConfigurationList = F82E75D718ABDC4E002D596E /* Build configuration list for PBXNativeTarget "Animated GIF Example" */; 136 | buildPhases = ( 137 | F82E75A718ABDC4E002D596E /* Sources */, 138 | F82E75A818ABDC4E002D596E /* Frameworks */, 139 | F82E75A918ABDC4E002D596E /* Resources */, 140 | ); 141 | buildRules = ( 142 | ); 143 | dependencies = ( 144 | ); 145 | name = "Animated GIF Example"; 146 | productName = "WebPImage Example"; 147 | productReference = F82E75AB18ABDC4E002D596E /* Animated GIF.app */; 148 | productType = "com.apple.product-type.application"; 149 | }; 150 | /* End PBXNativeTarget section */ 151 | 152 | /* Begin PBXProject section */ 153 | F82E75A318ABDC4E002D596E /* Project object */ = { 154 | isa = PBXProject; 155 | attributes = { 156 | LastUpgradeCheck = 1020; 157 | ORGANIZATIONNAME = Mattt; 158 | TargetAttributes = { 159 | F82E75AA18ABDC4E002D596E = { 160 | ProvisioningStyle = Automatic; 161 | }; 162 | }; 163 | }; 164 | buildConfigurationList = F82E75A618ABDC4E002D596E /* Build configuration list for PBXProject "Animated GIF Example" */; 165 | compatibilityVersion = "Xcode 3.2"; 166 | developmentRegion = en; 167 | hasScannedForEncodings = 0; 168 | knownRegions = ( 169 | en, 170 | Base, 171 | ); 172 | mainGroup = F82E75A218ABDC4E002D596E; 173 | productRefGroup = F82E75AC18ABDC4E002D596E /* Products */; 174 | projectDirPath = ""; 175 | projectRoot = ""; 176 | targets = ( 177 | F82E75AA18ABDC4E002D596E /* Animated GIF Example */, 178 | ); 179 | }; 180 | /* End PBXProject section */ 181 | 182 | /* Begin PBXResourcesBuildPhase section */ 183 | F82E75A918ABDC4E002D596E /* Resources */ = { 184 | isa = PBXResourcesBuildPhase; 185 | buildActionMask = 2147483647; 186 | files = ( 187 | F82E75B918ABDC4E002D596E /* InfoPlist.strings in Resources */, 188 | F82E75C118ABDC4E002D596E /* Images.xcassets in Resources */, 189 | F862CE2718E1F53800DC750D /* animated.gif in Resources */, 190 | ); 191 | runOnlyForDeploymentPostprocessing = 0; 192 | }; 193 | /* End PBXResourcesBuildPhase section */ 194 | 195 | /* Begin PBXSourcesBuildPhase section */ 196 | F82E75A718ABDC4E002D596E /* Sources */ = { 197 | isa = PBXSourcesBuildPhase; 198 | buildActionMask = 2147483647; 199 | files = ( 200 | F83E7E5F18E1FCA900309F89 /* AnimatedGIFImageSerialization.m in Sources */, 201 | F82E75BF18ABDC4E002D596E /* AppDelegate.m in Sources */, 202 | F82E75BB18ABDC4E002D596E /* main.m in Sources */, 203 | ); 204 | runOnlyForDeploymentPostprocessing = 0; 205 | }; 206 | /* End PBXSourcesBuildPhase section */ 207 | 208 | /* Begin PBXVariantGroup section */ 209 | F82E75B718ABDC4E002D596E /* InfoPlist.strings */ = { 210 | isa = PBXVariantGroup; 211 | children = ( 212 | F82E75B818ABDC4E002D596E /* en */, 213 | ); 214 | name = InfoPlist.strings; 215 | sourceTree = ""; 216 | }; 217 | /* End PBXVariantGroup section */ 218 | 219 | /* Begin XCBuildConfiguration section */ 220 | F82E75D518ABDC4E002D596E /* Debug */ = { 221 | isa = XCBuildConfiguration; 222 | buildSettings = { 223 | ALWAYS_SEARCH_USER_PATHS = YES; 224 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 225 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 226 | CLANG_CXX_LIBRARY = "libc++"; 227 | CLANG_ENABLE_MODULES = YES; 228 | CLANG_ENABLE_OBJC_ARC = YES; 229 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 230 | CLANG_WARN_BOOL_CONVERSION = YES; 231 | CLANG_WARN_COMMA = YES; 232 | CLANG_WARN_CONSTANT_CONVERSION = YES; 233 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 234 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 235 | CLANG_WARN_EMPTY_BODY = YES; 236 | CLANG_WARN_ENUM_CONVERSION = YES; 237 | CLANG_WARN_INFINITE_RECURSION = YES; 238 | CLANG_WARN_INT_CONVERSION = YES; 239 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 240 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 241 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 242 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 243 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 244 | CLANG_WARN_STRICT_PROTOTYPES = YES; 245 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 246 | CLANG_WARN_UNREACHABLE_CODE = YES; 247 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 248 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 249 | COPY_PHASE_STRIP = NO; 250 | ENABLE_STRICT_OBJC_MSGSEND = YES; 251 | ENABLE_TESTABILITY = YES; 252 | GCC_C_LANGUAGE_STANDARD = gnu99; 253 | GCC_DYNAMIC_NO_PIC = NO; 254 | GCC_NO_COMMON_BLOCKS = YES; 255 | GCC_OPTIMIZATION_LEVEL = 0; 256 | GCC_PREPROCESSOR_DEFINITIONS = ( 257 | "DEBUG=1", 258 | "$(inherited)", 259 | ); 260 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 261 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 262 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 263 | GCC_WARN_PEDANTIC = YES; 264 | GCC_WARN_UNDECLARED_SELECTOR = YES; 265 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 266 | GCC_WARN_UNUSED_FUNCTION = YES; 267 | GCC_WARN_UNUSED_VARIABLE = YES; 268 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 269 | ONLY_ACTIVE_ARCH = YES; 270 | SDKROOT = iphoneos; 271 | WARNING_CFLAGS = "-Weverything"; 272 | }; 273 | name = Debug; 274 | }; 275 | F82E75D618ABDC4E002D596E /* Release */ = { 276 | isa = XCBuildConfiguration; 277 | buildSettings = { 278 | ALWAYS_SEARCH_USER_PATHS = YES; 279 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 280 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 281 | CLANG_CXX_LIBRARY = "libc++"; 282 | CLANG_ENABLE_MODULES = YES; 283 | CLANG_ENABLE_OBJC_ARC = YES; 284 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 285 | CLANG_WARN_BOOL_CONVERSION = YES; 286 | CLANG_WARN_COMMA = YES; 287 | CLANG_WARN_CONSTANT_CONVERSION = YES; 288 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 289 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 290 | CLANG_WARN_EMPTY_BODY = YES; 291 | CLANG_WARN_ENUM_CONVERSION = YES; 292 | CLANG_WARN_INFINITE_RECURSION = YES; 293 | CLANG_WARN_INT_CONVERSION = YES; 294 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 295 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 296 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 297 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 298 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 299 | CLANG_WARN_STRICT_PROTOTYPES = YES; 300 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 301 | CLANG_WARN_UNREACHABLE_CODE = YES; 302 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 303 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 304 | COPY_PHASE_STRIP = YES; 305 | ENABLE_NS_ASSERTIONS = NO; 306 | ENABLE_STRICT_OBJC_MSGSEND = YES; 307 | GCC_C_LANGUAGE_STANDARD = gnu99; 308 | GCC_NO_COMMON_BLOCKS = YES; 309 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 310 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 311 | GCC_WARN_PEDANTIC = YES; 312 | GCC_WARN_UNDECLARED_SELECTOR = YES; 313 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 314 | GCC_WARN_UNUSED_FUNCTION = YES; 315 | GCC_WARN_UNUSED_VARIABLE = YES; 316 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 317 | SDKROOT = iphoneos; 318 | VALIDATE_PRODUCT = YES; 319 | WARNING_CFLAGS = "-Weverything"; 320 | }; 321 | name = Release; 322 | }; 323 | F82E75D818ABDC4E002D596E /* Debug */ = { 324 | isa = XCBuildConfiguration; 325 | buildSettings = { 326 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 327 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 328 | CODE_SIGN_IDENTITY = "iPhone Developer"; 329 | CODE_SIGN_STYLE = Automatic; 330 | DEVELOPMENT_TEAM = ""; 331 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 332 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 333 | GCC_PREFIX_HEADER = "Animated GIF Example/Prefix.pch"; 334 | INFOPLIST_FILE = "$(SRCROOT)/Animated GIF Example/Info.plist"; 335 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 336 | PRODUCT_BUNDLE_IDENTIFIER = "com.mattt.${PRODUCT_NAME:rfc1034identifier}"; 337 | PRODUCT_NAME = "Animated GIF"; 338 | PROVISIONING_PROFILE_SPECIFIER = ""; 339 | WRAPPER_EXTENSION = app; 340 | }; 341 | name = Debug; 342 | }; 343 | F82E75D918ABDC4E002D596E /* Release */ = { 344 | isa = XCBuildConfiguration; 345 | buildSettings = { 346 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 347 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 348 | CODE_SIGN_IDENTITY = "iPhone Developer"; 349 | CODE_SIGN_STYLE = Automatic; 350 | DEVELOPMENT_TEAM = ""; 351 | FRAMEWORK_SEARCH_PATHS = "$(inherited)"; 352 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 353 | GCC_PREFIX_HEADER = "Animated GIF Example/Prefix.pch"; 354 | INFOPLIST_FILE = "$(SRCROOT)/Animated GIF Example/Info.plist"; 355 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 356 | PRODUCT_BUNDLE_IDENTIFIER = "com.mattt.${PRODUCT_NAME:rfc1034identifier}"; 357 | PRODUCT_NAME = "Animated GIF"; 358 | PROVISIONING_PROFILE_SPECIFIER = ""; 359 | WRAPPER_EXTENSION = app; 360 | }; 361 | name = Release; 362 | }; 363 | /* End XCBuildConfiguration section */ 364 | 365 | /* Begin XCConfigurationList section */ 366 | F82E75A618ABDC4E002D596E /* Build configuration list for PBXProject "Animated GIF Example" */ = { 367 | isa = XCConfigurationList; 368 | buildConfigurations = ( 369 | F82E75D518ABDC4E002D596E /* Debug */, 370 | F82E75D618ABDC4E002D596E /* Release */, 371 | ); 372 | defaultConfigurationIsVisible = 0; 373 | defaultConfigurationName = Release; 374 | }; 375 | F82E75D718ABDC4E002D596E /* Build configuration list for PBXNativeTarget "Animated GIF Example" */ = { 376 | isa = XCConfigurationList; 377 | buildConfigurations = ( 378 | F82E75D818ABDC4E002D596E /* Debug */, 379 | F82E75D918ABDC4E002D596E /* Release */, 380 | ); 381 | defaultConfigurationIsVisible = 0; 382 | defaultConfigurationName = Release; 383 | }; 384 | /* End XCConfigurationList section */ 385 | }; 386 | rootObject = F82E75A318ABDC4E002D596E /* Project object */; 387 | } 388 | -------------------------------------------------------------------------------- /Example/Animated GIF Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Animated GIF Example/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // AppDelegate.h 2 | // 3 | // Copyright (c) 2014 – 2019 Mattt (http://mat.tt/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | @import UIKit; 24 | 25 | @interface AppDelegate : UIResponder 26 | 27 | @property (strong, nonatomic) UIWindow *window; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Example/Animated GIF Example/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // AppDelegate.m 2 | // 3 | // Copyright (c) 2014 – 2019 Mattt (http://mat.tt/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "AppDelegate.h" 24 | 25 | #import "AnimatedGIFImageSerialization.h" 26 | 27 | @implementation AppDelegate 28 | @synthesize window; 29 | 30 | - (BOOL)application:(__unused UIApplication *)application 31 | didFinishLaunchingWithOptions:(__unused NSDictionary *)launchOptions 32 | { 33 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 34 | 35 | UIViewController *viewController = [[UIViewController alloc] init]; 36 | self.window.rootViewController = viewController; 37 | 38 | UIImageView *imageView = [[UIImageView alloc] initWithFrame:viewController.view.bounds]; 39 | imageView.contentMode = UIViewContentModeScaleAspectFill; 40 | imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 41 | imageView.image = [UIImage imageNamed:@"animated.gif"]; 42 | [viewController.view addSubview:imageView]; 43 | 44 | self.window.backgroundColor = [UIColor whiteColor]; 45 | [self.window makeKeyAndVisible]; 46 | 47 | return YES; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Example/Animated GIF Example/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /Example/Animated GIF Example/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Example/Animated GIF Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationLandscapeLeft 34 | UIInterfaceOrientationLandscapeRight 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Example/Animated GIF Example/Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | @import Darwin.Availability; 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | #endif 17 | -------------------------------------------------------------------------------- /Example/Animated GIF Example/animated.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattt/AnimatedGIFImageSerialization/6744b861a30058de4e68a8e30bfc947ccce771ac/Example/Animated GIF Example/animated.gif -------------------------------------------------------------------------------- /Example/Animated GIF Example/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/Animated GIF Example/main.m: -------------------------------------------------------------------------------- 1 | // main.m 2 | // 3 | // Copyright (c) 2014 – 2019 Mattt (http://mat.tt/) 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | @import UIKit; 24 | 25 | #import "AppDelegate.h" 26 | 27 | int main(int argc, char * argv[]) { 28 | @autoreleasepool { 29 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 – 2019 Mattt (http://mat.tt/) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AnimatedGIFImageSerialization 2 | 3 | > This library is no longer maintained. 4 | > In iOS 13+ and macOS 10.15+, use [`CGAnimateImageAtURLWithBlock`](https://developer.apple.com/documentation/imageio/3333271-cganimateimageaturlwithblock) instead. 5 | 6 | `AnimatedGIFImageSerialization` decodes an `UIImage` from 7 | [Animated GIFs](http://en.wikipedia.org/wiki/Graphics_Interchange_Format), 8 | following the API conventions of Foundation's `NSJSONSerialization` class. 9 | 10 | By default, `UIImage` initializers can't decode animated images from GIF files. 11 | This library uses swizzling to provide this functionality for you. 12 | To opt out of this behavior, 13 | set `ANIMATED_GIF_NO_UIIMAGE_INITIALIZER_SWIZZLING` in your build environment. 14 | If you're using CocoaPods, 15 | you can add this build setting to your `Podfile`: 16 | 17 | ```ruby 18 | post_install do |r| 19 | r.pods_project.targets.each do |target| 20 | if target.name == 'AnimatedGIFImageSerialization' then 21 | target.build_configurations.each do |config| 22 | config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= 23 | ['$(inherited)', 'ANIMATED_GIF_NO_UIIMAGE_INITIALIZER_SWIZZLING=1'] 24 | end 25 | end 26 | end 27 | end 28 | ``` 29 | 30 | ## Usage 31 | 32 | ### Decoding 33 | 34 | ```objective-c 35 | UIImageView *imageView = ...; 36 | imageView.image = [UIImage imageNamed:@"animated.gif"]; 37 | ``` 38 | 39 | ![Animated GIF](https://raw.githubusercontent.com/mattt/AnimatedGIFImageSerialization/master/Example/Animated%20GIF%20Example/animated.gif) 40 | 41 | ### Encoding 42 | 43 | ```objective-c 44 | UIImage *image = ...; 45 | NSData *data = [AnimatedGIFImageSerialization animatedGIFDataWithImage:image 46 | duration:1.0 47 | loopCount:1 48 | error:nil]; 49 | ``` 50 | 51 | --- 52 | 53 | ## Contact 54 | 55 | Mattt ([@mattt](https://twitter.com/mattt)) 56 | 57 | ## License 58 | 59 | AnimatedGIFImageSerialization is available under the MIT license. 60 | See the LICENSE file for more info. 61 | --------------------------------------------------------------------------------