ColoRIX compressed 16-color format

This is a follow-up to my previous post on ColoRIX compressed 256-color images. Here I’ll explain how to decode (at least some) compressed 16-color images.

The short answer: The compression for 16-color images is the same as for 256-color images, except that the “XOR filter” step doesn’t happen.


The documentation for “RIX3” format (or “new” format) lists the following image types:

0 = Linear, one byte per pixel (a la VGA, TGA, PGA)
1 = Planar 0, 2, 1, 3 (a la EGA)
2 = Planar 0, 1, 2, 3 (a la EGA)
3 = Text (char, attr)
4 = Planar lines 0, 1, 2, 3

In my previous post, I covered type 0 images. In this post, I’ll cover type 4, plus “old” format .SCR files.

RIX3-type-4 files are created by ColoRIX VGA Paint, when configured to run in most 16-color modes.

ColoRIX VGA Paint splash screen

The old-format files, which I guess are created by (some old versions of) the software named EGA Paint, don’t have any sort of identifying signature or header. They just have a 16-byte palette, then the possibly-compressed image data.

EGA Paint by RIX Softworks was definitely a thing that existed, but I’ve never seen a copy of it. Some of the .SCR files made by it do still exist, though. For example: ROLEX.SCR.

Uncompressed 16-color formats

Discussing the non-compressed formats isn’t my goal here, but it will make it easier to explain the compressed formats.

Uncompressed Old-SCR-format

For old SCR format, the image is always 640×350 pixels. The dimensions are not stored in the file. There is also supposed to be an .SCP format that is 640×480 pixels, though I haven’t found any such files.

The first 16 bytes of the file are the color palette. Only the low 6 bits of each byte are used; the high 2 bits of each byte should be 0.

Each 6-bit palette entry is the index of a color in a standard EGA 64-color palette. Here is at least a close approximation of that standard palette, in hex RRGGBB format:

000000,0000aa,00aa00,00aaaa,aa0000,aa00aa,aaaa00,aaaaaa,
000055,0000ff,00aa55,00aaff,aa0055,aa00ff,aaaa55,aaaaff,
005500,0055aa,00ff00,00ffaa,aa5500,aa55aa,aaff00,aaffaa,
005555,0055ff,00ff55,00ffff,aa5555,aa55ff,aaff55,aaffff,
550000,5500aa,55aa00,55aaaa,ff0000,ff00aa,ffaa00,ffaaaa,
550055,5500ff,55aa55,55aaff,ff0055,ff00ff,ffaa55,ffaaff,
555500,5555aa,55ff00,55ffaa,ff5500,ff55aa,ffff00,ffffaa,
555555,5555ff,55ff55,55ffff,ff5555,ff55ff,ffff55,ffffff

The palette is 16 of these 64 colors. Each image pixel is the 4-bit index of one of the 16 colors.

The pixels’ palette indices are separated into four bit-planes. The planes are ordered in a particular way; then each is stored in the file contiguously, in its entirety.

If we call the most significant bit-plane “3”, down to the least significant “0”, then the planes are stored in the file in the order 0, 2, 1, 3.

Uncompressed RIX3-type-4

All RIX3 formats start with a 10-byte header. The palette usually starts at offset 10, though there is a rarely-used “extension block” feature that can change this. The palette format is the same as for 256-color palettes, except that it has just 16 colors. Each entry is 3 bytes, R-G-B, but only the low 6 bits of each byte are used.

Each pixel in the image data is a 4-bit index into the 16-color palette.

The image data is first separated into rows; then each row is separated into four bit-planes. If the image width is not a multiple of 8 pixels, then each bit-planes is padded to the next byte boundary.

The order of the bit-planes is each row is “least-significant bit first”: 0, 1, 2, 3.

Compressed 16-color formats

The compression is what I call “byte oriented”. It takes the bytes that make up the equivalent uncompressed image, and compresses those bytes, without too much regard for their interpretation as pixels.

As with the 256-color format, the image data is split into segments. But there is no XOR filtering step. Each segment is RLE-compressed, then compressed with Huffman coding, using a Huffman codebook shared by all segments.

Compressed Old-SCR-format

For the compressed version of this format, the high bit of the very first byte of the file is set to 1, presumably to indicate that it uses compression.

Each of the four bit-planes is compressed, and stored in its own compressed segment. So, there should always be exactly four compressed segments (not counting the special first segment, for the Huffman codebook).

Compressed RIX3-type-4

For the compressed version of this format, the image is split into strips, each containing some number of rows. In my limited testing, the number of rows per strip was always 96 (except for the last strip, which can be smaller).

In my previous post, I wondered if the number of rows per (non-final) strip was always 64. Clearly, it’s not. At the very least, it depends on the image type.

Each strip is then compressed, and stored in its own compressed segment, as it is in the 256-color format.

I still don’t know the proper way to deal with the “padding problem” discussed in my previous post.

Comments

I realize now that the compression scheme would have been easier to figure out if I had started with RIX3-type-4 format, because I wouldn’t have had to deal with the XOR filter. Usually, 256-color formats are simpler, because of the correspondence between bytes and pixels. But not here.

I can see how the format may have evolved…

It all made good sense for Old-SCR-format, where each bit-plane can be put in its own segment, and a segment never needs to be bigger than about 32KB or so.

The RLE compression scheme, which can only compress runs of 0x00 or 0xff bytes, makes perfect sense for planar data. Every sufficiently long run, of any color, will result in runs of either 0x00 or 0xff bytes, so the compression works.

When the planar configuration was changed, the original segmentation scheme was no longer possible. But some type of segmentation was sometimes necessary, because of the 64KB segment size limit. Dividing the image into strips was perhaps less than ideal, but it was one way to solve the problem.

The original compression scheme would have worked badly for 256-color, non-planar, images. The XOR filter is a somewhat clever way to make it work, because runs of any color become, after the filter, runs of 0x00 bytes.

But the compression scheme retains the ability to compress runs of (post-filter) 0xff bytes, which makes little sense for these non-planar images. It does allow for compression of runs of alternating black/white pixels, but that comes at a price: white pixels, in most other situations, compress less well than any other color. I now suspect that this was not by design, but merely an artifact of using a compression scheme that was designed for a different purpose.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s