Apple Color List格式(CLR)如何工作?

时间:2018-03-20 08:22:36

标签: macos colors reverse-engineering

我正在尝试解析.clr文件中的颜色数据,该文件在mac上用于存储系统范围的调色板。我使用Affinity Designer创建了一个测试文件,然后将其存储在~/Library/Colors中。我试着用不同的颜色来玩,然后弄清楚颜色值是如何存储在文件中的,但是无论我尝试什么颜色,我总是会得到非常奇怪的结果,这些结果似乎与所讨论的颜色几乎完全无关。

例如,我保存了一种名为"测试2"这只是一个完整的黑色(#000000)。然后该文件包含颜色的名称作为UTF8-String,因此我可以看到颜色的存储位置。

在第一种颜色的名称之前,有一个较长的字符串,只在文件的开头出现一次,无论它包含多少颜色,所以我想这应该是标题。

在颜色名称之后,在第二种颜色的名称之前有几个字节的二进制数据,所以我认为必须是颜色数据。但真正奇怪的是,所述数据块包含

����������;����;���@<����

fffd fffd fffd fffd fffd 1 fffd fffd fffd fffd fffd 3b fffd fffd fffd fffd 3b fffd fffd fffd 40 3c 1 fffd fffd fffd fffd 6

采用十六进制格式,仅适用于黑色。 然而,第二种颜色等于颜色#010101,具有二进制数据

��������

fffd fffd fffd fffd fffd 1 fffd fffd fffd

我无法理解这种文件格式如何存储颜色数据,广泛的研究也没有带来任何有用的结果,这符合我的问题。

1 个答案:

答案 0 :(得分:1)

正如@TomDoodler对这个问题的评论,.clr文件是NSColorList类的序列化。

我写了一个MacOS操场,它打开.clr文件并打印出颜色名称和RGB值。我想为颜色创建camelCase名称,所以这就是为什么我添加了字符串扩展名。

对于Swift 4。

import Cocoa

extension String {
    func lowercasedFirstLetter() -> String {
        return prefix(1).lowercased() + dropFirst()
    }

    mutating func lowercaseFirstLetter() {
        self = self.lowercasedFirstLetter()
    }
}

func floatToInt(_ f : CGFloat) -> Int {
    return Int(f * 255)
}

let colorList = NSColorList.init(name: "clr", fromFile: "/Path/To/Yourfile.clr")
if let allKeys = colorList?.allKeys {
    for key in allKeys {
        if let color = colorList?.color(withKey: key) {
            let red = floatToInt(color.redComponent)
            let green = floatToInt(color.greenComponent)
            let blue = floatToInt(color.blueComponent)
            let hexString = NSString(format: "#%02X%02X%02X", red, green, blue)
            let name = key.description.replacingOccurrences(of: " ", with: "").lowercasedFirstLetter()
            print(name, red, green, blue, hexString)
            // print("static let \(name) = UIColor.init(\"\(hexString)\")")
       }
     }
}