UIImage+PYJAnimatedGIF.h:

#import <UIKit/UIKit.h>

@interface UIImage (PYJAnimatedGIF)

+ (UIImage * _Nullable)animatedImageWithAnimatedGIFData:(NSData * _Nonnull)theData;

+ (UIImage * _Nullable)animatedImageWithAnimatedGIFURL:(NSURL * _Nonnull)theURL;

+ (UIImage * _Nullable)imageGIFWithName:(NSString * _Nonnull)theName;

+ (UIImage * _Nullable)imageGIFWithURL:(NSURL * _Nonnull)theURL;

+ (UIImage * _Nullable)imageGIFWithData:(NSData * _Nonnull)theData;

@end

UIImage+PYJAnimatedGIF.m:

#import "UIImage+PYJAnimatedGIF.h"
#import <ImageIO/ImageIO.h> #if __has_feature(objc_arc)
#define toCF (__bridge CFTypeRef)
#define fromCF (__bridge id)
#else
#define toCF (CFTypeRef)
#define fromCF (id)
#endif @implementation UIImage (PYJAnimatedGIF) static int delayCentisecondsForImageAtIndex(CGImageSourceRef const source, size_t const i) {
int delayCentiseconds = ;
CFDictionaryRef const properties = CGImageSourceCopyPropertiesAtIndex(source, i, NULL);
if (properties) {
CFDictionaryRef const gifProperties = CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary);
if (gifProperties) {
NSNumber *number = fromCF CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFUnclampedDelayTime);
if (number == NULL || [number doubleValue] == ) {
number = fromCF CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFDelayTime);
}
if ([number doubleValue] > ) {
delayCentiseconds = (int)lrint([number doubleValue] * );
}
}
CFRelease(properties);
}
return delayCentiseconds;
} static void createImagesAndDelays(CGImageSourceRef source, size_t count, CGImageRef imagesOut[count], int delayCentisecondsOut[count]) {
for (size_t i = ; i < count; ++i) {
imagesOut[i] = CGImageSourceCreateImageAtIndex(source, i, NULL);
delayCentisecondsOut[i] = delayCentisecondsForImageAtIndex(source, i);
}
} static int sum(size_t const count, int const *const values) {
int theSum = ;
for (size_t i = ; i < count; ++i) {
theSum += values[i];
}
return theSum;
} static int pairGCD(int a, int b) {
if (a < b)
return pairGCD(b, a);
while (true) {
int const r = a % b;
if (r == )
return b;
a = b;
b = r;
}
} static int vectorGCD(size_t const count, int const *const values) {
int gcd = values[];
for (size_t i = ; i < count; ++i) {
gcd = pairGCD(values[i], gcd);
}
return gcd;
} static NSArray *frameArray(size_t const count, CGImageRef const images[count], int const delayCentiseconds[count], int const totalDurationCentiseconds) {
int const gcd = vectorGCD(count, delayCentiseconds);
size_t const frameCount = totalDurationCentiseconds / gcd;
UIImage *frames[frameCount];
for (size_t i = , f = ; i < count; ++i) {
UIImage *const frame = [UIImage imageWithCGImage:images[i]];
for (size_t j = delayCentiseconds[i] / gcd; j > ; --j) {
frames[f++] = frame;
}
}
return [NSArray arrayWithObjects:frames count:frameCount];
} static void releaseImages(size_t const count, CGImageRef const images[count]) {
for (size_t i = ; i < count; ++i) {
CGImageRelease(images[i]);
}
} static UIImage *animatedImageWithAnimatedGIFImageSource(CGImageSourceRef const source) {
size_t const count = CGImageSourceGetCount(source);
CGImageRef images[count];
int delayCentiseconds[count]; // in centiseconds
createImagesAndDelays(source, count, images, delayCentiseconds);
int const totalDurationCentiseconds = sum(count, delayCentiseconds);
NSArray *const frames = frameArray(count, images, delayCentiseconds, totalDurationCentiseconds);
UIImage *const animation = [UIImage animatedImageWithImages:frames duration:(NSTimeInterval)totalDurationCentiseconds / 100.0];
releaseImages(count, images);
return animation;
} static UIImage *animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceRef CF_RELEASES_ARGUMENT source) {
if (source) {
UIImage *const image = animatedImageWithAnimatedGIFImageSource(source);
CFRelease(source);
return image;
} else {
return nil;
}
} + (UIImage *)animatedImageWithAnimatedGIFData:(NSData *)data {
return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithData(toCF data, NULL));
} + (UIImage *)animatedImageWithAnimatedGIFURL:(NSURL *)url {
return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithURL(toCF url, NULL));
} + (UIImage *)imageGIFWithName:(NSString *)theName {
NSURL *url = [[NSBundle mainBundle] URLForResource:theName withExtension:@"gif"];
return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithURL(toCF url, NULL));
} + (UIImage *)imageGIFWithURL:(NSURL *)theURL {
return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithURL(toCF theURL, NULL));
} + (UIImage *)imageGIFWithData:(NSData *)theData {
return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithData(toCF theData, NULL));
} @end

UIImage+PYJAnimatedGIF的更多相关文章

  1. SDWebImage源码解读 之 UIImage+GIF

    第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...

  2. 聊天气泡 button backgroundImage uiimage 拉伸 stretchableImageWithLeftCapWidth: 方法的使用

    - (UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight:(NSInteger)topCap ...

  3. github源码学习之UIImage+YYWebImage

    UIImage+YYWebImage是YYWebImage(https://github.com/ibireme/YYWebImage)中的一个分类,这个分类封装了一些image常用的变化方法,非常值 ...

  4. 第3月30天 UIImage imageWithContentsOfFile卡顿 Can't add self as subview MPMoviePlayerControlle rcrash

    1. UIImage imageWithContentsOfFile卡顿 [[UIImage alloc] initWithContentsOfFile 卡顿 2.uitableview scroll ...

  5. 使用libjpeg.framework压缩UIImage

    +(void)writeFile:(NSString *)filePath withQuality:(int)quality { //初始化图片参数 UIImage *image=[UIImage i ...

  6. iOS开发之功能模块--长方形UIImage截取中间最大正方形区域

    这里直接用CoreGraphics的一些处理图片的方法,本身不难,但是有些时候用的不多,就会遗忘掉使用方法的细节.下面就直接展示关键源码,以便下次重复需求,就可以立马找回. 该方法中在UIImage的 ...

  7. iOS 分析一个支持GIF的UIImage扩展:SwiftGIF

    Github:https://github.com/bahlo/SwiftGif 这个extension代码不多,主要通过Apple的ImageIO框架进行解析GIF. 整个扩展最核心还是下面的函数, ...

  8. UIImage加载本地图片的两种方式

    UIImage加载图片方式一般有两种: (1)imagedNamed初始化:默认加载图片成功后会内存中缓存图片,这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象.如果缓存中没有找到相应的图片 ...

  9. uiimage 上传 数据库

    之前我所接触的上传图片都是直接与服务器交互的,即 app端要做的就是上传到服务器 现在这个项目却是app先上传到"数据库",由"数据库"传到服务端 下面说主题 ...

随机推荐

  1. OpenCL 学习step by step (5) 使用二维NDRange workgroup

    http://www.cnblogs.com/mikewolf2002/archive/2012/09/07/2675634.html 在本教程中,我们使用二维NDRange来设置workgroup, ...

  2. python_初步

    官网地址:http://www.python.org/ Python最新源码,二进制文档,新闻资讯 Python文档下载地址:www.python.org/doc/ python教程:http://w ...

  3. react-native run-android Starting: Intent Error type 3 Error: Activity class does not exist

    使用”react-native run-android”命令运行android应用时,如果常常出现如下错误: Starting the app (/home/xxx/soft/sdk//platfor ...

  4. yum安装mysql后root用户的临时密码

    1.查看root用户临时随机密码 yum 安装mysql后,无法通过空密码登录数据库,如下: [root@ mysql]# mysql -u root -p Enter password: ERROR ...

  5. iOS开发进阶 - 日志输出框架CocoaLumberjack与XcodeColors插件的简单使用(swift版)

    CocoaLumberjack是Mac和iOS上一个集快捷.简单.强大和灵活于一身的日志框架.XcodeColors是用于控制台着色的工具,配合着CocoaLumberjack用有更好的效果,不废话, ...

  6. BZOJ-5424: 烧桥计划(单调队列)

    BZOJ-5424: 烧桥计划(单调队列) 题目链接 题解: 先考虑最暴力的\(dp\):设\(f[k][i]\)表示搞掉第\(1\sim i\)段,烧了\(k\)段的最小花费,设\(calc(x,y ...

  7. LeetCode——Reverse String

    LeetCode--Reverse String Question Write a function that takes a string as input and returns the stri ...

  8. linux 分析进程占用CPU过高

    重点是查看进程的线程中,哪个线程占用cpu过高,然后用gdb附加到进程,调试线程,看是否有死循环或者死锁等问题,步骤如下: 1 先用ps + grep找出该死的进程pid,比如 1706 2 top ...

  9. XML DOM解析 基础概念

    DOM和SAX W3C制定了一套书写XML分析器的标准接口规范——DOM. 除此以外,XML_DEV邮件列表中的成员根据应用的需求也自发地定义了一套对XML文档进行操作的接口规范——SAX. 这两种接 ...

  10. RENOUNCEMENT

    I must not think of thee;and,tired yet syrong,I shun the thought that lurks in all delight--The thou ...