Swift 通常可以使用 Core Graphics 转换图片格式,但是 Core Graphics 框架原生支持的格式有限:JPEG、PNG、TIFF、GIF、BMP等格式,不支持WebP格式。
在使用Core Graphics时,会遇到转换失败的情况:
let destination = CGImageDestinationCreateWithData(outputData, imageType, 1, nil)
这是因为当前系统没有注册UTType对应的Image Destination编码。
在macOS中,macOS 12及以下版本不支持读取WebP格式图片,macOS 13+版本支持读取WebP,但是不支持写入WebP格式图片。
转换WebP解决方案
方案1:使用SDWebImageWebPCoder
在Xcode中导入SDWebImageWebPCoder,添加到对应项目。
Swift代码:
// WebP 专用压缩方法
private func compressToWebP(image: NSImage,url: URL) -> Bool {
// 注册 WebP 编码器
SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared)
// 将 NSImage 转换为 CGImage
guard let tiffData = image.tiffRepresentation,
let source = CGImageSourceCreateWithData(tiffData as CFData, nil),
let cgImage = CGImageSourceCreateImageAtIndex(source, 0, nil) else {
print("无法获取 CGImage")
return false
}
// 使用 SDWebImage 编码为 WebP
let coder = SDImageWebPCoder.shared
// 设置压缩质量
let options: [SDImageCoderOption: Any] = [
.encodeCompressionQuality: appStorage.imageCompressionRate
]
guard let webpData = coder.encodedData(
with: NSImage(cgImage: cgImage, size: image.size),
format: .webP,
options: options
) else {
print("WebP 编码失败")
return
}
// 写入 WebP 数据
do {
try webpData.write(to: url)
return
} catch {
return
}
}
方案2:调用cwebp可执行文件
Homebrew默认安装动态链接版webp,在Xcode中配置动态链接非常复杂,涉及多个动态库的导入,这里不推荐使用动态链接版。
1、下载静态编译版cwebp:
// 下载源码
git clone https://chromium.googlesource.com/webm/libwebp
cd libwebp
// 安装 autotools
brew reinstall autoconf automake libtool
// 生成配置
./autogen.sh
// 配置为“仅静态链接”
./configure --disable-shared --enable-static
// 编译并生成文件
make -j$(sysctl -n hw.ncpu)
// 验证静态编译版
otool -L examples/cwebp
// 正确结果只会输出 libSystem.B.dylib,这是系统库,可以忽略
/usr/lib/libSystem.B.dylib
2、终端使用方法:
cwebp input.jpg -q 80 -o output.webp
3、文件签名
如果Xcode启用Sandbox和Hardened Runtime支持,还需要给文件签名:
codesign --force --options runtime \
--entitlements "/path/to/entitlements.plist" \
--sign "Developer ID Application: xxx" \
"/path/to/可执行文件路径"
4、集成到Xcode项目
将cwebp可执行文件,拖入Xcode项目中。
Swift调用cwebp代码:
func compressWithCWebP(inputURL: URL,
outputURL: URL,
quality: Int) -> Bool {
guard let toolPath = Bundle.main.path(forResource: "cwebp",
ofType: nil,
inDirectory: "tools") else {
print("找不到 cwebp 工具")
return false
}
let process = Process()
process.executableURL = URL(fileURLWithPath: toolPath)
process.arguments = [
inputURL.path,
"-q", "80",
"-o", outputURL.path
]
let pipe = Pipe()
process.standardError = pipe
process.standardOutput = pipe
do {
try process.run()
process.waitUntilExit()
if process.terminationStatus == 0 {
return true
} else {
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let msg = String(data: data, encoding: .utf8) ?? ""
print("cwebp 失败:", msg)
return false
}
} catch {
print("执行 cwebp 失败:", error)
return false
}
}
cwebp配置信息
1、质量控制
有损压缩质量:
-q <0–100>
75–80:最佳性价比
85:高质量
90+:体积增长明显,不推荐默认
2、无损模式
-lossless
可以配合压缩级别使用:
-z <0–9>
// 示例
-lossless -z 6
3、压缩强度
-m <0–6>
0表示最快、4表示中等、6表示最小体积,压缩速度最慢。
4、多线程
-mt
5、去除元数据(可减小体积)
-metadata none
或者:
-metadata exif
6、图像尺寸缩放
-resize <width> <height>
// 示例
-resize 1024 768
注意事项
cwebp目前仅支持PNG、JPEG、WebP、PNM格式的图片,如果压缩其他格式(TIFF),会报错并返回退出码 1。
TIFF support not compiled.
Please install the libtiff development package before building.
总结
macOS原生无法编码WebP,因此需要第三方库如cwebp实现WebP的编码工作。
