UIImage+PYJAnimatedGIF
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的更多相关文章
- SDWebImage源码解读 之 UIImage+GIF
第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...
- 聊天气泡 button backgroundImage uiimage 拉伸 stretchableImageWithLeftCapWidth: 方法的使用
- (UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight:(NSInteger)topCap ...
- github源码学习之UIImage+YYWebImage
UIImage+YYWebImage是YYWebImage(https://github.com/ibireme/YYWebImage)中的一个分类,这个分类封装了一些image常用的变化方法,非常值 ...
- 第3月30天 UIImage imageWithContentsOfFile卡顿 Can't add self as subview MPMoviePlayerControlle rcrash
1. UIImage imageWithContentsOfFile卡顿 [[UIImage alloc] initWithContentsOfFile 卡顿 2.uitableview scroll ...
- 使用libjpeg.framework压缩UIImage
+(void)writeFile:(NSString *)filePath withQuality:(int)quality { //初始化图片参数 UIImage *image=[UIImage i ...
- iOS开发之功能模块--长方形UIImage截取中间最大正方形区域
这里直接用CoreGraphics的一些处理图片的方法,本身不难,但是有些时候用的不多,就会遗忘掉使用方法的细节.下面就直接展示关键源码,以便下次重复需求,就可以立马找回. 该方法中在UIImage的 ...
- iOS 分析一个支持GIF的UIImage扩展:SwiftGIF
Github:https://github.com/bahlo/SwiftGif 这个extension代码不多,主要通过Apple的ImageIO框架进行解析GIF. 整个扩展最核心还是下面的函数, ...
- UIImage加载本地图片的两种方式
UIImage加载图片方式一般有两种: (1)imagedNamed初始化:默认加载图片成功后会内存中缓存图片,这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象.如果缓存中没有找到相应的图片 ...
- uiimage 上传 数据库
之前我所接触的上传图片都是直接与服务器交互的,即 app端要做的就是上传到服务器 现在这个项目却是app先上传到"数据库",由"数据库"传到服务端 下面说主题 ...
随机推荐
- sublime批量替换文本重复单词
事先需要把单词打到文本的每一行 排序 按F9或者选择菜单:Edit > Sort Lines,对每行文本进行排序 查找重复行 排序好后,按Ctrl+F,调出查找面板 查找字符串: ^(.+)$[ ...
- jenkins添加GIT repository报错
添加了ssh互信,但一直提示如下错误. Failed to connect to repository : Command "git ls-remote -h git@git.xxx.cn: ...
- golang解析json报错:invalid character '\x00' after top-level value
golang解析json报错:invalid character '\x00' after top-level value 手动复制字符串:{"files":["c:/t ...
- viewport大白话
以下所有内容均是我自己理解的,可能有误,懂得大佬希望指点一下我.. 首先,写一个简单的页面.里面只有1个200*200的div <html lang="en"> < ...
- 《Maven实战》第5章 坐标和依赖
5.1 Maven坐标——项目唯一标识 groupId(必须定义):定义Mavan项目隶属的实际项目,如SpringFramework,一个实际项目可包含多个Maven项目 artifactId(必须 ...
- Spring_事务(1)
- 查看linuxCPU信息
linux 下查看机器是cpu是几核的 几个cpu more /proc/cpuinfo |grep "physical id"|uniq|wc -l 每个cpu是几核(假设cpu ...
- 判断iframe页面是否是顶层页面
if (self!=top) { window.parent.location.reload();}
- Flume-NG源码阅读之FileChannel
FileChannel是flume一个非常重要的channel组件,非常常用.这个channel非常复杂,涉及的文件更多涉及三个包:org.apache.flume.channel.file.org. ...
- yii2:多条件多where条件下碰到between时,between语句如何处理呢?
yii2:多条件多where条件下碰到between时,between语句如何处理呢? 我有一张表:id,name,telphone,ticket_no,status,create_time等字段, ...