BBWebImage
一个用于异步下载、缓存和编辑网页图片的高性能 Swift 库。
示例
简单下载、显示和缓存图片。
下载图片。在下载过程中解码、编辑并显示图片。下载后,将编辑后的图片缓存到内存,并将原始图像数据缓存到磁盘。
- 添加滤镜
- 绘制圆角和边框
性能
测试库是 BBWebImage (1.1.0),SDWebImage (4.4.6 和 FLAnimatedImage 1.0.12 用于 GIF),YYWebImage (1.0.5) 和 Kingfisher (4.10.1)。测试设备是运行 iOS 12.1 的 iPhone 7。代码可以在 CompareImageLib 项目中找到,测试结果数据可以在 CompareImageLib.numbers 中找到。
- BBWebImage 具有高速的内存和磁盘缓存,尤其是缩略图图片。
- BBWebImage 在加载和显示 GIF 时消耗的 CPU 和内存较低。
功能
- 为
UIImageView
、UIButton
、MKAnnotationView
和CALayer
添加视图扩展以从 URL 设置图片 - 异步图像下载器
- 异步内存+文件+SQLite 图像缓存,使用最近最少使用算法
- 异步图像解压缩
- 异步图像编辑,不修改原始图像磁盘数据
- 动画图像智能解码、解压缩、编辑和缓存
- 独立使用的独立图片缓存、下载器、编码器和编辑器
- 定制的图片缓存、下载器和编码器
- 高性能
为什么要使用
解决SDWebImage的问题
SDWebImage 是一个用于下载和缓存网络图片的强大库。当 BBWebImage 的第一个版本(0.1.0)发布时,SDWebImage 的最新版本是 4.4.3,它不包含强大的图像编辑功能。如果我们使用 SDWebImage 4.4.3 下载图片并编辑它,将会出现以下问题:
- 编辑后的图片被缓存了,但是原始图片数据丢失。如果我们想显示它,需要重新下载原始图片。
- 原始图片数据被缓存在磁盘上。如果我们不缓存的编辑图片,我们需要每次显示编辑后的图片都要编辑图片。如果我们既缓存编辑后的图片到内存和磁盘,我们需要编写更多代码并管理缓存键。如果我们只缓存编辑后的图片到内存,当我们获取缓存的图片时,我们需要通过检查它在哪缓存来知道它是否被编辑过。
- 如果我们使用
Core Graphics
编辑图像,我们应该禁用 SDWebImage 图像解压缩(因为解压缩没有必要。编辑和解压缩有类似的步骤:创建CGContext
、绘制图像、创建新图像),稍后再次启用。
BBWebImage 诞生就是为了解决这些问题。
- 原始图片数据缓存在磁盘上,原始或编辑后的图片缓存在内存中。
UIImage
与一个编辑键相关联,这是一个表示图像如何编辑的字符串。编辑键对原始图像为 nil。当我们从网络或缓存加载图像时,我们可以传递BBWebImageEditor
来获取编辑后的图像。BBWebImageEditor 指定如何编辑图像,并包含将与编辑后的图像相关联的编辑键。如果内存缓存的图像的编辑键与 BBWebImageEditor 的编辑键相同,则内存缓存的图像就是我们需要的;或者 BBWebImage 将加载和编辑原始图像并将编辑后的图像缓存到内存中。如果我们想获取原始图像,不要传递 BBWebImageEditor。我们不会下载图像超过一次。我们不需要编写更多代码来缓存编辑后的图像或检查图像是否被编辑。 - 如果我们加载原始图像,BBWebImage 将默认解压缩图像。如果我们使用 BBWebImageEditor 加载图像,BBWebImage 将使用编辑器编辑图像而不会解压缩。我们不需要编写更多代码来启用或禁用图像解压缩。
智能地编辑动画图像和缓存
为了显示动画图像,我们需要解码图像帧,根据帧持续时间更改帧。我们使用 BBAnimatedImage
管理动画图像数据,使用 BBAnimatedImageView
播放动画。BBAnimatedImageView 决定要显示或解码的帧。BBAnimatedImage 在后台解码和缓存图像帧。最大缓存大小是动态计算的,并且缓存会自动清除。
BBAnimatedImage 使用 BBWebImageEditor 来编辑图像帧。BBAnimatedImage 有一个属性 bb_editor
,它是一个可选的 BBWebImageEditor 类型。将编辑器设置为属性以显示编辑后的图像帧,或将nil设置为属性以显示原始图像帧。
要求
- iOS 8.0+
- Swift 4.2
安装
使用 CocoaPods 安装
- 将
pod 'BBWebImage'
添加到您的 Podfile 中。添加pod 'BBWebImage/MapKit'
以兼容 MKAnnotationView 扩展。添加pod 'BBWebImage/Filter'
以使用图像过滤器。 - 运行
pod install
或pod update
。 - 将
import BBWebImage
添加到 Swift 源文件中。
使用方法
视图扩展
最简单的方法是使用 URL
为 UIImageView
设置图像
imageView.bb_setImage(with: url)
下面的代码
- 下载高分辨率图像
- 按照预期的最大分辨率和图像视图大小进行下采样和裁剪
- 绘制时使用圆角、边框和背景颜色
- 下载和编辑后显示编辑后的图像
- 在下载之前显示占位符图像
- 以增量方式解码图像并在下载过程中显示
- 下载过程中执行某些操作
- 将原始图像数据缓存到磁盘,缓存编辑后的图像到内存
- 加载完成后执行某些操作
let editor = bb_imageEditorCommon(with: imageView.frame.size,
maxResolution: 1024 * 1024,
corner: .allCorners,
cornerRadius: 5,
borderWidth: 1,
borderColor: .yellow,
backgroundColor: .gray)
let progress = { (data: Data?, expectedSize: Int, image: UIImage?) -> Void in
// Do something while downloading
}
imageView.bb_setImage(with: url,
placeholder: UIImage(named: "placeholder"),
options: .progressiveDownload,
editor: editor,
progress: progress)
{ (image: UIImage?, data: Data?, error: Error?, cacheType: BBImageCacheType) in
// Do something when finish loading
}
bb_setImage(with:)
方法的参数 options
是 BBWebImageOptions
,一个选项集。使用它来控制下载、缓存、解码和显示的一些行为。值 .progressiveDownload
表示在下载时渐进式显示图像。默认值是 .none
。
bb_setImage(with:)
方法的参数 editor
是一个可选的结构体 BBWebImageEditor
。传递 nil 来显示原始图像。还有其他内置编辑器可供选择。请参阅内置图像编辑器。
为了支持 GIF,将 UIImageView
替换为 BBAnimatedImageView
。BBAnimatedImageView 是 UIImageView 的子类。BBAnimatedImageView 支持静态图像和动画图像。
要支持其他图像格式或更改默认的编码/解码行为,请参阅支持的图像格式。
图像管理器
要在没有在视图中显示的情况下从缓存或网络获取图像,请使用 BBWebImageManager
的 loadImage(with:)
方法。此方法返回一个 BBWebImageLoadTask
对象。要取消任务,请调用任务的 cancel()
方法。
let progress = { (data: Data?, expectedSize: Int, image: UIImage?) -> Void in
// Do something while downloading
}
BBWebImageManager.shared.loadImage(with: url,
options: options,
editor: editor,
progress: progress)
{ (image: UIImage?, data: Data?, error: Error?, cacheType: BBImageCacheType) in
// Do something when finish loading
}
图像缓存
要从缓存获取图像或数据,请使用 BBLRUImageCache
的 image(forKey:)
方法。要仅从内存/磁盘获取图像或数据,将 .memory
或 .disk
传递给 cacheType
。
BBWebImageManager.shared.imageCache.image(forKey: key,
cacheType: .all)
{ (result: BBImageCacheQueryCompletionResult) in
switch result {
case let .memory(image: image): // Do something with memory image
case let .disk(data: data): // Do something with disk data
case let .all(image: image, data: data): // Do something with image and data
default: // Do something when no image or data
}
}
要存储图像或数据到缓存,请使用 store(_:)
方法。要仅存储图像或数据到内存/磁盘,将 .memory
或 .disk
传递给 cacheType
。
BBWebImageManager.shared.imageCache.store(image,
data: data,
forKey: key,
cacheType: .all)
{
// Do something after storing
}
要从缓存中移除图像或数据,请使用 removeImage(forKey:)
方法。要仅从内存/磁盘中移除图像或数据,将 .memory
或 .disk
传递给 cacheType
。
BBWebImageManager.shared.imageCache.removeImage(forKey: key,
cacheType: .all)
{
// Do something after removing
}
要从缓存中移除所有图像或数据,请使用 clear(_:)
方法。要从内存/磁盘中移除所有图像或数据,将 .memory
或 .disk
传递给第一个参数。
BBWebImageManager.shared.imageCache.clear(.all) {
// Do something after clearing
}
图像下载器
要下载图像数据,请使用 BBMergeRequestImageDownloader
的 download(with:)
方法。此方法返回一个遵守 BBImageDownloadTask
协议的任务。要取消任务,请调用下载器的 cancel(task:)
方法,并将任务作为参数传递。要取消所有下载任务,请调用下载器的 cancelAll()
方法。
let progress = { (data: Data?, expectedSize: Int, image: UIImage?) -> Void in
// Do something while downloading
}
BBWebImageManager.shared.imageDownloader.downloadImage(with: url,
options: options,
progress: progress)
{ (data: Data?, error: Error?) in
// Do something with data or error
}
图片编码器
要从数据中获取解码后的图像(不进行解压缩),请使用BBImageCoderManager
的decodedImage(with:)
方法。该方法返回一个可选的UIImage
对象。如果图像是BBAnimatedImage
,则它是一个可在BBAnimatedImageView
上显示的动画图像。如果图像是静态图像,则不会被解压缩。使用decompressedImage(with:
方法对其进行解压缩以进行显示。
let coder = BBWebImageManager.shared.imageCoder
if let decodedImage = coder.decodedImage(with: data) {
// Do something with decoded image
if let animatedImage = decodedImage as? BBAnimatedImage {
// Do something with animated image
} else if let decompressedImage = coder.decompressedImage(with: decodedImage, data: data) {
// Do something with decompressed image
} else {
// Can not decompress image
}
} else {
// Can not decode image data
}
要将图像编码为特定格式,请使用encodedData(with:)
方法。
if let data = coder.encodedData(with: image, format: .PNG) {
// Do something with data
} else {
// Can not encode data
}
要支持其他图像格式或更改默认的编码/解码行为,请参阅支持的图像格式。
支持的图片格式
- JPEG
- PNG
- GIF
要支持其他图片格式或更改默认的编码/解码行为,请自定义图片编码器。实现一个新的符合BBImageCoder
协议的编码器。获取旧编码器并进行更改。
if let coderManager = BBWebImageManager.shared.imageCoder as? BBImageCoderManager {
let oldCoders = coderManager.coders
let newCoders = ...
coderManager.coders = newCoders
}
内置图片编辑器
结构BBWebImageEditor
定义了如何在内存中编辑和缓存图像。以下是一些内置的图片编辑器
编辑器 | 描述 | 创建方法 |
---|---|---|
通用 | 使用期望的最大分辨率、视图大小和内容模式裁剪和调整图像大小。绘制圆角、边框和背景颜色。 | bb_commonEditedImage(with:) |
裁剪 | 将图像裁剪为特定矩形。 | bb_croppedImage(with:) |
调整大小 | 将图像调整到特定大小,或使其适应视图大小和内容模式。 | bb_resizedImage(with:) |
旋转 | 使用给定的角度旋转图像。 | bb_rotatedImage(withAngle:) |
翻转 | 水平或垂直翻转图像。 | bb_flippedImage(withHorizontal:) |
着色 | 使用颜色着色图像。 | bb_tintedImage(with:) |
渐变着色 | 使用渐变色着色图像。 | bb_gradientlyTintedImage(with:) |
叠加 | 将图像叠加到另一图像上。 | bb_overlaidImage(with:) |
颜色查找 | 使用颜色查找图像重新映射图像颜色。 | bb_imageEditorCILookupTestFilter(maxTileSize:) 在示例中 |
架构
许可证
BBWebImage采用MIT许可证发布。详细信息请参见LICENSE。