Specification v1.0

MIC Format

Multi-Image Container — Binary File Format Specification
Extension: .mic
Magic: 4D 49 43 21
Endianness: Little-endian
Max images: 65,535
Table of Contents
  1. Overview & Design Goals
  2. File Structure Layout
  3. File Header — § offset 0x00
  4. Index Table — § offset 0x20
  5. Thumbnail Block
  6. Image Data Blocks
  7. Flag Definitions
  8. Compression & Codec IDs
  9. Color Space & Channel Layout
  10. End-of-File Marker
  11. Reader / Writer Pseudocode
  12. Versioning & Extensibility

Design Goals

MIC is a compact, seekable binary container for bundling multiple images of heterogeneous formats into a single file. It is designed for asset pipelines, game engines, medical imaging, and any system that needs fast random access to individual frames or image layers without decompressing the entire container.

🔀 Mixed Formats
Each embedded image can be a different format: PNG, JPEG, WebP, raw pixels, etc.
⚡ Random Access
Index table at fixed offset enables O(1) seek to any image without scanning.
🖼️ Thumbnails
Optional embedded thumbnail strip for fast preview without full decode.
🔒 Integrity
CRC-32 per image block plus global header checksum.
📏 Alignment
Data blocks aligned to 16-byte boundaries for SIMD-friendly reads.
🔁 Extensible
Version field + reserved bytes + skip-able extension chunks.

File Structure Layout

A MIC file is laid out sequentially in memory. The index table appears immediately after the fixed-size header, enabling parsers to validate and map the entire file with two reads.

BYTE OFFSET →
File Header
32 bytes · offset 0x00
Index Table
N × 64 bytes · offset 0x20
Thumb Block
optional · variable
Image Data[0..N-1]
variable · 16-byte aligned
EOF Marker
8 bytes
Note The index table immediately follows the 32-byte header at 0x20, so a parser can validate the magic, read image count, then load the entire index in one additional read(N × 64) call before seeking to any image.

File Header — 32 bytes at offset 0x00

The file header is always exactly 32 bytes. All multi-byte integers are little-endian.

0x00MAG0
0x01MAG1
0x02MAG2
0x03MAG3
0x04VER
0x05VER
0x06FLG0
0x07FLG1
0x08CNT
0x09CNT
0x0ATS
0x0BTS
0x0CTS
0x0DTS
0x0ETS
0x0FTS
0x10TS
0x11TS
0x12CRC
0x13CRC
0x14CRC
0x15CRC
0x16RSV
0x17RSV
0x18RSV
0x19RSV
0x1ARSV
0x1BRSV
0x1CRSV
0x1DRSV
0x1ERSV
0x1FRSV
Field Offset Size Type Description
magic 0x00 4 B u8[4] Magic bytes: 4D 49 43 21 (ASCII MIC!). Must match exactly.
version 0x04 2 B u8, u8 Major (byte 4) · Minor (byte 5). This spec is 01 00.
flags 0x06 2 B u16 LE Global container flags. See §07 Flags. Bit 0 = has thumbnail block.
image_count 0x08 2 B u16 LE Number of embedded images (0–65535). Determines index table size.
created_at 0x0A 8 B u64 LE Unix timestamp (microseconds since epoch) when file was created.
header_crc32 0x12 4 B u32 LE CRC-32 of bytes 0x00–0x11 (with this field zeroed during computation).
reserved 0x16 10 B u8[10] Must be zero. Reserved for future use (extension chunk offsets, etc).

Index Table — N × 64 bytes at offset 0x20

Each index entry is exactly 64 bytes. The table allows a reader to locate, verify, and describe any image in the container without reading any image data. Entries are ordered by insertion order (index 0 = first image added).

Field Offset in Entry Size Type Description
data_offset +0x00 8 B u64 LE Absolute byte offset from file start to the start of this image's data block.
data_size +0x08 8 B u64 LE Byte length of the image data block (excluding padding).
width +0x10 4 B u32 LE Image width in pixels. 0 if unknown/not applicable.
height +0x14 4 B u32 LE Image height in pixels. 0 if unknown/not applicable.
codec_id +0x18 2 B u16 LE Format identifier. See §08 Codec IDs. e.g. 0x0001 = PNG.
color_space +0x1A 1 B u8 Color space identifier. See §09. e.g. 0x01 = sRGB.
bit_depth +0x1B 1 B u8 Bits per channel (e.g. 8, 10, 12, 16, 32).
channel_count +0x1C 1 B u8 Number of channels (1 = grayscale, 3 = RGB, 4 = RGBA).
entry_flags +0x1D 1 B u8 Per-image flags. Bit 0 = has alpha, Bit 1 = has thumbnail, Bit 2 = encrypted.
thumb_index +0x1E 2 B u16 LE Index into thumbnail block for this image's thumb. 0xFFFF = no thumbnail.
data_crc32 +0x20 4 B u32 LE CRC-32 of the raw image data bytes at data_offset.
label +0x24 24 B u8[24] Null-terminated UTF-8 label / filename (max 23 chars + null). Remaining bytes zero.
reserved +0x3C 4 B u8[4] Must be zero. Reserved for per-entry extension use.
Tip — Fast Metadata Scan To enumerate all images and their metadata, read 0x20 through 0x20 + (image_count × 64). No image data needs to be read.

Thumbnail Block — optional, follows index table

Present only when global flag bit 0 is set. Contains a compact sub-header followed by raw thumbnail data for each image that opted into thumbnails.

FieldOffsetSizeTypeDescription
thumb_magic+0x004 Bu8[4]Sub-block magic: 54 48 4D 42 (THMB).
thumb_count+0x042 Bu16 LENumber of thumbnail entries that follow.
thumb_width+0x062 Bu16 LEUniform thumbnail width in pixels (e.g. 128).
thumb_height+0x082 Bu16 LEUniform thumbnail height in pixels (e.g. 128).
thumb_codec+0x0A2 Bu16 LECodec for all thumbnails (typically 0x0003 = JPEG for space efficiency).
reserved+0x0C4 Bu8[4]Zero-padded.
thumb_entries[]+0x10variablesee belowArray of thumb_count variable-length entries.

Each thumbnail entry is:

FieldSizeTypeDescription
thumb_data_size4 Bu32 LEByte length of thumbnail data that follows.
thumb_dataN Bu8[N]Raw thumbnail bytes (JPEG, PNG, etc. per thumb_codec).
padding0–15 Bu8[]Zero-padding to next 16-byte boundary.

Image Data Blocks — 16-byte aligned

Each image data block stores the raw bytes of the encoded image. Blocks appear consecutively in index order, each starting at a 16-byte aligned offset to permit direct SIMD loads.

FieldSizeTypeDescription
block_magic4 Bu8[4]Per-block magic: 49 4D 47 21 (IMG!). Allows forward scanning.
image_index2 Bu16 LEIndex of this image in the index table. For validation during forward scan.
block_reserved2 Bu8[2]Zero-padded.
image_datadata_size Bu8[N]Raw image bytes as stored by the codec (PNG IHDR…IEND, JPEG SOI…EOI, etc.).
padding0–15 Bu8[]Null bytes to align next block to 16-byte boundary. padding = (16 - ((8 + data_size) % 16)) % 16
Important The data_offset in the index entry points to the start of the 8-byte block header (IMG! magic), not to the image payload itself. Readers must skip 8 bytes to reach raw image data.

Global Container Flags — flags field at 0x06

Bit 0 — 0x0001
HAS_THUMBNAILS
Thumbnail block present after index table.
Bit 1 — 0x0002
SORTED_BY_SIZE
Images are sorted by file size ascending for streaming use cases.
Bit 2 — 0x0004
ALL_SAME_FORMAT
All images share the same codec_id. Optimization hint.
Bit 3 — 0x0008
CONTAINS_ANIMATION
Images form an animation sequence; use codec_id 0x0010+ for frame metadata.
Bit 4 — 0x0010
READONLY
Writer signals file should not be modified. Advisory only.
Bits 5–15
RESERVED
Must be zero. Future versions may define additional flags.

Codec Identifiers — codec_id (u16)

codec_idNameMIME TypeStatus
0x0000RAWimage/rawCore
0x0001PNGimage/pngCore
0x0002JPEGimage/jpegCore
0x0003JPEG XLimage/jxlCore
0x0004WebPimage/webpCore
0x0005AVIFimage/avifCore
0x0006GIFimage/gifOptional
0x0007BMPimage/bmpOptional
0x0008TIFFimage/tiffOptional
0x0009HDR (RGBE)image/vnd.radianceOptional
0x000AEXR (OpenEXR)image/x-exrOptional
0x000BQOIimage/qoiOptional
0x0010–0x00FFAnimation framesReserved
0x8000–0xFFFFVendor-definedCustom
Raw Format (0x0000) When codec_id is RAW, image data is an uncompressed pixel buffer. Layout is determined by color_space, bit_depth, and channel_count. Row stride = width × channel_count × (bit_depth / 8), rows packed without padding.

Color Space & Channel Layout — color_space (u8)

ValueNameDescription
0x00UNKNOWNColor space not specified.
0x01sRGBStandard sRGB (IEC 61966-2-1). Most web images.
0x02LINEAR_RGBLinear light RGB. No gamma curve.
0x03DISPLAY_P3Apple Display P3 wide gamut.
0x04REC2020BT.2020 wide color gamut (HDR).
0x05ADOBE_RGBAdobe RGB (1998).
0x06CMYK4-channel CMYK print space.
0x07GRAYSCALESingle-channel luminance.
0x08LABCIE L*a*b* perceptual color space.
0x09YCbCrLuma + chroma (common in JPEG internals).
0x80–0xFFVENDORVendor/application-defined color spaces.

EOF Marker — 8 bytes

The final 8 bytes of a valid MIC file must be the EOF marker. This allows tail-readers and validators to quickly confirm a file was written completely.

// EOF marker bytes (always at end of file) u8[8] eof_marker = { 0x45, 0x4E, 0x44, 0x4D, 0x49, 0x43, 0x21, 0x00 }; // 'E' 'N' 'D' 'M' 'I' 'C' '!' NUL

Reader / Writer Pseudocode

Reader

Pseudocode function read_mic(path): file = open(path, "rb") // 1. Read and validate header (32 bytes) header = file.read(32) assert header[0:4] == b"MIC!" image_count = u16le(header[8:10]) // 2. Read entire index table index = [] for i in 0..image_count: entry = file.read(64) // 64 bytes per entry index.append(parse_entry(entry)) // 3. Random access to image N function get_image(n): e = index[n] file.seek(e.data_offset + 8) // skip IMG! header raw = file.read(e.data_size) assert crc32(raw) == e.data_crc32 return decode_by_codec(raw, e.codec_id)

Writer

Pseudocode function write_mic(images, path): // 1. Encode all image payloads first (to know sizes/offsets) payloads = [encode(img) for img in images] // 2. Compute data block offsets base = 32 + len(images) × 64 // header + index table // (add thumb block size here if HAS_THUMBNAILS) offsets = [] cursor = base for p in payloads: offsets.append(cursor) block_size = 8 + len(p) cursor += block_size + pad16(block_size) // 3. Write header file.write(b"MIC!") file.write_u16le(VERSION) // 0x0100 file.write_u16le(flags) file.write_u16le(len(images)) file.write_u64le(unix_micros()) file.write_u32le(crc32_header()) file.write(zeros(10)) // reserved // 4. Write index table for i, img in enumerate(images): file.write_u64le(offsets[i]) file.write_u64le(len(payloads[i])) file.write_u32le(img.width) file.write_u32le(img.height) file.write_u16le(img.codec_id) ... // remaining index fields file.write(img.label.encode("utf-8").ljust(24, b'\x00')) // 5. Write data blocks for i, p in enumerate(payloads): file.write(b"IMG!") file.write_u16le(i) file.write(b'\x00\x00') file.write(p) file.write(zeros(pad16(8 + len(p)))) // 6. Write EOF marker file.write(b"ENDMIC!\x00")

Versioning & Extensibility Rules

The version field encodes [major, minor]. Readers should:

Extension Chunks (future) Future minor versions may introduce an optional extension chunk area between the thumbnail block and image data. These will use a CHUNK_MAGIC (4B) + chunk_size (4B) + payload pattern so older readers can skip them. The 10 reserved bytes in the file header may be used for an extension chunk table offset in v1.x.
Quick Reference — MIC v1.0
Magic
4D 49 43 21
Header size
32 bytes
Index entry
64 bytes
Index offset
0x20
Block alignment
16 bytes
Max images
65,535
Endianness
Little-endian
Checksum
CRC-32