I am trying to parse the color data from a .clr file, which is used on mac to store system wide color palettes. I created a test file using Affinity Designer, which is then stored in ~/Library/Colors
. I tried playing around with different colors to then get a clue how the colorvalues are stored in the file, but whatever color I tried, I always get really strange results which seem to be almost completely unrelated to the color in question.
For example, I saved a color called "Test 2" which is just a complete black (#000000). The file then contains the name of the color as a UTF8-String, so I can see where the color is stored.
Before the name of the first color there is a longer string which only appears once at the beginning of the file, no matter how many colors it contains, so I guess this should be the header.
After the name of the color, there are a few bytes of binary data before the name of the second color, so I assumed that has to be the color data. But what is really strange, is that said block of data contains
����������;����;���@<����
or
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
in a hexadecimal format, just for the color black. The second color however, which equals to the color #010101, has the binary data
��������
or
fffd fffd fffd fffd fffd 1 fffd fffd fffd
I fail to make any sense of how this file format stores the color data, extensive research also didn't bring any helpful results, which fit my problem.
As @TomDoodler commented on the question, the .clr file is the serialization of the NSColorList
class.
I wrote a MacOS playground that opens the .clr file and prints out the color names and RGB values. I wanted to create camelCase
names for the colors, so that's why I added a String extension.
For 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)\")")
}
}
}