极乌客

我的一些笔记和日记

Swift 通过执行二进制文件增强功能

Swift 使用 Process 可以执行二进制文件从而实现一定功能,例如下面的完整 图片压缩 例子

pngquant 原本是没有 Swift 版本的,在我之前开发的的 macOS 原生 SwiftUI 版本切图上传工具中的图片压缩功能,手动实现起来极其复杂而且效果可能很差,所以使用了这种方法,目前稳定使用了数月

大致步骤:

  1. 读取内置二进制文件 Bundle.main.path(forResource: "pngquant", ofType: nil)
  2. 创建 Process 实例 let process = Process()
  3. 在 Process 中指定二进制文件 process.executableURL = URL(fileURLWithPath: oxipngPath)
  4. 加入参数 process.arguments = ["--quality", "0-70", "--force", "-o", outputFilePath, inputFilePath]
  5. 创建管道 let pipe = Pipe(); process.standardOutput = pipe
  6. 启动进程 try process.run(); process.waitUntilExit()
  7. 非必要 读取输出_ = pipe.fileHandleForReading.readDataToEndOfFile()
  8. 在执行结束后进行下一步操作 if process.terminationStatus == 0 { // 结束 }

import Foundation

// 获取指定路径的文件大小
func fileSize(atPath path: String) -> UInt64? {
    do {
        // 尝试获取指定路径文件的属性
        let attributes = try FileManager.default.attributesOfItem(atPath: path)
        // 返回文件大小属性(如果存在),并转换为 UInt64 类型
        return attributes[.size] as? UInt64
    } catch {
        // 如果无法获取文件属性,则打印错误信息
        print("无法获取文件大小: \(error)")
        return nil
    }
}

// 使用 pngquant 压缩文件并计算压缩效果
func compress(url: String, outputPath: String) -> (originalFileSize: UInt64?, compressedFileSize: UInt64?, compressionRate: Double?) {
    // 尝试在应用程序包中找到 pngquant 二进制文件的路径
    guard let oxipngPath = Bundle.main.path(forResource: "pngquant", ofType: nil) else {
        fatalError("无法找到 pngquant 二进制文件")
    }

    // 使用 fileSize 函数获取原始文件大小
    guard let originalFileSize = fileSize(atPath: url) else {
        print("无法获取原始文件大小")
        return (nil, nil, nil)
    }

    // 设置 Process 以运行 pngquant 命令
    let process = Process()
    process.executableURL = URL(fileURLWithPath: oxipngPath)
    // 定义 pngquant 命令的参数
    process.arguments = ["--quality", "0-70", "--force", "-o", outputPath, url]

    do {
        // 尝试运行该进程
        try process.run()
        // 等待进程完成
        process.waitUntilExit()

        // 检查进程是否成功完成
        if process.terminationStatus == 0, let compressedFileSize = fileSize(atPath: outputPath) {
            // 计算压缩率(百分比)
            let compressionRate = Double(originalFileSize - compressedFileSize) / Double(originalFileSize) * 100
            // 返回原始大小、压缩后大小和压缩率
            return (originalFileSize, compressedFileSize, compressionRate.rounded())
        } else {
            // 如果优化失败,打印错误信息
            print("PNG 优化失败")
            return (originalFileSize, nil, nil)
        }
    } catch {
        // 如果进程启动失败,打印错误信息
        print("启动失败: \(error)")
        return (originalFileSize, nil, nil)
    }
}

 

Golang 可选参数实现

上一篇
评论
发表评论 说点什么
还没有评论