Writing Adobe Swatch Exchange (ase) files using C#
The second in a two part series showing how to write Adobe Stack Exchange (ase) files using C#
In my last post, I described how to read Adobe Swatch
Exchange files using C#. Now I'm going to update that sample
program to save ase
files as well as load them.
I covered the basics of writing big-endian values in my original post on writing Photoshop aco files, so I'll not cover that again but only mention the new bits.
Firstly, we now need to store float values. I mentioned the
trick that BitConverter.ToSingle
does where it converts a
int
to a pointer, and then the pointer to a float
. I'm going
to do exactly the reverse in order to write the float to a
stream - convert the float
to a pointer, then convert it to an
int
, then write the bytes of the int
.
We also need to store unsigned 2-byte integers, so we have another extension for that.
Finally, lets not forget our length prefixed strings!
I covered the format of an ase
file in the previous post, so I
won't cover that again either. In summary, you have a version
header, a block count, then a number of blocks - of which a
block can either be a group (start or end) or a colour.
Saving the version header is rudimentary
After this, we write the number of blocks, then cycle each group and colour in our document.
Writing a block is slightly complicated as you need to know - up
front - the final size of all of the data belonging to that
block. Originally I wrote the block to a temporary
MemoryStream
, then copied the length and the data into the
real stream but that isn't a very efficient approach, so now I
just calculate the block size.
If you recall from the previous article, a group is comprised of
at least two blocks - one that starts the group (and includes
the name), and one that finishes the group. There can also be
any number of colour blocks in between. Potentially you can have
nested groups, but I haven't coded for this - I need to grab
myself a Creative Cloud subscription and experiment with ase
files, at which point I'll update these samples if need be.
Writing a colour block is fairly painless, at least for RGB
colours. As with loading an ase
file, I'm completely ignoring
the existence of Lab, CMYK and Gray scale colours.
When I originally tested this code, I added a simple compare
function which compared the bytes of a source ase
file with a
version written by the new code. For two of the three samples I
was using, this was fine, but for the third the files didn't
match. As this didn't help me in any way diagnose the issue, I
ended up writing a very basic (and inefficient!) hex viewer,
artfully highlighted using the same colours as the ase
format
description on sepla.net.
This allowed me to easily view the files side by side and be able to break the files down into their sections and see what was wrong. The example screenshot above shows an identical comparison.
With that third sample file, it was more complicated. In the first case, the file sizes were different - the hex viewer very clearly showed that the sample file has 3 extra null bytes at the end of the file, which my version doesn't bother writing. I'm not entirely sure what these bytes are for, but I can't imagine they are official as it's an odd number.
The second issue was potentially more problematic. In the screenshot above, you can see all the orange values which are the float point representations of the RGB colours, and the last byte of each of these values does not match. However, the translated RGB values do match, so I guess it is a rounding / precision issue.
When I turn this into something more production ready, I will probably store the original floating point values and write them back, rather than loosing precision by converting them to integers (well, bytes really as the range is 0-255) and back again.
The updated demonstration application is available for download below, including new sample files generated directly by the program.
Like what you're reading? Perhaps you like to buy us a coffee?
# Louise