SwiftUI转换WebP格式图片
SwiftUI转换WebP格式图片

SwiftUI转换WebP格式图片

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/可执行文件路径"

详细请见《Xcode打包报错:App sandbox not enabled. The following executables must include the “com.apple.security.app-sandbox” entitlement with a Boolean value of true in the entitlements property list》。

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.

详细请见《Xcode打包报错:App sandbox not enabled. The following executables must include the “com.apple.security.app-sandbox” entitlement with a Boolean value of true in the entitlements property list》。

总结

macOS原生无法编码WebP,因此需要第三方库如cwebp实现WebP的编码工作。

相关文章

1、Swift使用core-graphics转换图片格式

2、SDWebImageWebPCoder

3、Xcode打包报错:App sandbox not enabled. The following executables must include the “com.apple.security.app-sandbox” entitlement with a Boolean value of true in the entitlements property list

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注