macoscocoanscolorpanel

access NSColorPanel's bottom/custom colors


I would like to read the list of colors that are shown on the bottom of the NSColorPanel (see image below). Is there a way to do this?


Solution

  • For undocumented access (this may not work within a sandbox and will get your app rejected by Apple if you plan to distribute through the App Store):

    NSArray *libraries = [[NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory inDomains:NSAllDomainsMask];
    NSURL *url = [[libraries objectAtIndex:0] URLByAppendingPathComponent:@"Colors/NSColorPanelSwatches.plist"];
    NSData *fileData = [NSData dataWithContentsOfURL:url];
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:fileData];
    
    NSArray *colors = [unarchiver decodeObjectForKey:@"NSSwatchColorArray"];
    

    The colors array will then contain NSColor objects of the colour panel.

    This works as far back as OS X 10.6. It may work on earlier versions also but you'll need to obtain the filename differently (since URLsForDirectory:inDomains: was introduced in 10.6). Inside the NSColorPanelSwatches.plist file is an internal version number which is set to 6 for 10.6 right through to 10.10. It could change in the future, but you could be more-or-less safe by doing:

    if ([unarchiver decodeIntForKey:@"NSSwatchFileVersion"] == 6)
    {
        NSArray *colors = [unarchiver objectForKey:@"NSSwatchColorArray"];
        // do something with colors
    }
    else
    {
        NSLog(@"System unsupported");
    }
    

    If you're interested in where the positions of the colours are, you can decode an NSIndexSet from the unarchiver using the NSSwatchColorIndexes key, and use that index set in conjunction with the number of rows and columns that you can determine by decoding integers with the keys NSSwatchLayoutNumRows and NSSwatchLayoutNumColumns. The nth index in the index set refers to the location of the nth colour in the array and the indexes increase downwards. For example, the first “colour box” in the panel is index 0, and the box below it is index 1. The box to the right of “index 0” is actually index 10 (or whatever number you decoded from NSSwatchLayoutNumRows).

    So if you have a colour in the first box, and another colour in the box to the right, you'll have two NSColor objects in the colors array, and the NSIndexSet will contain two indexes, 0 and 10.