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. JSP与Servlet之前台页面自动回复之实现

    [JSP与Servlet之前台页面自动回复之实现] 该内容 来自于imooc的一个视屏教程.http://www.imooc.com/video/4562 就是当点击 发送 的时候把这个对话框内容添加 ...

  2. 使用Python实现基于图像识别的iOS自动化测试

    相对于Android来说,iOS比较封闭.这一点,在设计和评估自动化测试方案的时候感觉尤其强烈.iOS平台上没有特别好用的自动化测试工具.苹果针对iOS提供了UI Automation的Instrum ...

  3. 解决You have new mail in /var/spool/mail/root提示

    终端远程登陆后经常提示You have new mail in /var/spool/mail/root 这个提示是LINUX会定时查看LINUX各种状态做汇总,每经过一段时间会把汇总的信息发送的ro ...

  4. MySQL 数据(数据库)迁移

    查找MySQL真正的Data目录 show variables like 'datadir'; +---------------+-----------------+ | Variable_name ...

  5. JMS-activeMq点对点模式

    上一篇对JMS进行介绍了一下,接下来总结一下activemq点对点模式以及订阅发布模式. (1)下载:首先到官网http://activemq.apache.org下载activemq (2)运行:解 ...

  6. JavaWeb -- Struts1 多文件上传与下载 DownloadAction, DispatchAction

    1. 多文件上传与下载 上传下载jsp: <%@ page language="java" import="java.util.*" pageEncodi ...

  7. Pow,求x的y次幂

    算法分析:很显然用递归.但是直接用递归会造成栈溢出,时间复杂度是o(n).所以要用分治思想,时间复杂度是o(logN). public class Power { //栈溢出,时间复杂度是o(n) p ...

  8. java8 函数接口 Predicate例子

    import java.util.HashSet; import java.util.Collection; import java.util.function.Predicate; public c ...

  9. cmake手册

    cmake手册 部分转载自:http://www.cnblogs.com/coderfenghc/tag/cmake/ CMake2.8.3 主索引 命令名称 用法 描述 命令选项 生成器 命令 属性 ...

  10. mysql查询结果带上序号

    select (@i:=@i+1) as rownum,t1.id ","from mega_user t1,(select @i:=0) t2 order by t1.gold ...