Files
QLAppBundle/AssetCarReader/AssetCarReader.swift
2025-11-01 22:17:36 +01:00

86 lines
3.1 KiB
Swift

import Foundation
import AppKit // NSImage
private import CoreUI // CUICatalog
private import os // OSLog
private let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "AssetCarReader")
public class CarReader {
private let catalog: CUICatalog
public init?(_ data: Data) {
do {
catalog = try data.withUnsafeBytes { try CUICatalog(bytes: $0.baseAddress!, length: UInt64(data.count)) }
} catch {
os_log(.error, log: log, "[asset-car] ERROR: could not open catalog: %{public}@", error.localizedDescription)
return nil
}
}
/// Use `CUICatalog` to extract an image from `Assets.car`
public func imageFromAssetsCar(_ imageName: String) -> NSImage? {
if let validName = verifyNameExists(imageName, in: catalog) {
if let bestImage = findHighestResolutionIcon(catalog.images(withName: validName)) {
os_log(.debug, log: log, "[asset-car] using Assets.car with key %{public}@", validName)
return NSImage(cgImage: bestImage.image, size: bestImage.size)
}
}
return nil;
}
// MARK: - Private methods
/// Helper method to check available icon names. Will return a valid name or `nil` if no image with that key is found.
private func verifyNameExists(_ imageName: String, in catalog: CUICatalog) -> String? {
if let availableNames = catalog.allImageNames(), !availableNames.contains(imageName) {
// Theoretically this should never happen. Assuming the image name is found in an image file.
os_log(.info, log: log, "[asset-car] WARN: key '%{public}@' does not match any available key", imageName)
if let alternativeName = searchAlternativeName(imageName, inAvailable: availableNames) {
os_log(.info, log: log, "[asset-car] falling back to '%{public}@'", alternativeName)
return alternativeName
}
os_log(.debug, log: log, "[asset-car] available keys: %{public}@", catalog.allImageNames() ?? [])
return nil
}
return imageName;
}
/// If exact name does not exist in catalog, search for a name that shares the same prefix.
/// E.g., "AppIcon60x60" may match "AppIcon" or "AppIcon60x60_small"
private func searchAlternativeName(_ originalName: String, inAvailable availableNames: [String]) -> String? {
var bestOption: String? = nil
var bestDiff: Int = 999
for option in availableNames {
if option.hasPrefix(originalName) || originalName.hasPrefix(option) {
let thisDiff = max(originalName.count, option.count) - min(originalName.count, option.count)
if thisDiff < bestDiff {
bestDiff = thisDiff
bestOption = option
}
}
}
return bestOption
}
/// Given a list of `CUINamedImage`, return the one with the highest resolution. Vector graphics are ignored.
private func findHighestResolutionIcon(_ availableImages: [CUINamedImage]) -> CUINamedImage? {
var largestWidth: CGFloat = 0
var largestImage: CUINamedImage? = nil
// cast to NSArray is necessary as otherwise this will crash
for img in availableImages as NSArray {
guard let img = img as? CUINamedImage else {
continue // ignore CUINamedMultisizeImageSet
}
let w = img.size.width
if w > largestWidth {
largestWidth = w
largestImage = img
}
}
return largestImage
}
}