当前位置: 首页 > 编程日记 > 正文

源码阅读:SDWebImage(六)——SDWebImageCoderHelper

该文章阅读的SDWebImage的版本为4.3.3。

这个类提供了四个方法,这四个方法可分为两类,一类是动图处理,一类是图像方向处理。

1.私有函数

先来看一下这个类里的两个函数

/**这个函数是计算两个整数a和b的最大公约数*/
static NSUInteger gcd(NSUInteger a, NSUInteger b) {NSUInteger c;while (a != 0) {c = a;a = b % a;b = c;}return b;
}
复制代码
/**这个函数是计算一个整数数组的最大公约数*/
static NSUInteger gcdArray(size_t const count, NSUInteger const * const values) {if (count == 0) {return 0;}NSUInteger result = values[0];for (size_t i = 1; i < count; ++i) {result = gcd(values[i], result);}return result;
}
复制代码

2.动图相关方法

/**将元素为SDWebImageFrame对象的数组转换为动图*/
+ (UIImage * _Nullable)animatedImageWithFrames:(NSArray<SDWebImageFrame *> * _Nullable)frames;
复制代码
+ (UIImage *)animatedImageWithFrames:(NSArray<SDWebImageFrame *> *)frames {// 如果数组中没有元素就不是动图就直接返回nilNSUInteger frameCount = frames.count;if (frameCount == 0) {return nil;}// 生成临时变量保存动图UIImage *animatedImage;#if SD_UIKIT || SD_WATCH// 生成一个元素类型为非负整数,长度为动图帧数的数组,保存每一帧的展示时间NSUInteger durations[frameCount];for (size_t i = 0; i < frameCount; i++) {// 遍历传入的SDWebImageFrame对象数组,获取每一帧的展示时间durations[i] = frames[i].duration * 1000;}// 计算所有帧展示时长的最大公约数NSUInteger const gcd = gcdArray(frameCount, durations);// 生成临时变量保存总时长__block NSUInteger totalDuration = 0;// 生成临时变量保存动图数组NSMutableArray<UIImage *> *animatedImages = [NSMutableArray arrayWithCapacity:frameCount];// 遍历传入的SDWebImageFrame对象数组[frames enumerateObjectsUsingBlock:^(SDWebImageFrame * _Nonnull frame, NSUInteger idx, BOOL * _Nonnull stop) {// 获取SDWebImageFrame对象保存的每一帧的图像UIImage *image = frame.image;// 获取SDWebImageFrame对象保存的每一帧的展示时间NSUInteger duration = frame.duration * 1000;// 增加总时长totalDuration += duration;// 生成临时变量保存重复次数NSUInteger repeatCount;// 如果计算出的最大公约数大于零,每一帧的重复次数就是展示时间除以最大公约数// 否则每一帧只重复一次,也就说不重复if (gcd) {repeatCount = duration / gcd;} else {repeatCount = 1;}// 根据重复次数向动图数组中重复添加同一帧for (size_t i = 0; i < repeatCount; ++i) {[animatedImages addObject:image];}}];// 利用生成的动图数组和时长生成动图对象animatedImage = [UIImage animatedImageWithImages:animatedImages duration:totalDuration / 1000.f];#elseNSMutableData *imageData = [NSMutableData data];CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatGIF];// Create an image destination. GIF does not support EXIF image orientationCGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, frameCount, NULL);if (!imageDestination) {// Handle failure.return nil;}for (size_t i = 0; i < frameCount; i++) {@autoreleasepool {SDWebImageFrame *frame = frames[i];float frameDuration = frame.duration;CGImageRef frameImageRef = frame.image.CGImage;NSDictionary *frameProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary : @{(__bridge_transfer NSString *)kCGImagePropertyGIFDelayTime : @(frameDuration)}};CGImageDestinationAddImage(imageDestination, frameImageRef, (__bridge CFDictionaryRef)frameProperties);}}// Finalize the destination.if (CGImageDestinationFinalize(imageDestination) == NO) {// Handle failure.CFRelease(imageDestination);return nil;}CFRelease(imageDestination);SDAnimatedImageRep *imageRep = [[SDAnimatedImageRep alloc] initWithData:imageData];animatedImage = [[NSImage alloc] initWithSize:imageRep.size];[animatedImage addRepresentation:imageRep];
#endifreturn animatedImage;
}
复制代码

/**将动图转换为元素为SDWebImageFrame对象的数组,是上面那个方法的逆方法*/
+ (NSArray<SDWebImageFrame *> * _Nullable)framesFromAnimatedImage:(UIImage * _Nullable)animatedImage;
复制代码
+ (NSArray<SDWebImageFrame *> *)framesFromAnimatedImage:(UIImage *)animatedImage {// 如果没传参就不继续执行了,直接返回空if (!animatedImage) {return nil;}// 生成临时变量保存SDWebImageFrame对象和数量NSMutableArray<SDWebImageFrame *> *frames = [NSMutableArray array];NSUInteger frameCount = 0;#if SD_UIKIT || SD_WATCH// 获取动图的帧图片数组NSArray<UIImage *> *animatedImages = animatedImage.images;// 获取动图的帧图片数量frameCount = animatedImages.count;// 如果帧图片的数量为0就不继续执行了,直接返回空if (frameCount == 0) {return nil;}// 计算每一帧的平均展示时间NSTimeInterval avgDuration = animatedImage.duration / frameCount;// 如果这个动图没有展示时间就默认每一帧展示100毫秒if (avgDuration == 0) {avgDuration = 0.1; }// 记录不同帧图片的数量__block NSUInteger index = 0;// 记录一帧图片重复次数__block NSUInteger repeatCount = 1;// 记录当前遍历到的图片之前的图片__block UIImage *previousImage = animatedImages.firstObject;[animatedImages enumerateObjectsUsingBlock:^(UIImage * _Nonnull image, NSUInteger idx, BOOL * _Nonnull stop) {// 第一张图片不处理if (idx == 0) {return;}if ([image isEqual:previousImage]) {// 如果这一帧的图片和之前一帧图片相同就添加重复次数repeatCount++;} else {// 如果两帧图片不相同,就生成SDWebImageFrame对象SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:previousImage duration:avgDuration * repeatCount];// 数组记录对象[frames addObject:frame];// 重复次数设置为一次repeatCount = 1;// 记录不同的帧数自增index++;}// 记录当前图片,用于下次遍历使用previousImage = image;// 如果是最后一张照片就直接添加if (idx == frameCount - 1) {SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:previousImage duration:avgDuration * repeatCount];[frames addObject:frame];}}];#elseNSBitmapImageRep *bitmapRep;for (NSImageRep *imageRep in animatedImage.representations) {if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) {bitmapRep = (NSBitmapImageRep *)imageRep;break;}}if (bitmapRep) {frameCount = [[bitmapRep valueForProperty:NSImageFrameCount] unsignedIntegerValue];}if (frameCount == 0) {return nil;}for (size_t i = 0; i < frameCount; i++) {@autoreleasepool {// NSBitmapImageRep need to manually change frame. "Good taste" API[bitmapRep setProperty:NSImageCurrentFrame withValue:@(i)];float frameDuration = [[bitmapRep valueForProperty:NSImageCurrentFrameDuration] floatValue];NSImage *frameImage = [[NSImage alloc] initWithCGImage:bitmapRep.CGImage size:CGSizeZero];SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:frameImage duration:frameDuration];[frames addObject:frame];}}
#endifreturn frames;
}
复制代码

3.图像方向处理相关方法

/**将EXIF图像方向转换为iOS版本的方向*/
+ (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation;
复制代码
+ (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation {// CGImagePropertyOrientation在iOS8上才可用,这里是为了保持兼容性UIImageOrientation imageOrientation = UIImageOrientationUp;// 根据不同参数返回不同类型switch (exifOrientation) {case 1:imageOrientation = UIImageOrientationUp;break;case 3:imageOrientation = UIImageOrientationDown;break;case 8:imageOrientation = UIImageOrientationLeft;break;case 6:imageOrientation = UIImageOrientationRight;break;case 2:imageOrientation = UIImageOrientationUpMirrored;break;case 4:imageOrientation = UIImageOrientationDownMirrored;break;case 5:imageOrientation = UIImageOrientationLeftMirrored;break;case 7:imageOrientation = UIImageOrientationRightMirrored;break;default:break;}return imageOrientation;
}
复制代码

/**将iOS版本的方向转换为EXIF图像方向*/
+ (NSInteger)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation;
复制代码
+ (NSInteger)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation {NSInteger exifOrientation = 1;// 根据不同类型返回不同数字switch (imageOrientation) {case UIImageOrientationUp:exifOrientation = 1;break;case UIImageOrientationDown:exifOrientation = 3;break;case UIImageOrientationLeft:exifOrientation = 8;break;case UIImageOrientationRight:exifOrientation = 6;break;case UIImageOrientationUpMirrored:exifOrientation = 2;break;case UIImageOrientationDownMirrored:exifOrientation = 4;break;case UIImageOrientationLeftMirrored:exifOrientation = 5;break;case UIImageOrientationRightMirrored:exifOrientation = 7;break;default:break;}return exifOrientation;
}
复制代码

源码阅读系列:SDWebImage

源码阅读:SDWebImage(一)——从使用入手

源码阅读:SDWebImage(二)——SDWebImageCompat

源码阅读:SDWebImage(三)——NSData+ImageContentType

源码阅读:SDWebImage(四)——SDWebImageCoder

源码阅读:SDWebImage(五)——SDWebImageFrame

源码阅读:SDWebImage(六)——SDWebImageCoderHelper

源码阅读:SDWebImage(七)——SDWebImageImageIOCoder

源码阅读:SDWebImage(八)——SDWebImageGIFCoder

源码阅读:SDWebImage(九)——SDWebImageCodersManager

源码阅读:SDWebImage(十)——SDImageCacheConfig

源码阅读:SDWebImage(十一)——SDImageCache

源码阅读:SDWebImage(十二)——SDWebImageDownloaderOperation

源码阅读:SDWebImage(十三)——SDWebImageDownloader

源码阅读:SDWebImage(十四)——SDWebImageManager

源码阅读:SDWebImage(十五)——SDWebImagePrefetcher

源码阅读:SDWebImage(十六)——SDWebImageTransition

源码阅读:SDWebImage(十七)——UIView+WebCacheOperation

源码阅读:SDWebImage(十八)——UIView+WebCache

源码阅读:SDWebImage(十九)——UIImage+ForceDecode/UIImage+GIF/UIImage+MultiFormat

源码阅读:SDWebImage(二十)——UIButton+WebCache

源码阅读:SDWebImage(二十一)——UIImageView+WebCache/UIImageView+HighlightedWebCache

相关文章:

基于 OpenCV 的网络实时视频流传输

作者 | 努比来源 | 小白学视觉大多数人会选择使用IP摄像机&#xff08;Internet协议摄像机&#xff09;而不是CCTV&#xff08;闭路电视&#xff09;&#xff0c;因为它们具有更高的分辨率并降低了布线成本。在本文中&#xff0c;我们将重点介绍IP摄像机。IP摄像机是一种数字 摄…

【转】让Chrome化身成为摸鱼神器,利用Chorme运行布卡漫画以及其他安卓APK应用教程...

下周就是十一了&#xff0c;无论是学生党还是工作党&#xff0c;大家的大概都会有点心不在焉&#xff0c;为了让大家更好的心不在焉&#xff0c;更好的在十一前最后一周愉快的摸鱼&#xff0c;今天就写一个如何让Chrome&#xff08;google浏览器&#xff09;运行安卓APK应用的教…

PHP安装parsekit扩展查看opcode

也可以通过VLD查看&#xff0c;具体请看本人写的http://blog.csdn.net/21aspnet/article/details/7002644安装parsekit扩展 http://pecl.php.net/package/parsekit 下载最新的 #wget http://pecl.php.net/get/parsekit-1.3.0.tgz 安装过程省略 可以参考 本人写的http://blog.c…

group by 查找订单的最新状态 join

Order&#xff1a;snProcedures&#xff1a;sn,status1、 有订单表和流程表。订单表含有订单的详细信息【假设没有订单状态哈】&#xff0c;每个订单有好多种状态&#xff1a;已付款、处理中、待收货等等。现在的需求可能是查询订单状态是待收货的所有订单的信息。【答】先找到…

Xcache安装与使用

官网&#xff1a;http://xcache.lighttpd.net 最新版本下载地址&#xff1a;http://xcache.lighttpd.net/wiki/Release-1.3.2 安装&#xff1a; # wget http://xcache.lighttpd.net/pub/Releases/1.3.2/xcache-1.3.2.tar.gz # tar zvxf xcache-1.3.2.tar.gz # cd xcache-1.3…

安装mysql_python的适合遇到mysql_config not found解决方案(mac)

为什么80%的码农都做不了架构师&#xff1f;>>> 安装mysql_python的适合遇到mysql_config not found解决方案&#xff08;mac&#xff09; 用pip安装MySQL-python时候遇到报错&#xff1a; ------我是分割线------ Complete output from command python setup.py e…

推荐 6 个好用到爆的 Pycharm 插件

作者 | 小欣来源 | Python爱好者集中营相信对于不少的Python程序员们都是用Pycharm作为开发时候的IDE来使用的&#xff0c;今天小编来分享几个好用到爆的Pycharm插件&#xff0c;在安装上之后&#xff0c;你的编程效率、工作效率都能够得到极大地提升。安装方法插件的安装方法一…

Kibana 用户指南(使用Flight仪表盘探索Kibana)

使用Flight仪表盘探索Kibana 你是Kibana的新手并希望尝试一下&#xff0c;只需单击一下&#xff0c;你就可以安装Flights样本数据并开始与Kibana交互。 Flight数据集包含四家航空公司的数据&#xff0c;你可以从Kibana主页加载数据和预配置的仪表盘。 在主页上&#xff0c;单击…

php扩展xdebug安装以及用kcachegrind系统分析

一&#xff1a;安装 安装方法一&#xff1a;编译安装1、下载PHP的XDebug扩展&#xff0c;网址&#xff1a;http://xdebug.org/# wget http://pecl.php.net/get/xdebug-2.1.2.tgz# tar -xzf xdebug-2.1.2.tgz# xdebug-2.1.2# cd xdebug-2.1.2# /usr/local/php/bin/phpize# ./con…

Meta AI 新研究,统一模态的自监督新里程碑

作者 | 青苹果来源 | 数据实战派虽然 AI 领域不断涌现出新的突破和进展&#xff0c;却始终难以逃离单一领域的束缚——一种用于个性化语音合成的新颖方法&#xff0c;却并不能用于识别人脸的表情。为了解决这个问题&#xff0c;不少研究人员正在致力于开发功能更强大、应用更广…

细说Debug和Release区别

VC下Debug和Release区别 最近写代码过程中&#xff0c;发现 Debug 下运行正常&#xff0c;Release 下就会出现问题&#xff0c;百思不得其解&#xff0c;而Release 下又无法进行调试&#xff0c;于是只能采用printf方式逐步定位到问题所在处&#xff0c;才发现原来是给定的一个…

26期20180601目录管理

6月1日任务2.1/2.2 系统目录结构2.3 ls命令2.4 文件类型2.5 alias命令系统目录结构ls - list所有的用户在系统里都有自己的家目录&#xff0c;比如现在登陆的是root用户&#xff0c;登陆进去就是在root的家目录中&#xff0c;可以看到之前创建的公钥文件也是在这。但是如果是其…

thttpd安装与调试

http://www.acme.com/software/thttpd/ thttpd是一个非常小巧的轻量级web server&#xff0c;它非常非常简单&#xff0c;仅仅提供了HTTP/1.1和简单的CGI支持&#xff0c;在其官方网站上有一个与其他web server&#xff08;如Apache, Zeus等&#xff09;的对比图Benchmark&…

7 款可替代 top 命令的工具!(二)

作者 | JackTian来源 | 杰哥的IT之旅上一篇文章中给大家介绍了《11 款可替代 top 命令的工具&#xff01;》&#xff0c;今天我再来给大家推荐 7 款可替代 top 命令的工具&#xff0c;看完这两篇替代品的文章相信能让你对 Linux 操作系统下一个小小的命令大开眼界。一、atopato…

Error:Execution failed for task ':app:dexDebug'. com.android.ide.common.process.ProcessException

异常Log&#xff1a; Error:Execution failed for task ‘:app:dexDebug’. > com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process ‘command ‘/Library/……/java” finished with non-zero exit value 2 错误原因&am…

# 学号 2017-2018-20172309 《程序设计与数据结构》第十一周学习总结

---恢复内容开始--- 学号 2017-2018-20172309 《程序设计与数据结构》第十一周学习总结 教材学习内容总结 第23章 初识Android操作系统&#xff1a;一个多用户的Linux系统&#xff0c;一个运用程序运行时与其他的运用运行是独立的。发展&#xff1a;在Android4.4之前所有的应用…

php扩展xdebug基本使用

官网&#xff1a;http://www.xdebug.org/ 使用&#xff1a;http://www.xdebug.org/docs/安装 http://blog.csdn.net/21aspnet/article/details/7036087使用1.获取文件名&#xff0c;行号&#xff0c;函数名 xdebug_call_class() <?php function fix_string($a) { …

基于 Opencv 实现眼睛控制鼠标

作者 | 小白来源 | 小白学视觉如何用眼睛来控制鼠标&#xff1f;一种基于单一前向视角的机器学习眼睛姿态估计方法。在此项目中&#xff0c;每次单击鼠标时&#xff0c;我们都会编写代码来裁剪你们的眼睛图像。使用这些数据&#xff0c;我们可以反向训练模型&#xff0c;从你们…

linux 安装安装rz/sz 和 ssh

安装rz&#xff0c;sz yum install lrzsz; 安装ssh yum install openssh-server 查看已安装包 rpm -qa | grep ssh 更新yum源 1、备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2、下载新的CentOS-Base.repo 到/etc/yum.repos.d/ CentO…

css左固定右自适应常用方法

下面是几种方法的公用部分&#xff08;右自适应也是一样的&#xff0c;换一下方向&#xff09; html: <div class"demo"> <div class"sidebar">我是固定的</div> <div class"content">我是自适应的</div> </di…

nginx或httpd实现负载均衡tomcat(三)

接博客nginx或httpd实现反向代理tomcat并实现会话保持&#xff08;二&#xff09;实例四&#xff1a;使用httpd负载均衡后端tomcat服务第一步&#xff1a;准备两个tomcat服务器节172.16.240.203修改tomcat的server.xml配置文件&#xff0c;添加一个host。<Host name"to…

为 PHP 应用提速、提速、再提速

原文地址&#xff1a; http://www.ibm.com/developerworks/cn/opensource/os-php-fastapps1/ http://www.ibm.com/developerworks/cn/opensource/os-php-fastapps2/index.html为 PHP 应用提速、提速、再提速&#xff01;PHP 是一种脚本语言&#xff0c;常用于创建 Web 应用程序…

冬奥会夺金的背后杀手锏,竟是位 AI 虚拟教练

整理 | 禾木木 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 近日&#xff0c;一则消息登上了热搜&#xff1a; 2月14日晚&#xff0c;在北京冬奥会自由式滑雪女子空中技巧决赛中&#xff0c;徐梦桃为中国代表团再添一金。她选择了难度系数4.293的动作&#xff0c…

Socket-实例

import socket,os,time server socket.socket() server.bind(("localhost",9999)) server.listen()while True:conn,addrserver.accept()print("new conn",addr)while True:print("等待新指令")data conn.recv(1024)if not data:print("客…

kcachegrind安装

http://kcachegrind.sourceforge.net/cgi-bin/show.cgi/KcacheGrindDownload http://hi.baidu.com/wangxinhui419/blog/item/4a7409c78c22b4c8d100608a.html http://wxiner.blog.sohu.com/156841393.html说明&#xff1a;linux下如果安装不上&#xff0c;直接下载windows版的吧…

Java【小考】

课上&#xff0c; 老师出了一个题: 考察&#xff1a;1、类的定义 2、类的属性 3、类的方法、重载、构造方法、代码块 题目是这样的&#xff1a; 设计 一个 类&#xff1a;Tree 要求&#xff1a; 1、包含main方法 2、属性&#xff1a;静态&#xff1a; String name ; double hei…

首个深度强化学习AI,能控制核聚变,成功登上《Nature》

编译 | 禾木木 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 最近&#xff0c;DeepMind 开发出了世界上第一个深度强化学习 AI &#xff0c;可以在模拟环境和真正的核聚变装置中实现对等离子体的自主控制。 这项研究成果登上了《Nature》杂志。 托卡马克是一种用于…

windows下安装mysql8.0压缩版

下面总结下安装过程&#xff1a; 首先解压下载好的压缩版本。将解压后mysql的bin文件目录配置系统环境path变量中使用cmd打开命令窗口&#xff0c;输入mysqld --initialize命令初始化mysql的data数据目录&#xff0c;记住初始化完毕后&#xff0c;会在解压目录下生成一个data文…

Linux实时监控工具Nmon使用

官网&#xff1a;http://nmon.sourceforge.net/pmwiki.php?nMain.HomePage 下载&#xff1a;http://sourceforge.net/projects/nmon/files/nmon_linux_14g.tar.gz 解压&#xff1a; #chmod ux nmon_x86_64_sles11 #chmod 777 nmon_x86_64_sles11 版本不同&#xff0c;对应文件…

英特尔2022年投资者大会:公布技术路线图及重要节点

在英特尔2022年投资者大会上&#xff0c;英特尔CEO帕特基辛格和各业务部门负责人概述了公司发展战略及长期增长规划的主要内容。在半导体需求旺盛的时代&#xff0c;英特尔的多项长期规划将充分把握转型增长的机遇。在演讲中&#xff0c;英特尔公布了其主要业务部门的产品路线图…