iOS开发_加载Gif动态图

1、加载gif

NSString *full_path = @"/Users/sdr_mac/Desktop/1f914.gif"
NSData *image_data = [NSData dataWithContentsOfFile:full_path];
UIImage *gc_Image = [[UIImage alloc] initWithData:image_data];
self.image_v.image = gc_Image;

2、核心代码

  • 不需要 #import 类,直接将以下代码文件放到工程里面就行了。
  • 2.1 AnimatedGIFImageSerialization.h

// AnimatedGIFImageSerialization.h
//
// Copyright (c) 2014 – 2019 Mattt (http://mat.tt/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

@import Foundation;

#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)

@import UIKit;

NS_ASSUME_NONNULL_BEGIN

/**

 */
extern __attribute__((overloadable)) UIImage * _Nullable UIImageWithAnimatedGIFData(NSData *data);

/**

 */
extern __attribute__((overloadable)) UIImage * _Nullable UIImageWithAnimatedGIFData(NSData *data, CGFloat scale, NSTimeInterval duration, NSError * __autoreleasing *error);

#pragma mark -

/**

 */
extern __attribute__((overloadable)) NSData * _Nullable UIImageAnimatedGIFRepresentation(UIImage *image);

/**

 */
extern __attribute__((overloadable)) NSData * _Nullable UIImageAnimatedGIFRepresentation(UIImage *image, NSTimeInterval duration, NSUInteger loopCount, NSError * __autoreleasing *error);

#pragma mark -

/**

 */
@interface AnimatedGIFImageSerialization : NSObject

/// @name Creating an Animated GIF

/**

 */
+ (UIImage * _Nullable)imageWithData:(NSData *)data
                               error:(NSError * __autoreleasing *)error;

/**

 */
+ (UIImage * _Nullable)imageWithData:(NSData *)data
                               scale:(CGFloat)scale
                            duration:(NSTimeInterval)duration
                               error:(NSError * __autoreleasing *)error;

/// @name Creating Animated Gif Data

/**

 */
+ (NSData * _Nullable)animatedGIFDataWithImage:(UIImage *)image
                               error:(NSError * __autoreleasing *)error;

/**

 */
+ (NSData * _Nullable)animatedGIFDataWithImage:(UIImage *)image
                                      duration:(NSTimeInterval)duration
                                     loopCount:(NSUInteger)loopCount
                                         error:(NSError * __autoreleasing *)error;

@end

/**

 */
extern NSString * const AnimatedGIFImageErrorDomain;

NS_ASSUME_NONNULL_END

#endif
  • 2.2 AnimatedGIFImageSerialization.m

// AnimatedGIFImageSerialization.m
//
// Copyright (c) 2014 – 2019 Mattt (http://mat.tt/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#import "AnimatedGIFImageSerialization.h"

@import ImageIO;
@import MobileCoreServices;

NS_ASSUME_NONNULL_BEGIN

typedef NS_ENUM(NSInteger, AnimatedGifScreenType) {
    AnimatedGifScreenType480h = 480, // iPhone 1, 2, 3, 4, 4s
    AnimatedGifScreenType568h = 568, // iPhone 5, iPhone 5s
    AnimatedGifScreenType667h = 667, // iPhone 6
    AnimatedGifScreenType736h = 736, // iPhone 6+
    AnimatedGifScreenTypeUnknown = 0
};

static NSString * const AnimatedGifScreenTypeSuffix480h = @"";
static NSString * const AnimatedGifScreenTypeSuffix568h = @"-568h";
static NSString * const AnimatedGifScreenTypeSuffix667h = @"-667h";
static NSString * const AnimatedGifScreenTypeSuffix736h = @"-736h";

NSString * const AnimatedGIFImageErrorDomain = @"com.compuserve.gif.image.error";

__attribute__((overloadable)) UIImage * _Nullable UIImageWithAnimatedGIFData(NSData *data) {
    return UIImageWithAnimatedGIFData(data, [[UIScreen mainScreen] scale], 0.0, nil);
}

__attribute__((overloadable)) UIImage * _Nullable UIImageWithAnimatedGIFData(NSData *data, CGFloat scale, NSTimeInterval duration, NSError * __autoreleasing *error) {
    if (!data) {
        return nil;
    }

    NSMutableDictionary<NSString *, id> *mutableOptions = [NSMutableDictionary dictionary];
    mutableOptions[(__bridge NSString *)kCGImageSourceShouldCache] = @(YES);
    mutableOptions[(__bridge NSString *)kCGImageSourceTypeIdentifierHint] = (__bridge NSString *)kUTTypeGIF;

    CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, (__bridge CFDictionaryRef)mutableOptions);

    size_t numberOfFrames = CGImageSourceGetCount(imageSource);
    NSMutableArray<UIImage *> *mutableImages = [NSMutableArray arrayWithCapacity:numberOfFrames];

    NSTimeInterval calculatedDuration = 0.0;
    for (size_t idx = 0; idx < numberOfFrames; idx++) {
        CGImageRef imageRef = CGImageSourceCreateImageAtIndex(imageSource, idx, (__bridge CFDictionaryRef)mutableOptions);

        NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imageSource, idx, NULL);
        NSDictionary *gifProperties = properties[(__bridge NSString *)kCGImagePropertyGIFDictionary];

        NSNumber *delay = gifProperties[(__bridge NSString *)kCGImagePropertyGIFUnclampedDelayTime];
        if (!delay) {
            delay = gifProperties[(__bridge NSString *)kCGImagePropertyGIFDelayTime];
        }

        calculatedDuration += [delay doubleValue];

        [mutableImages addObject:[UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp]];

        CGImageRelease(imageRef);
    }

    CFRelease(imageSource);

    if (numberOfFrames == 1) {
        return [mutableImages firstObject];
    } else {
        return [UIImage animatedImageWithImages:mutableImages duration:(duration <= 0.0 ? calculatedDuration : duration)];
    }
}

static BOOL AnimatedGifDataIsValid(NSData *data) {
    if (data.length > 4) {
        const unsigned char * bytes = [data bytes];

        return bytes[0] == 0x47 && bytes[1] == 0x49 && bytes[2] == 0x46;
    }

    return NO;
}

__attribute__((overloadable)) NSData * _Nullable UIImageAnimatedGIFRepresentation(UIImage *image) {
    return UIImageAnimatedGIFRepresentation(image, 0.0, 0, nil);
}

__attribute__((overloadable)) NSData * _Nullable UIImageAnimatedGIFRepresentation(UIImage *image, NSTimeInterval duration, NSUInteger loopCount, NSError * __autoreleasing *error) {
    if (!image) {
        return nil;
    }

    NSArray<UIImage *> *images = image.images;
    if (!images) {
        images = @[image];
    }

    NSDictionary *userInfo = nil;
    {
        size_t frame_count = images.count;
        NSTimeInterval frameDuration = (duration <= 0.0 ? image.duration / frame_count : duration / frame_count);
        NSUInteger frameDelayCentiseconds = (NSUInteger)lrint(frameDuration * 100);
        NSDictionary<NSString *, id> *frameProperties = @{
                                                          (__bridge NSString *)kCGImagePropertyGIFDictionary: @{
                                                                (__bridge NSString *)kCGImagePropertyGIFDelayTime: @(frameDelayCentiseconds)
                                                            }
                                                         };

        NSMutableData *mutableData = [NSMutableData data];
        CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)mutableData, kUTTypeGIF, frame_count, NULL);

        NSDictionary<NSString *, id> *imageProperties = @{ (__bridge NSString *)kCGImagePropertyGIFDictionary: @{
                                                                (__bridge NSString *)kCGImagePropertyGIFLoopCount: @(loopCount)
                                                            }
                                                         };
        CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)imageProperties);

        for (size_t idx = 0; idx < images.count; idx++) {
            CGImageRef _Nullable cgimage = [images[idx] CGImage];
            if (cgimage) {
                CGImageDestinationAddImage(destination, (CGImageRef _Nonnull)cgimage, (__bridge CFDictionaryRef)frameProperties);
            }
        }

        BOOL success = CGImageDestinationFinalize(destination);
        CFRelease(destination);

        if (!success) {
            userInfo = @{
                         NSLocalizedDescriptionKey: NSLocalizedString(@"Could not finalize image destination", nil)
                        };

            goto _error;
        }

        return [NSData dataWithData:mutableData];
    }
    _error: {
        if (error) {
            *error = [[NSError alloc] initWithDomain:AnimatedGIFImageErrorDomain code:-1 userInfo:userInfo];
        }

        return nil;
    }
}

@implementation AnimatedGIFImageSerialization

+ (UIImage * _Nullable)imageWithData:(NSData *)data
                     error:(NSError * __autoreleasing *)error
{
    return [self imageWithData:data scale:1.0 duration:0.0 error:error];
}

+ (UIImage * _Nullable)imageWithData:(NSData *)data
                               scale:(CGFloat)scale
                            duration:(NSTimeInterval)duration
                               error:(NSError * __autoreleasing *)error
{
    return UIImageWithAnimatedGIFData(data, scale, duration, error);
}

#pragma mark -

+ (NSData * _Nullable)animatedGIFDataWithImage:(UIImage *)image
                                         error:(NSError * __autoreleasing *)error
{
    return [self animatedGIFDataWithImage:image duration:0.0 loopCount:0 error:error];
}

+ (NSData * _Nullable)animatedGIFDataWithImage:(UIImage *)image
                                      duration:(NSTimeInterval)duration
                                     loopCount:(NSUInteger)loopCount
                                         error:(NSError *__autoreleasing *)error
{
    return UIImageAnimatedGIFRepresentation(image, duration, loopCount, error);
}

@end

NS_ASSUME_NONNULL_END

#pragma mark -

#ifndef ANIMATED_GIF_NO_UIIMAGE_INITIALIZER_SWIZZLING
@import ObjectiveC.runtime;

static inline void animated_gif_swizzleSelector(Class class, SEL originalSelector, SEL swizzledSelector) {
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
    if (class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) {
        class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

@interface UIImage (_AnimatedGIFImageSerialization)
@end

@implementation UIImage (_AnimatedGIFImageSerialization)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        @autoreleasepool {
            animated_gif_swizzleSelector(object_getClass((id)self), @selector(imageNamed:), @selector(animated_gif_imageNamed:));
            animated_gif_swizzleSelector(object_getClass((id)self), @selector(imageWithData:), @selector(animated_gif_imageWithData:));
            animated_gif_swizzleSelector(object_getClass((id)self), @selector(imageWithData:scale:), @selector(animated_gif_imageWithData:scale:));
            animated_gif_swizzleSelector(object_getClass((id)self), @selector(imageWithContentsOfFile:), @selector(animated_gif_imageWithContentsOfFile:));
            animated_gif_swizzleSelector(self, @selector(initWithContentsOfFile:), @selector(animated_gif_initWithContentsOfFile:));
            animated_gif_swizzleSelector(self, @selector(initWithData:), @selector(animated_gif_initWithData:));
            animated_gif_swizzleSelector(self, @selector(initWithData:scale:), @selector(animated_gif_initWithData:scale:));
        }
    });
}

#pragma mark -

NS_ASSUME_NONNULL_BEGIN

+ (UIImage * _Nullable)animated_gif_imageNamed:(NSString *)name __attribute__((objc_method_family(new))) {
    CGFloat scale = [[UIScreen mainScreen] scale];
    CGRect screenBounds = [[UIScreen mainScreen] bounds];

    NSString *ratioSuffix = @"";
    switch ((NSUInteger)screenBounds.size.height) {
        case AnimatedGifScreenType480h:
            ratioSuffix = AnimatedGifScreenTypeSuffix480h;
            break;
        case AnimatedGifScreenType568h:
            ratioSuffix = AnimatedGifScreenTypeSuffix568h;
            break;
        case AnimatedGifScreenType667h:
            ratioSuffix = AnimatedGifScreenTypeSuffix667h;
            break;
        case AnimatedGifScreenType736h:
            ratioSuffix = AnimatedGifScreenTypeSuffix736h;
            break;
    }

    NSString *scaleSuffix = @"";
    if (scale >= 3) {
        scaleSuffix = @"@3x";
    } else if (scale >= 2) {
        scaleSuffix = @"@2x";
    }

    NSString * _Nullable path = nil;
    if (!path) {
        // e.g. animated-568h@2x.gif
        NSString *nameWithRatioAndScale = [[[name stringByDeletingPathExtension] stringByAppendingString:ratioSuffix] stringByAppendingString:scaleSuffix];
        path = [[NSBundle mainBundle] pathForResource:nameWithRatioAndScale ofType:[name pathExtension]];
    }

    if (!path) {
        // e.g. animated@2x.gif
        NSString *nameWithRatio = [[[name stringByDeletingPathExtension] stringByAppendingString:scaleSuffix] stringByAppendingPathExtension:[name pathExtension]];
        path = [[NSBundle mainBundle] pathForResource:nameWithRatio ofType:[name pathExtension]];
    }

    if (!path) {
        // e.g. animated.gif
        path = [[NSBundle mainBundle] pathForResource:[name stringByDeletingPathExtension] ofType:[name pathExtension]];
    }

    if (path) {
        NSData *data = [NSData dataWithContentsOfFile:(NSString * _Nonnull)path];
        if (AnimatedGifDataIsValid(data)) {
            return UIImageWithAnimatedGIFData(data);
        }
    }

    return [self animated_gif_imageNamed:name];
}

+ (UIImage * _Nullable)animated_gif_imageWithContentsOfFile:(NSString *)path {
    if (path) {
        NSData *data = [NSData dataWithContentsOfFile:path];
        if (AnimatedGifDataIsValid(data)) {
            if ([[path stringByDeletingPathExtension] hasSuffix:@"@3x"]) {
                return UIImageWithAnimatedGIFData(data, 3.0, 0.0, nil);
            } else if ([[path stringByDeletingPathExtension] hasSuffix:@"@2x"]) {
                return UIImageWithAnimatedGIFData(data, 2.0, 0.0, nil);
            } else {
                return UIImageWithAnimatedGIFData(data);
            }
        }
    }

    return [self animated_gif_imageWithContentsOfFile:path];
}

+ (UIImage * _Nullable)animated_gif_imageWithData:(NSData *)data {
    if (AnimatedGifDataIsValid(data)) {
        return UIImageWithAnimatedGIFData(data);
    }

    return [self animated_gif_imageWithData:data];
}

+ (UIImage * _Nullable)animated_gif_imageWithData:(NSData *)data
                                            scale:(CGFloat)scale {
    if (AnimatedGifDataIsValid(data)) {
        return UIImageWithAnimatedGIFData(data, scale, 0.0, nil);
    }

    return [self animated_gif_imageWithData:data scale:scale];
}

#pragma mark -

- (instancetype)animated_gif_initWithContentsOfFile:(NSString *)path __attribute__((objc_method_family(init))) {
    NSData *data = [NSData dataWithContentsOfFile:path];
    if (AnimatedGifDataIsValid(data)) {
        if ([[path stringByDeletingPathExtension] hasSuffix:@"@3x"]) {
            return UIImageWithAnimatedGIFData(data, 3.0, 0.0, nil);
        } else if ([[path stringByDeletingPathExtension] hasSuffix:@"@2x"]) {
            return UIImageWithAnimatedGIFData(data, 2.0, 0.0, nil);
        } else {
            return UIImageWithAnimatedGIFData(data);
        }
    }

    return [self animated_gif_initWithContentsOfFile:path];
}

- (instancetype)animated_gif_initWithData:(NSData *)data __attribute__((objc_method_family(init))) {
    if (AnimatedGifDataIsValid(data)) {
        return UIImageWithAnimatedGIFData(data);
    }

    return [self animated_gif_initWithData:data];
}

- (instancetype)animated_gif_initWithData:(NSData *)data
                                    scale:(CGFloat)scale __attribute__((objc_method_family(init)))
{
    if (AnimatedGifDataIsValid(data)) {
        return UIImageWithAnimatedGIFData(data, scale, 0.0, nil);
    }

    return [self animated_gif_initWithData:data scale:scale];
}

@end

NS_ASSUME_NONNULL_END

#endif
posted @ 2020-11-12 23:36  CH520  阅读(1949)  评论(0编辑  收藏  举报