#!/usr/bin/env swift import AppKit import Foundation struct HandConfig { let sourcePath: String let outputDirectoryName: String let frameCount: Int let sourceWidth: CGFloat let sourceHeight: CGFloat let pivotX: CGFloat let pivotY: CGFloat let digits: Int let angleStep: CGFloat } enum AssetError: Error, CustomStringConvertible { case invalidImage(String) case pngEncodingFailed(String) var description: String { switch self { case let .invalidImage(path): return "无法读取图片:\(path)" case let .pngEncodingFailed(path): return "无法编码 PNG:\(path)" } } } let fileManager = FileManager.default let workingDirectory = URL(fileURLWithPath: fileManager.currentDirectoryPath, isDirectory: true) let repoRoot = CommandLine.arguments.count > 1 ? URL(fileURLWithPath: CommandLine.arguments[1], isDirectory: true) : workingDirectory let outputRoot = CommandLine.arguments.count > 2 ? URL(fileURLWithPath: CommandLine.arguments[2], isDirectory: true) : repoRoot.appendingPathComponent("assets/kindle-clock", isDirectory: true) let faceSourceURL = repoRoot.appendingPathComponent("assets/clock-face.png") let targetSize = NSSize(width: 220, height: 220) let faceSourceSize = NSSize(width: 431, height: 431) let scale = targetSize.width / faceSourceSize.width let handConfigs = [ HandConfig( sourcePath: "assets/hour-hand.png", outputDirectoryName: "hour-hand", frameCount: 720, sourceWidth: 32, sourceHeight: 205, pivotX: 13, pivotY: 138, digits: 3, angleStep: 0.5 ), HandConfig( sourcePath: "assets/minite-hand.png", outputDirectoryName: "minute-hand", frameCount: 60, sourceWidth: 32, sourceHeight: 288, pivotX: 15, pivotY: 203, digits: 2, angleStep: 6 ), ] func loadImage(at url: URL) throws -> NSImage { guard let image = NSImage(contentsOf: url) else { throw AssetError.invalidImage(url.path) } return image } func savePNG(_ image: NSImage, to url: URL) throws { guard let tiffRepresentation = image.tiffRepresentation, let bitmap = NSBitmapImageRep(data: tiffRepresentation), let pngData = bitmap.representation(using: .png, properties: [:]) else { throw AssetError.pngEncodingFailed(url.path) } try fileManager.createDirectory( at: url.deletingLastPathComponent(), withIntermediateDirectories: true ) try pngData.write(to: url) } func renderImage(size: NSSize, draw: () -> Void) -> NSImage { let image = NSImage(size: size) image.lockFocusFlipped(true) NSColor.clear.setFill() NSBezierPath(rect: NSRect(origin: .zero, size: size)).fill() draw() image.unlockFocus() return image } func renderFace() throws { let faceImage = try loadImage(at: faceSourceURL) let renderedFace = renderImage(size: targetSize) { faceImage.draw( in: NSRect(origin: .zero, size: targetSize), from: NSRect(origin: .zero, size: faceImage.size), operation: .sourceOver, fraction: 1 ) } try savePNG(renderedFace, to: outputRoot.appendingPathComponent("clock-face.png")) } func renderHandFrames(config: HandConfig) throws { let sourceURL = repoRoot.appendingPathComponent(config.sourcePath) let handImage = try loadImage(at: sourceURL) let outputDirectory = outputRoot.appendingPathComponent(config.outputDirectoryName, isDirectory: true) let scaledWidth = config.sourceWidth * scale let scaledHeight = config.sourceHeight * scale let scaledPivotX = config.pivotX * scale let scaledPivotY = config.pivotY * scale try fileManager.createDirectory(at: outputDirectory, withIntermediateDirectories: true) for frameIndex in 0..