# The .mcap file One capture in one file: a fixed magic, a file version stamp, the capture's data as [Capture Text](capture_text.md), what OCR read in it, a small preview, then the images. There is no ZIP and no compression around it; the images keep their own PNG compression. The parts a library browser needs (header, text, OCR and preview) come first, so it reads the start of each file and never touches the images; a search, which needs no preview, reads less still. ## Layout, version 2 All integers are little-endian. Sizes count bytes. | Field | Type | | | --- | --- | --- | | magic | 8 bytes | `89 4D 43 41 50 0D 0A 1A`, which is `\x89MCAP\r\n\x1A`. Says this is an .mcap, in every version. | | file version | u32 | `2`. Version 1 files are still read; see below. | | text size, text | u32, bytes | Capture Text, UTF-8: every JSON file of the capture, as `[[file]]` sections. | | OCR size, OCR | u32, bytes | OCR text, UTF-8 (below): what each OCR model read. Size 0 when none has. | | preview width, height | u16, u16 | In pixels. | | preview size, preview | u32, bytes | PNG. Size 0 when there is none. | | original name size, name | u16, bytes | The original image's name in the .snagx, such as `{GUID}.png`; the page's `CaptureBackgroundImage` names it too. | | original size, original | u32, bytes | The capture as taken: PNG, exactly as it was in the .snagx. | | rendered kind | u8 | 0: none. 1: the same as the original (stored once). 2: its own, below. | | rendered size, rendered | u32, bytes | Only for kind 2. The capture with its annotations drawn in (Snagit's `thumbnail.png`): PNG, exactly as it was. | The file ends there: anything after the last part is a mistake. The magic borrows PNG's: the first byte has its high bit set, so a channel that strips it shows; `\r\n` shows line endings being converted; and `\x1A` stops `type` on Windows. **Version 1** is the same without the OCR size and OCR. A reader takes both; anything written is version 2, so a version 1 file becomes version 2 the first time OCR is stored in it. ## The parts - **Text.** Everything the capture's JSON held: `index.json`, `metadata.json`, the page's `{GUID}.json`, and `{GUID}.backup.json` when there is one. - **OCR.** One section per OCR model, so a capture read by several models keeps every reading; reading it again with a model replaces only that model's section. See *OCR text* below. - **Preview.** The rendered image (or the original, when there is no rendered one) scaled so its longest side is at most 320 pixels, as a PNG. An image already that small is used as it is, never scaled up. - **Original and rendered.** A capture with no annotations has a rendered image identical to the original, byte for byte; it is then stored once, as kind 1. - **One page.** An .mcap holds one page, as every capture so far does; a .snagx with more is not converted. - **Left out:** `{GUID}.backup.png`, Snagit's image from before an edit. Its `{GUID}.backup.json` is kept, as plenty of captures have one without the image. ## Versions A reader checks the magic, then the file version. It refuses a version above its own, never writing over a file from a later version, and reads every version up to its own. Version 0 does not exist. ## Converting `snagit-converter mcap` converts .snagx files (or extracted captures) to .mcap, and `snagit-converter snagx` converts .mcap files back to a .snagx Snagit can open. See the README for what each checks. Back in a .snagx, the JSON is laid out as Snagit writes it, the images are the same bytes, and only the backup image is missing. JSON numbers come back as values: `3.0` is written `3`. ## OCR text In the style of the Ex4 text formats: ``` @version 2 [ocr ppocr-v5-mobile] engine: "onnxruntime 1.30.0, CUDA" image: rendered 1920 1080 date: 2026-10-08T21:04:11Z line: 412 96 640 18 412 96 1052 96 1052 114 412 114 0.993 "Assign Footprints - KiCad" line: 20 140 220 14 20 140 240 140 240 154 20 154 0.981 "Symbol : Footprint Assignments" line: 1700 300 20 160 1720 300 1720 460 1700 460 1700 300 0.952 "Read downwards" ``` | Key | Value | | --- | --- | | `[ocr NAME]` | A section: the model's name, as in its `models.config`. | | `engine` | What ran it, quoted. | | `image` | Which image was read (`rendered` or `original`) and its width and height; the lines' boxes are in its pixels. | | `date` | When it was read, UTC. | | `line` | A text line: x, y, width and height, then its four corners as x y pairs, its confidence (0 to 1), and its text, quoted with `""` for a quote. A control character in the text is written as a space. | The corners go clockwise from the text's top left: top left, top right, bottom right, bottom left, as the text reads. Level text has the box's corners; a turned line's say which way it reads (the third line above reads downwards, so its top left is the box's top right). x, y, width and height bound them. A line that cannot be read is skipped, as are keys this version does not know. **Version 1** OCR text had no corners (`line: x y width height confidence "text"`); it is still read, with the box's corners. The OCR text carries its own version, so this did not change the .mcap file version. `mcap_store_ocr` (`modules/Capture_File/ocr_text.jai`) stores a section in a file.