All the data in an aco file is stored in big-endian
format and therefore needs to be reversed on Windows systems
before writing it back into the file.
We can use the following two methods to write a short or a
int respectively into a stream as a series of bytes. Of
course, if you just want functions to convert these into bytes
you could use similar code, just remove the bit-shift.
As with the equivalent read functions, the >> 0 shift is
unnecessary but it does clarify the code.
We also need to store colour swatch names, so again we'll make
use of the Encoding.BigEndianUnicode property to convert a
string into a series of bytes to write out.
Writing the file
When writing the file, I'm going to follow the specification's
suggestion of writing a version 1 palette (for backwards
compatibility), followed by a version 2 palette (for
applications that support swatch names).
The core save routine follows. First, we write the version of
format and then the number of colours in the palette.
With that done, we loop through each colour, calculate the four
values that comprise the colour data and then write that.
If it's a version 2 file, we also write the swatch name. As
these basic examples are just using the Color class, there's
no real flexibility in names, so we cheat - if it's a "named"
colour, then we use the Color.Name property. Otherwise, we
generate a Swatch <index> name.
Converting colour spaces
As previously mentioned, the specification states that each
colour is comprised of four values. Even if a particular colour
space doesn't use all four (for example Grayscale just uses
one, you still need to write the other values, typically as
Although it's a slight duplication, I'll include the description
table for colour spaces to allow easy reference of the value
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.
While supporting CMYK colours are beyond the scope of this
article as they require colour profiles, and I haven't the
foggiest on the Lab space, we can easily support RGB, HSL
and Grayscale spaces.
RGB is the simplest as .NET colours are already in this format.
The only thing we have to do is multiple each channel by 256 as
the specification uses the range 0-65535 rather than the typical
Notice value4 is simply initialized to zero as this space only
needs 3 of the 4 values.
We can also support HSL without too much trouble as the Color
class already includes methods for extracting these values.
Again, we need to do a little fiddling to change the numbers
into the range used by the specification.
The last format we can easily support is grayscale. If the
source colour is already grey (i.e. the red, green and blue
channels are all the same value), then we use that, otherwise
we'll average the 3 channels and use that as the value.
The usual sample application is available from the links at the
end of this article. The sample generates a random 256 colour
palette, then writes this to a temporary file using the
specified colour space. It then reads it back in, and displays
both palettes side by side for comparison.
2009-08-10 - First published
2020-11-21 - Updated formatting
Like what you're reading? Perhaps you like to buy us a coffee?
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.