§ 42 - .mcai image format

§ 42.1 - Overview

.mcai files are an experimental 64-bit file format I am using to explore various image data compression ideas.

The general concept is that an image is broken up into regular-sized blocks, then multiple strategies are tested against each block, with the strategy that results in the greatest compression being the one chosen for actually storing the block in the .mcai file. The more strategies are added, the more likely one of them will provide significantly better compression than the others.

iToolBox will always be able to load .mcai files from older versions, but as the format gains various compression modes, newer file saves will result in smaller files that cannot be loaded by older versions of the software. So backwards compatability is guaranteed, again, older files will always be loadable by newer versions of this software, but not the other way around. You may prefer to use the .ato format instead, as it is just as capable.

§ 42.2 - Rules:

  1. An .mcai file consists of a series of chunks, each of which is signaled by an 8-byte chunk ID. The first four bytes of the ID define the chunk type and will be uppercase and/or numeric ASCII. The second four bytes will be the same as the first four, except that any letters in the chunk ID will be lowercase and they will be in reverse order. For instance, the "AUTH" chunk is signaled by "AUTHhtua"; if a reader encounters a byte sequence that does not meet the preceding metric when it is expecting a new chunk ID, the file reader must abort.
    • Following the 8-letter chunk ID is a 32-bit value (4 bytes) that indicates the length of the chunk. If the chunk ID is not recognized by the file reader, it must be skipped by seeking ahead in the file using this value; the value does not include the chunk ID or the four bytes of size information. The value may be little endian, or big-endian, as indicated by the MCAI_littleEndian bit being set in the header's flags1 field, or not. This is true for all values in the file larger than a single byte.
  2. Chunk ordering is generally unrestricted, except that:
    • The "MCAI" header chunk must be first; Further, decoding of an .mcai file can only be attempted if the header block has been validated according to the specification below.
    • If a "THUM" chunk is present, it must occur immediately after the "MCAI" chunk
    • If a map chunk is present for a channel, it must immediately precede the channel chunk. For instance, a "MAPG" chunk, if present, would immediately precede a "GCHA" chunk. Aside from that constraint, the two related chunks themselves as a pair may appear anywhere in the file's chunk ordering.

§ 42.3 - Specification

§ 42.3.1 - The MCAI (Header) Chunk

Note: The code shown below is Qt c++ code; the quint32 objects are Qt's way of representing a 4-byte, unsigned 32-bit entity, and the quint8 objects are Qt's way of representing a 1 byte, unsigned 8-bit entity.

// Header flags as bitmasks
// All undefined bits will be zero
// -------------------------------
// flags1:
#define MCAI_littleEndian	0x01	// if set, all values are stored in file as little endian
#define MCAI_thumbnail		0x02	// if set, there is a THUM chunk containing a jpeg
#define MCAI_monochrome		0x04	// if set, the image consists of an MCHA chunk
#define MCAI_mappedR		0x08	// if set, red channel is indexed to a corresponding remap chunk
#define MCAI_mappedG		0x10	// if set, green channel is indexed to a corresponding remap chunk
#define MCAI_mappedB		0x20	// if set, blue channel is indexed to a corresponding remap chunk
#define MCAI_mappedA		0x40	// if set, alpha channel is indexed to a corresponding remap chunk
#define MCAI_mappedM		0x80	// if set, monochrome channel is indexed to a corresponding remap chunk
// flags2 - presently unused, will be 0x00
// flags3 - presently unused, will be 0x00
// flags4 - presently unused, will be 0x00
// flags5 - presently unused, will be 0x00
// flags6 - presently unused, will be 0x00
// flags7 - presently unused, will be 0x00
// flags8 - presently unused, will be 0x00

struct header
{
};

struct mcaiHeader		//   Offset --- Description
{				//   ======================
	char	chunkID[8];	//   0 -------- The ASCII characters "MCAIiacm"
	quint32	size;		//   8 -------- sizeof(struct mcaiHeader) - (8 + sizeof(quint32))
	quint32	magic;		//  12 -------- Always 0x90862081 (observe endian flag in flags1)
	quint32	xw;		//  16 -------- Image x width (observe endian flag in flags1)
	quint32	yw;		//  20 -------- Image y width (observe endian flag in flags1)
	quint32	cx;		//  24 -------- Cell x size (always 8) (observe endian flag in flags1)
	quint32	cy;		//  28 -------- Cell y size (always 8) (observe endian flag in flags1)
	quint32	version;	//  32 -------- 1...1 (observe endian flag in flags1)
// When reading the checksum below, observe endian flag in flags1
	quint32	checksum;	//  36 -------- Sum of all bytes in header as unsigned values EXCEPT flags1;
	quint8	flags1;		//  40 -------- Flags; see above defines
	quint8	flags2;		//  41 -------- Flags; see above defines
	quint8	flags3;		//  42 -------- Flags; see above defines
	quint8	flags4;		//  43 -------- Flags; see above defines
	quint8	flags5;		//  44 -------- Flags; see above defines
	quint8	flags6;		//  45 -------- Flags; see above defines
	quint8	flags7;		//  46 -------- Flags; see above defines
	quint8	flags8;		//  47 -------- Flags; see above defines
};

§ 42.3.2 - The THUM Chunk

THUMmuht
32-bit size (observe endian flag in flags1)
JPEG content

Optional; if present, contains a .jpeg image of the file content scaled to a reasonable thumbnail size. Readers that handle the "THUM" chunk must be prepared to further scale the thumbnail image to their specific desired preview size.

The canonical thumbnail size written in the reference implementation in iToolBox is 256 pixels wide, with the vertical size scaled proportionally. Writers are well advised to keep .jpeg quality relatively low (or in other words, keep the .jpeg compression high); the thumbnail image is only a preview and so does not require high fidelity.

Also in the canonical iToolBox implementation, when source images are smaller than the thumbnail size on both axis', they will be pixel-duplicated to the larger thumbnail size so as to preserve sharp pixel detail, while all other source images will be (somewhat) smoothly scaled down so as to preserve regional detail. This is suggested, but not required, behavior for an .mcai writer.

§ 42.3.3 - Text-content Chunks

All of the following chunks contain UTF-8 text; integer and real numbers defined here are also text fields which must be converted by the file reader into the reader's internal numeric formats.

§ 42.3.3.1 - The AUTH chunk

Optional; if present, provides image author details.

AUTHhtua
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.2 - The ANNO chunk

Optional; if present, provides image author details.

ANNOonna
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.3 - The COPY chunk

Optional; if present, provides image copyright details.

COPYypoc
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.4 - The CTIM chunk

Optional; if present, provides image creation time details in the format "YYYYmmDD:HHmmSS UTC".

CTIMmitc
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.5 - The MTIM chunk

Optional; if present, provides image modification time details in the format "YYYYmmDD:HHmmSS UTC".

MTIMmitm
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.6 - The NAME chunk

Optional; if present, provides image short-form name details.

NAMEeman
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.7 - The SOFT chunk

Optional; if present, provides details on the software used to create or edit the image.

SOFTtfos
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.8 - The LATI chunk

Optional; if present, provides geographical latitude in meters as a real number.

LATIital
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.9 - The LONG chunk

Optional; if present, provides geographical longitude in meters as a real number.

LONGgnol
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.10 - The ALTI chunk

Optional; if present, provides geographical altitude in meters as a real number.

ALTIitla
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.11 - The SHUT chunk

Optional; if present, provides camera shutter speed in seconds as a real number.

SHUTtuhs
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.12 - The APER chunk

Optional; if present, provides camera f/aperture as a real number.

APERrepa
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.13 - The FLEN chunk

Optional; if present, provides camera focal length in millimeters as a real number.

FLENnelf
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.14 - The ISOV chunk

Optional; if present, provides camera ISO value as a real number.

ISOVvosi
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.15 - The XCEN chunk

Optional; if present, provides image X centering as an integer pixel location. If the image is placed over another image, this is the horizontal location on the underlying image where the center of this image should align.

XCENnecx
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.16 - The YCEN chunk

Optional; if present, provides image Y centering as an integer pixel location. If the image is placed over another image, this is the vertical location on the underlying image where the center of this image should align.

YCENnecy
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.17 - The XDPI chunk

Optional; if present, provides image horizontal DPI as an integer.

XDPIipdx
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.3.18 - The YDPI chunk

Optional; if present, provides image vertical DPI as an integer.

YDPIipdy
32-bit size (observe endian flag in flags1)
UTF-8 content

§ 42.3.4 - Image Data Chunks

There are five possible channel chunks which contain 16-bit image data...

  1. RCHA
  2. GCHA
  3. BCHA
  4. ACHA
  5. MCHA

...any of which may be immediately preceded by an associated map chunk...

  • MAPR
  • MAPG
  • MAPB
  • MAPA
  • MAPM
Warning: If a MAPX chunk is present, it must immediately precede the associated channel chunk.

§ 42.3.4.1 - MAPX chunks

MAPX chunks allow a channel that contains less than 257 or 17 distinct values to be reduced, repectively, to 8-bit or 4-bit monochome palette, or map, entries. An .mcai encoder first determines how many values are present in a channel, and then generates the appropriate map, then a mapped channel result immediately following.

A MAPX chunk is structured as follows, where X stands in for R (red), G (green), B (blue), A (alpha), or M (monochrome):

MAPXxpam
32-bit size (observe endian flag in flags1)
16-bit count of map entities, valid values of 1-256 (observe endian flag in flags1)
[count] mapping values

When a MAPX chunk is present, if count is less than 17, then the lower four-bits of each decoded channel value select a mapping value to replace that channel value. So for instance, if a decompresed channel value is 0x7777, then masking that to four bits results in 0x0007, which is then used to select the 8th value provided in the map. The entire channel must be remapped in this fashion after decompression. These map values are based at zero; in other words, a value of 0x0000 selects the first map value.

When a MAPX chunk is present, if count is greater than 16, then the lower eight-bits of each decoded channel value select a mapping value to replace that channel value. So for instance, if a decompresed channel value is 0x8181, then masking that to eight bits results in 0x0081, which is then used to select the 130th value provided in the map channel. The entire channel must be remapped in this fashion after decompression. These map values are based at zero; in other words, a value of 0x0000 selects the first map value.

§ 42.3.4.2 - XCHA chunks

A XCHA chunk is structured as follows, where X stands in for R (red), G (green), B (blue), A (alpha), or M (monochrome):

XCHAxahc
32-bit size (observe endian flag in flags1)
A series of compression blocks that will decompress to size cx times cy as defined in the header

The RCHA, GCHA, BCHA and ACHA chunks are respectively decompressed to the red, green, blue and alpha channels of the image. A value of 0x000 is minimum (zero) channel intensity; a value of 0xFFFF is maximum (full) channel intensity. In the case of an ACHA chunk, a value of 0x0000 results in a fully transparent pixel, while a value of 0xFFFF results in a fully opaque pixel.

The MCHA chunk, if present, is decompressed to all three of the red, green and blue channels, ultimately resulting in identical channel values for all three color channels.

Each .mcai image file must contain either (at least) one MCHA chunk, or (at least one of) all three of the CHA, CHA and CHA chunks.

If the ACHA chunk is not present, then the all alpha channel values default to 0xFFFF, which means the associated pixels are all fully opaque.

Note: When multiple XCHA chunks of the same type are present, the most recent chunk encountered is used to set the associated channel values. Such a circumstance, while legal, is not sensible and should not be written to an .mcai file.

§ 42.3.4.3 - Compression blocks

Each compression block will decompress to a perfectly square group of channel values exactly cx times cy in size. When a decompressed block overlaps an image right or bottom edge, the additional values are to be ignored; so in reconstructing a channel, the block is overlapped at cx and cy intervals over the actual channel, and only those values in the block that actually overlap the channel data are used. Once a block has been decompressed, if the associated MAPx chunk was encountered first, then the block is remapped as described above before being transferred to the target channel(s.)

Note: When generating compression blocks, when a block is being generated that overlaps a right or bottom edge, the rightmost values on the channel should be duplicated rightwards, and the bottom right value on the channel should be duplicated both rightwards and downwards. This allows the block compressors to reach higher efficiency; other than that, as these values are not placed into the channel when decompressed, the out-of-block-overlap values do not matter.

Each compression block begins with a single code byte that indicates the type of compression the block is encoded with:

Code10Mode
1MCAI_nocomp
5MCAI_newsingle
7MCAI_newsingle8
8MCAI_nocomp8
10MCAI_nocomp4
11MCAI_4dm2
17MCAI_monolithic
18MCAI_4mapped16
19MCAI_8mapped16
20MCAI_2mapped16
21MCAI_1mapped16
22MCAI_zlib
§ 42.3.4.3.1 - MCAI_nocomp Blocks

The MCAI_nocomp code is followed by cx times cy 16 bit values. Observe the endian flag in the header in resolving these values. Data order is column, row.

§ 42.3.4.3.2 - MCAI_newsingle Blocks

The MCAI_newsingle code is followed by exactly one 16 bit value. This value is copied to each position in the cx times cy block. Observe the endian flag in the header in resolving this value.

§ 42.3.4.3.3 - MCAI_newsingle8 Blocks

The MCAI_newsingle8 code is followed by exactly one 8 bit value. This value is duplicated to the upper 8 bits of a 16-bit value (in other words, 0x5C would become 0x5C5C), and then is copied to each position in the cx times cy block.

§ 42.3.4.3.4 - MCAI_nocomp8 Blocks

The MCAI_nocomp8 code is followed by cx times cy 8 bit values. These values are each duplicated to the upper 8 bits of a 16-bit value (in other words, 0x5C would become 0x5C5C), and then the resulting values are placed at each relevant position in the cx times cy block. Data order is column, row.

§ 42.3.4.3.5 - MCAI_nocomp4 Blocks

The MCAI_nocomp4 code is followed by cx times cy 4 bit values, arranged as 2 to a byte, with the left most pixel in the left nybble of each byte. These values are each duplicated to each nybble of the upper 12 bits of a 16-bit value (in other words, 0x5 would become 0x5555), and then the resulting values are placed at each relevant position in the cx times cy block. Data order is column, row.

§ 42.3.4.3.6 - MCAI_4dm2 Blocks

The MCAI_4dm2 code is followed by a single byte that contains a value in the range 0x00 to 0x0f. This is the 4-bit value of the [0,0]th block. The rest of the MCAI_monolithic block consists of four 2-bit values per byte, with the highest two bits being the leftmost value, and the lowest two bits the rightmost value. Each of these two-bit values is a signed value indicating the delta from the previous value as follows...

00No change
01Subtract 1 from previous value
10Subtract -2 from previous value
11Subtract -1 from previous value

...that will result in the final value after being copied to the upper three nybbles in the 16-bit channel value. Data order is spiral: The deltas are taken starting at 0,0, proceeding clockwise from the outside to the inside up to and including the last pixel in the block. This is shown graphically in the example below.

Here is an example 4x4 block, along with the associated data, scan order, and decode process:


4x4 .mcai block encoded with MCAI_monolithic
Block scan order indicated as 0 through 15. Keep in mind the minimum
block size is 8x8; this 4x4 block is simply demonstrating the spiral technique.

 

Block Data and Subsequent Decode Process
0x0B

MCAI_4dm2 code
0x06

value at [0,0]
0x3f 0xD5 0xD4 0x00
bit pairs: 00 11 11 11 11 01 01 01 11 01 01 00 00 00 00 00
delta values:  0 -1 -1 -1 -1  1  1  1 -1  1  1  0  0  0  0  0
4 bit results:  6  7  8  9  A  9  8  7  8  7  6  6  6  6  6  6
channel values: 6666 7777 8888 9999 AAAA 9999 8888 7777 8888 7777 6666 6666 6666 6666 6666 6666
§ 42.3.4.3.7 - MCAI_monolithic Blocks

The MCAI_monolithic code is followed by exactly one 16 bit value (Observe the endian flag in the header in resolving this value.) This value is copied to every pixel in the entire channel. This is a special case: Only one block is used to describe the entire channel. Therefore, a reader must check the first block to see if the first block is an MCAI_monolithic block, and if it is, perform the MCAI_monolithic decompression and then skip the normal block-by block sequencing, as the channel decoding is already complete.

§ 42.3.4.3.8 - MCAI_1mapped16 Blocks

The MCAI_1mapped16 code is followed by a single byte that contains a count in the range 0x01 to 0x02. This value indicates how many 16-bit mapping values are to follow. After [count] of 16-bit mapping values comes one byte for every set of eight block values, left-side in the high bit, right in the low bit; the eight bits in each byte contain an index value from 0 to 1, which tell you which of the previously fetched 16-bit mapping values is to be used as the value for that position in the block.

§ 42.3.4.3.9 - MCAI_2mapped16 Blocks

The MCAI_2mapped16 code is followed by a single byte that contains a count in the range 0x03 to 0x04. This value indicates how many 16-bit mapping values are to follow. After [count] of 16-bit mapping values comes one byte for every set of four of block values, left-side in the high two bits, right in the lowest two bits; the four bit-pairs in each byte contain an index value from 0x00 to 0x03, which tell you which of the previously fetched 16-bit mapping values is to be used as the value for that position in the block.

§ 42.3.4.3.10 - MCAI_4mapped16 Blocks

The MCAI_4mapped16 code is followed by a single byte that contains a count in the range 0x05 to 0x10. This value indicates how many 16-bit mapping values are to follow. After [count] of 16-bit mapping values comes one byte for every pair of block values, left-side in the high nybble, right in the low; the two nybbles in each byte contain an index value from 0x00 to 0x0f, which tell you which of the previously fetched 16-bit mapping values is to be used as the value for that position in the block.

§ 42.3.4.3.11 - MCAI_8mapped16 Blocks

The MCAI_8mapped16 code is followed by a single byte that contains a count in the range 0x11 to 0xff. This value indicates how many 16-bit mapping values are to follow. After [count] of 16-bit mapping values comes one byte per block value; these bytes contain an index value from 0x00 to 0xff, which tell you which of the previously fetched 16-bit mapping values is to be used as the value for that position in the block.

§ 42.3.4.3.12 - MCAI_zlib Blocks

The MCAI_zlib code is followed by a two-byte, 16-bit value that contains a count in the range 0x11 to 0xff that indicates the size of the compressed data in bytes. The value may be little endian, or big-endian, as indicated by the MCAI_littleEndian bit being set in the header's flags1 field, or not. Following this count is [count] of byte data as compressed by Qt's qCompress() function; it may be directly uncompressed with Qt's qUncompress() function. This compression is essentially the same as zlib's DEFLATE mechanism, except as the following note indicates.

Note: If you want to decompress this data using zlib itself, you need skip the first four bytes in the data in the block handed to zlib for decompression. Likewise, if you want to create one of these blocks using zlib, you first need to prepend a four byte header to the byte array containing the data. The header must contain the expected length (in bytes) of the uncompressed data, expressed as an unsigned, big-endian, 32-bit integer.
Document Keyboard Navigation
, Previous Page . Next Page
t TOC i Index k Keyboard o Operators g Glossary c Changes

Valid HTML 4.01 Loose
 

This manual was generated with wtfm
wtfm uses aa_macro and SqLite
wtfm and aa_macro are coded in python 2.7
iToolBox 3.12
This Documentation and Associated Application Executables are Public Domain
Please consider supporting my iToolBox development efforts with a small PayPal donation.