├── 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 | 
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 |
--------------------------------------------------------------------------------