Reverse-engineering the ColorSchemer Studio 2 File Format
Published on
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.
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 ...
Item | Description | Type |
---|---|---|
File header | The string "CS" always appears here. | string |
Base colour block | This block contains the details of the 'base' colour – the one currently showing in the main picker controls. This is always present. | n/a |
Block header | This dictates what type of block this is (colour) and thus what will follow. This is always 1. | int16 |
Colour name | The name of the colour. In this case, the colour is nameless and has an empty string here. | string of length (int16) |
Colour space | The colour space for this colour (RGB, CMYK) | int16 |
Colour component values | The 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 count | Number of subsequent blocks in the file. This is always present. | int16 |
Content blocks | This 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 00 | 1 | Colour |
02 00 | 2 | Start of group |
03 00 | 3 | End 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
Item | Description | Type |
---|---|---|
Block header | See above | int16 |
Colour name | The name of the colour. In this case, the colour is "yellooooooo". In | string of length (int16) |
Colour space | The colour space for this colour (RGB, CMYK) | int16 |
Red component | The red value for this colour (between 0 and 1, inclusive) | float32 |
Green component | The green value for this colour (between 0 and 1, inclusive) | float32 |
Blue component | The blue value for this colour (between 0 and 1, inclusive) | float32 |
Whether 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 00 | 1 | RGB |
02 00 | 2 | CMYK |
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
Item | Description | Type |
---|---|---|
Block header | The start of the block. See above. | int16 |
Group name | The name of this group of colours. | string of length (int16) |
Whether 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.