如何把 GIF 动图保存到相册?
iOS 的相册是支持保存 GIF 和 APNG 动图的,只是不能直接播放。用 [ALAssetsLibrary writeImageDataToSavedPhotosAlbum:metadata:completionBlock] 可以直接把 APNG、GIF 的数据写入相册。如果图省事直接用 UIImageWriteToSavedPhotosAlbum() 写相册,那么图像会被强制转码为 PNG。
将 UIImage 保存到磁盘,用什么方式最好?
目前来说,保存 UIImage 有三种方式:1.直接用 NSKeyedArchiver 把 UIImage 序列化保存,2.用 UIImagePNGRepresentation() 先把图片转为 PNG 保存,3.用 UIImageJPEGRepresentation() 把图片压缩成 JPEG 保存。
实际上,NSKeyedArchiver 是调用了 UIImagePNGRepresentation 进行序列化的,用它来保存图片是消耗最大的。苹果对 JPEG 有硬编码和硬解码,保存成 JPEG 会大大缩减编码解码时间,也能减小文件体积。所以如果图片不包含透明像素时,UIImageJPEGRepresentation(0.9) 是最佳的图片保存方式,其次是 UIImagePNGRepresentation()。
UIImage 缓存是怎么回事?
通过 imageNamed 创建 UIImage 时,系统实际上只是在 Bundle 内查找到文件名,然后把这个文件名放到 UIImage 里返回,并没有进行实际的文件读取和解码。当 UIImage 第一次显示到屏幕上时,其内部的解码方法才会被调用,同时解码结果会保存到一个全局缓存去。据我观察,在图片解码后,App 第一次退到后台和收到内存警告时,该图片的缓存才会被清空,其他情况下缓存会一直存在。
我要是用 imageWithData 能不能避免缓存呢?
不能。通过数据创建 UIImage 时,UIImage 底层是调用 ImageIO 的 CGImageSourceCreateWithData() 方法。该方法有个参数叫 ShouldCache,在 64 位的设备上,这个参数是默认开启的。这个图片也是同样在第一次显示到屏幕时才会被解码,随后解码数据被缓存到 CGImage 内部。与 imageNamed 创建的图片不同,如果这个图片被释放掉,其内部的解码数据也会被立刻释放。
怎么能避免缓存呢?
1. 手动调用 CGImageSourceCreateWithData() 来创建图片,并把 ShouldCache 和 ShouldCacheImmediately 关掉。这么做会导致每次图片显示到屏幕时,解码方法都会被调用,造成很大的 CPU 占用。
2. 把图片用 CGContextDrawImage() 绘制到画布上,然后把画布的数据取出来当作图片。这也是常见的网络图片库的做法。
我能直接取到图片解码后的数据,而不是通过画布取到吗?
1.CGImageSourceCreateWithData(data) 创建 ImageSource。
2.CGImageSourceCreateImageAtIndex(source) 创建一个未解码的 CGImage。
3.CGImageGetDataProvider(image) 获取这个图片的数据源。
4.CGDataProviderCopyData(provider) 从数据源获取直接解码的数据。
ImageIO 解码发生在最后一步,这样获得的数据是没有经过颜色类型转换的原生数据(比如灰度图像)。
如何判断一个文件的图片类型?
通过读取文件或数据的头几个字节然后和对应图片格式标准进行比对。我在这里写了一个简单的函数,能很快速的判断图片格式。
怎样像浏览器那样边下载边显示图片?
首先,图片本身有 3 种常见的编码方式:
第一种是 baseline,即逐行扫描。默认情况下,JPEG、PNG、GIF 都是这种保存方式。
第二种是 interlaced,即隔行扫描。PNG 和 GIF 在保存时可以选择这种格式。
第三种是 progressive,即渐进式。JPEG 在保存时可以选择这种方式。
在下载图片时,首先用 CGImageSourceCreateIncremental(NULL) 创建一个空的图片源,随后在获得新数据时调用
CGImageSourceUpdateData(data, false) 来更新图片源,最后在用 CGImageSourceCreateImageAtIndex() 创建图片来显示。
你可以用 PINRemoteImage 或者我写的 YYWebImage 来实现这个效果。SDWebImage 并没有用 Incremental 方式解码,所以显示效果很差。
评论 :roll: :roll: :roll: :oops: 仔仔细细看看好好研究研究最后再谢谢
评论 :roll: :roll: 谢谢大神分享,收益良多
受益良多,谢谢分享。
不错,涨知识了,GIF直接保存到相册后,直接发出来还是静态的PNG吧
从相册获取图片时,直接去读 data 二进制数据,就能原封不动的取出来。
请问如何搭建一个属于自己的网站
我想实现直接保存gif图到本地,然后分享,怎么实现?
请教一下,博主是用什么方式测试性能数据的?能开源一个测试工具吗?
P.S.我搞了半天才知道上面的验证码是咋回事。。
吊到没朋友。。。 :sad:
#define YY_FOUR_CC(c1,c2,c3,c4) ((uint32_t)(((c4) << 24) | ((c3) << 16) | ((c2) << 8) | (c1)))
#define YY_TWO_CC(c1,c2) ((uint16_t)(((c2) << 8) | (c1)))
请问这个是什么意思啊?
位运算,简单的说就是0xc4c3c2c1,另外一个就是0xc2c1
请问一下,如果处理 Assets.xcassets中的图片呢?
请问你是如何知道系统api的一些底层信息的呢?比如你知道UIImage 底层是调用 ImageIO 的 CGImageSourceCreateWithData() 方法,还有在界面优化那个篇中你提到calayer的内部实际是没有属性的,请问这些你是如何去知道并且确认的呢?
Instruments 查看调用栈、Symbolic Breakpoint、调试、查看 dump 出来的头文件和函数里列表、网上查资料、猜测等等。
你好,有一个显示大图的问题请教下你。
我现在有一张10000*10000px的图片需要下载并显示,使用SDWebImage会因为直接渲染原图导致内存过高崩溃,PINRemoteImage虽然最终内存会下降至一般状态,但是期间会有一小段时间占用内存有300+。尝试过使用UIGraphicsBeginImageContextWithOptions对下载的图片进行裁剪再显示,内存激增600+,貌似裁剪的时候也涉及到了渲染。后来试了CGImageSourceCreateThumbnailAtIndex利用下载的图片NSData,创建小图,还是不行,效果和PINRemoteImage类似,内存在增加到300+左右会回落。
对于这种情况,请问你有什么建议么?谢谢
对了UIWebView显示图片没有问题,是否可以说在你对它对图片的呈现方式的理解呢?
可以参考苹果官方例子:
https://developer.apple.com/library/ios/samplecode/LargeImageDownsizing/ 另外,在用图片库时,用参数禁用解码。
多谢哈,之前看到了苹果官方的示例,不过看到了它还是使用了UIGraphicsBeginImageContext以为不行,就没下过来运行了,还是粗心了。
SDWebImage好像没有使能解码参数。
还有我想问下,按照你说的,禁用解码,也就是说我尝试的后两种方法,之所以内存会增加到300+,然后再回落是因为解码占用的内存过多么?
请问,这个加载大尺寸图片的问题,你解决了吗?
我也是看了Apple官网的例子,配合YYImageCache内存缓存,是解决了一些问题,但是,当加载图片数目过多时,内存同样高居不下,闪退问题。
如果你已经解决了,有好的办法,还望不吝赐教!
先谢谢了~
您好,YYImage禁用解码的参数是什么?
使用YYWebImage时,当列表页有大量图片而且来回浏览会收到内存警告,App瞬间闪退,有什么好办法吗?下边的方法并没有能避免
YYMemoryCache *memoryCache = [YYMemoryCache new];//生成内存缓存
memoryCache.shouldRemoveAllObjectsOnMemoryWarning = YES;//内存警告的时候删除所有内容
memoryCache.shouldRemoveAllObjectsWhenEnteringBackground = YES;//进入后台删除所有内容
memoryCache.countLimit = NSUIntegerMax;//不予限制
memoryCache.costLimit = NSUIntegerMax;//不予限制
memoryCache.ageLimit = 12 * 60 * 60;//cache存在的时间限制设置为12个小时
我也遇到了同样的问题,你是怎么解决的呢
memoryCache.countLimit = NSUIntegerMax;// 不能设置无限, 举个栗子, 10, 即上限10张图片
memoryCache.costLimit = NSUIntegerMax;//不能设置无限, 举个栗子, 3264 * 2448 * 10,即 800万像素, 10张图片
将无限变为有限, 可以让 cache 不断地删除旧的, 添加新的
您好,我使用YYWebImage从网络上缓存图片存到本地时,除了用Key来取到图片,有什么别的办法可以根据图片的URL来取到图片存在本地的URL吗?
[[YYWebImageManager sharedManager].cache getImageForKey:[[YYWebImageManager sharedManager] cacheKeyForURL:[NSURL URLWithString:@””]] withType:YYImageCacheTypeMemory];
您好,我想请教你个问题:如何查看某个方法调用的更底层的堆栈呢?
请问使用YYWebImage的时候短连接如何处理? 我直接使用yy_setImageWithURL: 这个方法短连接无法加载到图片
一些文章写到通过imageNamed创建图片可以立刻解压图片而不用等到绘制的时候。而楼主在文中写到「通过 imageNamed 创建 UIImage 时,系统实际上只是在 Bundle 内查找到文件名,然后把这个文件名放到 UIImage 里返回,并没有进行实际的文件读取和解码。当 UIImage 第一次显示到屏幕上时,其内部的解码方法才会被调用」这两种说法是否矛盾呢? :arrow: 还望ibireme指教
评论 :x :twisted: :smile:
代码如下,我在用下面的方法下载image的时候,在block中image总是为Nil,stage是cancel状态, 但是将url放到浏览器上面是能够显示的,请问这个如何处理?但是我用afn下载图片的方法就可以下载到图片
[[[UIImageView alloc] init] yy_setImageWithURL:[NSURL URLWithString:[UserParam sharedParam].appSkin.topBannerBackImg] placeholder:nil options:YYWebImageOptionShowNetworkActivity completion:^(UIImage * _Nullable image, NSURL * _Nonnull url, YYWebImageFromType from, YYWebImageStage stage, NSError * _Nullable error) {
if (image) {
[[UINavigationBar appearance] setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];
}
}];
如何将NSURLConnection改成session呢 NSURLConnection貌似不支持http2.0
你好,如果我有一个需求,需要从相册中读取所有的图片并展示,但是每次去相册中去读取太慢,缓存的话又没有分页机制,太占用内存。
我想第一次读取的时候,将图片保存为JPEG(如果不包含透明通道)格式的文件,然后再取的时候从本地的JPEG数据(持久化)中去拿,直接不做内存缓存,博主你认为这样的方式如何呢?
多张gif图片 同时显示 帧速度会变慢 怎么解决?