In a previous article I described how to read the colour
map from a DeluxePaint LBM/BBM file. In the next pair of
articles, I'm going to describe how to load and save colour
swatch files used by Photoshop (those with the .aco
As usual, I'll start with a warning. I have a very limited set
of sample files to test with, so it may be that there's an error
in this code which means it can't handle all files. Certainly it
can't handle all colour spaces (more on that later). However,
I've tested it on a number of files download from the internet
Structure of a Photoshop colour swatch file
The structure of the aco file is straightforward, helped by
Adobe themselves publishing the specification which is
something to appreciate. This article was created using the
October 2013 edition of this specification.
According to the specification, there's two versions of the
format both of which are are fairly similar. The specification
also implies that applications which support version 2 should
write a version 1 palette first, which would admirably solve
backwards compatibility problems. In practice this doesn't seem
to be the case, as some of the files I tested only had version 2
palettes in them.
The structure is simple. There's a 2-byte version code, followed
by 2-bytes describing the number of colours. Then, for each
colour, there are 10 further bytes, 2 each describing the colour
space and then four values to describe the colour. Version two
palettes also then follow this with a four byte integer
describing the length of the name, then the bytes which make up
Number of colours
count * 10 (+ 4 + variable (version 2 only))
Colour data value 1
Colour data value 2
Colour data value 3
Colour data value 4
Version 2 only
Length of name string in characters
length * 2
Unicode code characters, two bytes per character
All the data in an aco file is stored in big-endian
format and therefore needs to be reversed on Windows systems.
Most colour spaces only use three of the four available values,
but regardless of how many are actually used, all must be
I mentioned above that each colour has a description of what
colour space it belongs to. The specification defines the
following colour spaces:
RGB. The first three values in the colour data are red, green, and blue. They are full unsigned 16-bit values as in Apple's RGBColordata structure. Pure red = 65535, 0, 0.
HSB. The first three values in the colour data are hue, saturation, and brightness. They are full unsigned 16-bit values as in Apple's HSVColordata structure. Pure red = 0,65535, 65535.
CMYK. The four values in the colour data are cyan, magenta, yellow, and black. They are full unsigned 16-bit values. For example, pure cyan = 0,65535,65535,65535.
Lab. The first three values in the colour data are lightness, a chrominance, and b chrominance. Lightness is a 16-bit value from 0...10000. Chrominance components are each 16-bit values from -12800...12700. Gray values are represented by chrominance components of 0. Pure white = 10000,0,0.
Grayscale. The first value in the colour data is the gray value, from 0...10000.
To avoid complicating matters, this article will concentrate on
RGB and Grayscale colour spaces, although I'll include the
basics of HSV too for if you have a conversion class kicking
Reading short/int data types from bytes
As I mentioned above, the values in this file format are all
big-endian. As Windows uses little-endian, we need to do some
bit shifting when we read each byte comprising either a short
(Int16) or an int (Int32), using the following helpers:
The << 0 bit-shift in the above methods is technically
unnecessary and can be removed. However, I find it makes the
intent of the code clearer.
For version 2 files, we need to read a string, which is
comprised of two bytes per character. Fortunately for us, the
.NET Framework includes a BigEndianUnicode (MSDN) class
that we can use to convert a byte array to a string. As this
class does the endian conversion for us, we don't need to do
anything special when reading the bytes.
Reading the file
With the preliminaries done with, lets read the file!
We start off by reading the file version so we know how to
process the rest of the file, or at least the first part of it.
If we don't have a version 1 or version 2 file, then we simply
In the above example, if a file has both versions, then I read
them both (assuming the file contains version 1 followed by
version 2). However, there's no point in doing this if you
aren't going to do anything with the swatch name. For example,
this demonstration program converts all the values into the
standard .NET Color structure - which doesn't allow you to
set the Name property. In this scenario, clearly it's a waste
of time reading the version 2 data if you've just read the data
from version 1. However, if you are storing the data in an
object that supports the name, then it's probably a good idea to
discard the previously read data and re-read the version 2 data.
Reading colour data
As the two documented file formats are almost identical, we can
use the same code to handle reading the data, and then perform a
little bit extra for the newer file format. The core of the code
which reads the colour data looks like this.
Translating the colour spaces
Once we've read the colour space and the four values of the
colour data, we need to process it.
The first space, RGB, is simple enough. The Adobe format is
using the range 0-65535, so we just need to convert that to the
standard 0-255 range:
Next is HSL. How you process that depends on the class you are
using, and the range of values it accepts.
The last colour space we can easily support is gray scale.
Files using the Lab or CMYK spaces will throw an exception as
these are beyond the scope of this example.
Although none of the sample files I tested mixed colour spaces,
they were either all RGB, all Lab or all CMYK, the specification
suggests that it's at least possible. In this case, throwing an
exception might not be the right idea as it could be possible to
load other colours. Therefore it may be a better idea to just
ignore such errors to allow any valid data to be read.
The founder of Cyotek, Richard enjoys creating new blog content for the site. Much more though, he likes to develop programs, and can often found writing reams of code. A long term gamer, he has aspirations in one day creating an epic video game - but until that time comes, he is mostly content with adding new bugs to WebCopy and the other Cyotek products.
The second in a two part series that describes how to load and save Adobe Photoshop colour swatch files using C#. This second article provides a full example project that will write RGB and HSL based swatch files.
The first of a two part series which describes how to load and ultimately save Adobe Photoshop colour swatch files using C#. This first article describes the file format, and provides a full example project that will read RGB based swatch files.