Skip to content

Reverse-engineering the ColorSchemer Studio 2 File Format

Recently I bought the excellent ColorSchemer Studio 2 through the Mac App Store. Put simply, the app allows creation of colour palettes using a variety of tools including a colour wheel, various schemes, mixers and more. These palettes can also be saved to files to be opened again later, however these files are stored in a proprietary binary format that no other app (to my knowledge) can read.

As some of you will already know, I have already written a small colour picker/palette app called Colour Chooser. Since I originally wrote that post and published the app, I have added the ability to create a palette of colours and save this to a little XML format that I created for that purpose. This was all very well – and indeed we use the tool at work – but it's often useful to be able to read (and occasionally write) palettes in other formats. As of today, the app can operate with the following formats:

  • Colour Chooser XML Palette (native format) (.ccxml)
  • Adobe Swatch Exchange (.ase)
  • GIMP Palette (.gpl)

This list is already a mix of both text-based and binary formats but in all of these cases, the format had already been documented. Having now purchased ColorSchemer, what I would ideally like is to be able to interoperate between the two. Clearly I can already use many formats and several of these are also supported by ColorSchemer Studio via the import/export functionality, however I think this can be made much more seamless. Colour Chooser needs to understand ColorSchemer Studio's native format.

Someone's Done This... Right?

My first thought is that this is the internet we're talking about here. Someone must have done this before, right? Well... it turns out the answer is no. The closest I got was this excellent site (which I have used before for some of the other formats) that at first glance appears to have the answer right there. However it turns out that this is for version 1 of the app rather than 2, and the format is nothing alike at all.

Challenge Accepted!

My first port of call for this was to find a decent hex editor, and I have to say that Hex Fiend really hits the spot here. It has all the basics, but what really makes it for me (and was invaluable for this task) are the little inspector thingies that you can add to the bottom of the window which will show the values of your selections in the main area in a number of formats.

Hex Fiend inspectors

Initially I thought the first job is to identify where the actual colours in the file where. This wasn't quite as easy as it first sounded as it turned out the colours are stored as a set of floats ranging from 0 to 1 rather than as integers from 0 to 255 as I initially expected. However once I'd figured this out with the help of those little inspector parts, I was already part of the way there. To decipher the rest, I basically ended up making a lot of changes to the file one after the other and noting the changes in the file. Doing this, I was slowly building up a picture of what each part meant. The key was very much to make one single change each time and see what happened.

The Format Revealed

So in case anyone else is faced with this particular problem, here is the format documented. This is 100% correct (to my knowledge and for all files I have examined or created) for version 2.1. It is possible future versions might change or add to this.

43 53 01 00 00 00 01 00 00 00 80 3F 
4E A2 27 3F 64 2E 1B 3F 06 00 01 00 
07 00 23 66 ...
ItemDescriptionType
File headerThe string "CS" always appears here.string
Base colour blockThis block contains the details of the 'base' colour – the one currently showing in the main picker controls. This is always present.n/a
Block headerThis dictates what type of block this is (colour) and thus what will follow. This is always 1.int16
Colour nameThe name of the colour. In this case, the colour is nameless and has an empty string here.string of length (int16)
Colour spaceThe colour space for this colour (RGB, CMYK)int16
Colour component valuesThe values of the colour components. Either 3 values for R, G and B or 4 values for C, M, Y and K.(×3 or ×4) float32
Block countNumber of subsequent blocks in the file. This is always present.int16
Content blocksThis content is that of all the blocks in the file, the number of which matches the above block count. See the following sections for details of the block types and their contents.n/a

Block Types

The different block headers used. Each header is just two bytes (a 16 bit integer) which indicates what comes next.

Value (hex)Value (int)Description
01 001Colour
02 002Start of group
03 003End of group

Colour Block

This block type contains all the necessarily information to represent a colour. It is very similar to the base colour block seen above.

01 00 0B 00 79 65 6C 6C 
6F 6F 6F 6F 6F 6F 6F 01 
00 00 00 80 3F ED 73 62 
3F 7E 0E 29 3E 00
ItemDescriptionType
Block headerSee aboveint16
Colour nameThe name of the colour. In this case, the colour is "yellooooooo". In string of length (int16)
Colour spaceThe colour space for this colour (RGB, CMYK)int16
Red componentThe red value for this colour (between 0 and 1, inclusive)float32
Green componentThe green value for this colour (between 0 and 1, inclusive)float32
Blue componentThe blue value for this colour (between 0 and 1, inclusive)float32
ExpandedWhether or not the colour is expanded in the list (0 = no, 1 = yes).int8

The colour spaces are as follows:

Value (hex)Value (int)Description
01 001RGB
02 002CMYK

For a colour in the CMYK colour space there will be 4 component values instead of 3, in the order of C, M, Y then K. They are still specified as floats between 0 and 1, just as for RGB.

Start of Group Block

This block type indicates the beginning of a group (essentially a single-level folder which contains colours).

02 00 0E 00 43 6F 6D 65 
20 41 62 6F 61 72 64 20 
23 32 01
ItemDescriptionType
Block headerThe start of the block. See above.int16
Group nameThe name of this group of colours.string of length (int16)
ExpandedWhether or not the group is expanded in the list (0 = no, 1 = yes).int8

End of Group Block

This block type consists solely of the header which indicates the end of the group. There is no further content, and the next block (if any) follows.

03 00

Next Step

Now that I've deciphered the format, the next step is to built support into Colour Chooser. That ought to be pretty easy now, as I have plenty of information to refer to and to build tests around. This is a pretty small and simple binary format but it really isn't as scary as it might first look to some, even when there is no documentation or information anywhere.

Now there is.