Working with CorelDRAW Palettes part 2, writing .pal files
Continuing my investigation into CorelDRAW palettes, this brief article describes how to write .pal files for use with CorelDRAW! 3.0.
I recently picked up a copy of CorelDRAW! 3.0 from eBay which
came on two CD's with a different version on each. That gave me
two different surprises, the first in that 3.0A wasn't an
improved version of 3.0, and secondly instead of the .cpl
format I was expecting to find, there were two different .pal
formats, one text based (for CorelDRAW!) and one binary (for
PHOTO-PAINT! (very shouty this software!)). This first article
covers reading the text based palette format.
The palette format itself is simple enough, from the example
colours below we can infer that each colour entry is in CMYK
format with the range 0-100
. Although it looks as if it is a
fixed width format, when looking at other palettes using this
format this isn't the case and columns can be of differing
widths.
I'm not sure what limits there are on the number of colours, but one of the palettes I looked at had over 2000 colours so clearly not as limited as some older formats.
In order to have a common base to compare to, I recreated DawnBringer's 32 colour palette using the CorelDRAW application.
From experimenting with CorelDRAW, I also found that it won't allow swatch names to be longer than 29 characters.
Reading the palette is straight forward enough, although one of
the palettes I tested did have a old school wild card. As this
is a plain text format with each colour on a single line, I'm
just going to use a StreamReader
to pull out each line.
In the above while loop, instead of just checking that the line
is not null
as I usually would, I also have an extra check to
see if the first character is (char)26
and if so, to cancel
loading. But what is this character?
This is the SUB
or substitute character and was
originally designed to be used in place of a character that is
invalid. Historical DOS systems and its predecessors used this
as an end of file character, which is how it has been used in
one of the palettes that shipped with this version of CorelDRAW.
An interesting facet of computing history I wasn't expecting to find!
As swatch names start with a quote and end with a quote, and are
the only quoted string in the line we can find the end of the
name by using LastIndexOf
.
As the .NET Color
structure doesn't allow the Name
property
to be set it isn't used by the demonstration, but is still
preserved for use with custom structures.
While testing I discovered that although CorelDRAW lets you enter quotes into the palette editor, it silently discarded any swatches with quotes in their name.
Although I don't go to crazy lengths, string parsing is typically quite expensive in terms of memory and/or processing power and so I often try and optimise this as I go.
In this case, while I could do string.Split
, I'd rather avoid
the array allocation so I'm manually looking for the number
sequences. As we already have the end of the swatch name from
the previous section, we can walk the rest of the string,
discarding the white-space, finding the longest sequence of
digits and then parsing out the result.
I start by iterating the string from an given start position and keep moving forward as long as the current character is a space.
Once I've ran out of spaces, I check how much of the string is left to determine the maximum number of characters to read - normally I want to read 3 as this is the maximum number of digits which can be present, however if it is at the end of the line and the final result isn't a 3 digit number there won't be enough data to read.
With the maximum number of digits established, I then check through these characters - if I find a digit, I increment a counter telling me how long the final number is. Anything else and I break out.
With both the start of the numeric field and its length I can
then use byte.Parse
on the substring.
It would be interesting to know if I could use the new
Span<T>
functionality in .NET Core to skip any string processing at all. An experiment for a future day!
The final action I perform is to record the new start position, so the next call to the method will continue from this point.
With this method in place, I can quite easily read out the four colour components without doing any array allocation.
Reading palettes is hardly going to be a performance critical
operation, so maybe you don't need to write any exotic code. If
you don't care about the allocations, you could write the value
extraction a lot simpler by using string.Split
. Note that even
here, I still want to avoid "silent" allocations and use a
prepared array with the split characters.
Personally, I prefer the former approach however I have to admit I didn't profile either approach as the article is overdue.
In absolutely no co-incidence at all, my previous article described how to convert between CMYK and RGB so I don't need to have a digression in this article.
With this helper in place and regardless of which method you used to get the individual C, M, Y and K components, we can now fully read CorelDRAW 3.0 text based palettes into .NET.
As usual, an example project demonstrating how to read CorelDRAW
.pal
files is available from the link below.
Like what you're reading? Perhaps you like to buy us a coffee?