SDWebImageSVGCoder

CI Status Version License Platform Carthage compatible

背景

目前,SDWebImage 组织提供 3 种 SVG Coder 插件支持,以下是比较:

插件名称 矢量图像 位图图像 平台 兼容性 依赖
SVGNativeCoder iOS 9+ 最佳且符合 W3C 标准 adobe/svg-native-viewer
SVGCoder iOS 13+ 可以,但在某些 SVG 上存在 Bug Apple CoreSVG (私有)
SVGKitPlugin iOS 9+ 最差,不再维护 SVGKit/SVGKit

作用

SDWebImageSVGCoder 是 SDWebImage 框架的一个 SVG coder 插件,为 SVG 提供图像加载支持。

SVG 渲染使用 Apple 的 CoreSVG.framework 框架(iOS 13/macOS 10.15 中引入)。

SVGKit 用户请注意

在 1.0.0 版本之前,此 SVG Coder 由第三方库 SVGKit 提供支持。它也支持 iOS 8+ (macOS 10.10+)。

但是,由于该第三方库缺乏支持,包含大量问题且没有社区帮助,版本发布也不明确,这给我们维护带来了痛苦。因此,我们决定弃用 SVGKit 支持并将其移至另一个仓库:SDWebImageSVGKitPlugin

使用 SVGKit 或必须支持 iOS 8+ (macOS 10.10+) 的用户仍然可以使用 SDWebImageSVGKitPlugin。您也可以同时混合使用这两种 SVG coder。但由于 Apple 已经提供了一个内置框架支持,我们更喜欢使用它,这可以减少复杂的依赖关系、代码大小,并从 Apple 的系统升级中受益。

CoreSVG 框架注意事项

到目前为止(Xcode 11.4 && iOS 13.4),CoreSVG.framework 仍然是私有框架。我已经发送了反馈雷达以请求公开此框架。如果可以,请帮助我们发送雷达并向 Apple 请求:https://feedbackassistant.apple.com/

CoreSVG.framework API 是稳定的,并且与 CoreGraphics 的 PDF API 概念相同,因此没有理由保持私有。我们已经提交了使用 CoreSVG 在 App Store 上渲染矢量图像的应用程序。

我们在此处使用的所有 SPI 访问都使用运行时访问和早期检查,即使未来的操作系统升级破坏了该功能,此框架也不会使您的应用程序崩溃,只会加载失败。我将持续更新,以适应每个固件更新的最新变化。

如果您仍然担心 SPI 的使用,可以使用 SDWebImageSVGKitPlugin。但我们可能不会响应与 SVGKit 相关的任何解析器或渲染问题,因为它已经不再维护。

还有另一种解决方案:SVG-Native,这是 Adobe 的一项新的 W3C 标准,它是 SVG/1.1 的一个子集。Apple/Google/Microsoft 已经加入对该标准的协议,您可以尝试使用来自 SVG-native-viewer 的代码编写自己的 coder,并为矢量图像采用 SVG-native。

警告:一些用户报告说,Apple 的 CoreSVG 在某些 SVG 上存在兼容性问题(例如使用非系统字体、渐变),从 v1.7.0 开始,我们保护了一些情况,但其他异常情况是无法捕获的。对于这些崩溃,要么使用将 SVG 渲染为位图图像(见下文),要么编辑您的 SVG 源文件以使 Apple 的 CoeSVG 兼容。

示例

要运行示例项目,请克隆该存储库,并首先从 Example 目录运行pod install

您可以修改代码或使用一些其他 SVG 文件来检查兼容性。

要求

安装

CocoaPods

SDWebImageSVGCoder 可通过 CocoaPods 获得。 要安装它,只需将以下行添加到您的 Podfile 中

pod 'SDWebImageSVGCoder'

Carthage

SDWebImageSVGCoder 可通过 Carthage 获得。

github "SDWebImage/SDWebImageSVGCoder"

Swift Package Manager

SDWebImageSVGCoder 可通过 Swift Package Manager 获得。

let package = Package(
    dependencies: [
        .package(url: "https://github.com/SDWebImage/SDWebImageSVGCoder.git", from: "1.4.0")
    ]
)

用法

将 SVG 渲染为矢量图像

要使用 SVG coder,您应首先将 SDImageSVGCoder 添加到 coders 管理器。 然后,您可以调用 View Category 方法来开始加载 SVG 图像。 有关这些步骤,请参见此处的 Wiki - Coder Usage

请注意,SVG 是一种 矢量图像 格式,并且 UIImageView/NSImageView 也支持渲染矢量图像。 这意味着您可以更改大小而不会丢失任何细节。

// register coder, on AppDelegate
SDImageSVGCoder *SVGCoder = [SDImageSVGCoder sharedCoder];
[[SDImageCodersManager sharedManager] addCoder:SVGCoder];
// load SVG url
UIImageView *imageView;
[imageView sd_setImageWithURL:url]
// Changing size
CGRect rect = imageView.frame;
rect.size.width = 200;
rect.size.height = 200;
imageView.frame = rect;
// register coder, on AppDelegate
let SVGCoder = SDImageSVGCoder.shared
SDImageCodersManager.shared.addCoder(SVGCoder)
// load SVG url
let imageView: UIImageView
imageView.sd_setImage(with: url)
// Changing size
var rect = imageView.frame
rect.size.width = 200
rect.size.height = 200
imageView.frame = rect

请注意,由于 UIImageView/NSImageView 支持这种矢量渲染,因此这意味着此 coder 插件可以与 SwiftUI 兼容。 有关用法,请检查 SDWebImageSwiftUI

注意:对于 watchOS,它不支持 UIKit,因此您不能使用矢量图像格式。(包括 SVG 和 PDF)

将 SVG 渲染为位图图像

在大多数情况下,矢量 SVG 是首选。 但是,有时您可能需要 SVG 的位图形式,用于图像处理或 watchOS。

默认情况下,它使用 SVG viewBox 大小。您还可以使用 .imageThumbnailPixelSize 上下文选项在图像加载期间指定所需的大小。您可以使用 .imagePreserveAspectRatio 上下文选项指定缩放期间是否保持纵横比。

注意:使用 imageThumbnailPixelSize 时,传递 0 作为宽度或高度将删除此长度的限制。例如,给定一个原始大小为 (40,50) 的 SVG 图像

保持纵横比 宽度 高度 效果
50 50 (40,50)
0 100 (80,100)
20 0 (20,25)
0 0 (40,50)
50 50 (50,50)
0 100 (40,100)
20 0 (20,50)
0 0 (40,50)

注意:一旦您传递了 imageThumbnailPixelSize,我们将始终生成位图表示形式。 如果您确实需要矢量格式,请不要传递它们,让 UIImageView 动态拉伸 SVG。

UIImageView *imageView;
CGSize bitmapSize = CGSizeMake(500, 500);
[imageView sd_setImageWithURL:url placeholderImage:nil options:0 context:@{SDWebImageContextThumbnailPixelSize: @(bitmapSize)];
let imageView: UIImageView
let bitmapSize = CGSize(width: 500, height: 500)
imageView.sd_setImage(with: url, placeholderImage: nil, options: [], context: [.imageThumbnailPixelSize : bitmapSize])

导出 SVG 数据

SDWebImageSVGCoder 提供了一种简单的方法来将此 coder 插件生成的 SVG 图像导出到原始 SVG 数据。

注意:SVG 的位图形式不支持 SVG 数据导出。

UIImage *svgImage; // UIImage with vector image, or NSImage contains `NSSVGImageRep`
if (svgImage.sd_isVector) { // This API available in SDWebImage 5.6.0
    NSData *svgData = [svgImage sd_imageDataAsFormat:SDImageFormatSVG];
}
let svgImage: UIImage // UIImage with vector image, or NSImage contains `NSSVGImageRep`
if svgImage.sd_isVector { // This API available in SDWebImage 5.6.0
    let svgData = svgImage.sd_imageData(as: .SVG)
}

CoreSVG 框架的兼容性

当存在 fill 颜色时,CSS opacity 无法应用

<path d="M399.8,68.2c77.3,3.1,160.6,32.1" opacity="0.15" fill="rgb(29,36,60)" />

应用程序崩溃。

<path d="M399.8,68.2c77.3,3.1,160.6,32.1" fill="rgba(29,36,60,0.15)" />

向后兼容性

此框架支持在 iOS 12-/macOS 10.14- 上的向后兼容。 并且您可以将 SDWebImageSVGCoder 用于更高的固件版本,将 SDWebImageSVGKitPlugin 用于更低的固件版本。

对于 CocoaPods 用户,您可以使用以下方法跳过 Podfile 中的平台版本验证

platform :ios, '13.0' # This does not effect your App Target's deployment target version, just a hint for CocoaPods

请注意,您应始终使用运行时版本检查来确保这些符号可用,您还应使用 API_AVAILABLE 注释标记所有使用公共 API 的类。 见下文

if (@available(iOS 13, *)) {
    [SDImageCodersManager.sharedCoder addCoder:SDImageSVGCoder.sharedCoder];
} else {
    [SDImageCodersManager.sharedCoder addCoder:SDImageSVGKCoder.sharedCoder];
}

屏幕截图

这些 SVG 图像来自 wikimedia,您也可以使用自己的 SVG 图像尝试该演示。

作者

DreamPiggy

许可证

SDWebImageSVGCoder 在 MIT 许可下可用。 有关更多信息,请参见 LICENSE 文件。