Files

258 KiB
Raw Permalink Blame History

INDD objects

How the byte stream of a database object (see database.md) is structured, and what the classes and chunks used by the converter mean. Implemented in src/object.rs and src/model/.

How this was learned

IDML exported by InDesign names most objects Self="u<hex>", and that hex number is the object's UID in the INDD file. So each corpus pair gives, for every such IDML element, the INDD object, its class, and the attribute values its chunks must encode. Facts below were found by comparing the two, and are checked by tools/compare.py, which converts every pair (78 unique pairs, InDesign 7.5–21) and compares the output with the reference IDML attribute by attribute.

Chunks

Most objects (99.9 % of 773,753 in the little-endian corpus) are a sequence of chunks:

Size Field
4 Chunk ID
4 Data length n
n Data

The rest are plain byte streams: objects of class 0x129 (raw data, below) and the XMP packet (UID 0x80000001). In the 245 distinct little-endian files, all 1,171 class 0x129 objects are plain byte streams. Chunk IDs are in the same number space as class IDs; a chunk often lists objects of the class with the same number (for example chunk 0x501 of the document lists spreads, class 0x501).

Primitive encodings

Object data is in the byte order of the header's flag (header.md). All samples except two are little-endian, and the examples here are little-endian. Big-endian data and the layouts of InDesign 3.0 and 4.0 are in big-endian.md.

  • UID lists: u32 count, then that many u32 UIDs.
  • Matrices: six f64, in IDML ItemTransform order (a b c d tx ty).
  • Text segments: a u16 header, flags in bits 14–15 and a count in bits 0–13. 0x4000: count single-byte characters follow. 0x8000: count UTF-16 code units follow. A text of n code units is a sequence of segments adding up to n. Example: "WOMEN’S\r" is 05 40 "WOMEN" 01 80 19 20 02 40 "S\r".
  • In-object strings: u8 2, u8 (usually 0; a script code in some strings, below), u16 length in code units, then segments. 4,135 occurrences in three sample files. In files from InDesign 2.0 the first byte is 1: in the four distinct 2.0 files, the pattern tag, 0, length n, 0, segment header 0x4000 + n occurs 154 to 353 times per file with tag 1 and never with tag 2. In the 83 distinct 3.0, 4.0 and 5.0 little-endian files the same pattern has tag 2 (76 to 4,296 times per file); tag 1 matches once in each of two of them.

Document (class 0xE01, always UID 1)

Chunk Contents
0x501 UID list: spreads, in order
0x1401 UID list: master spreads
0x301 UID list: layers (the first is an internal layer that holds pages)
0x313 u32: active layer (IDML ActiveLayer)
0x222 Two UID lists: the stories, then the XML backing story; IDML StoryList is both (xml.md)
0x4C01 UID list: sections
0xA443 Document users: u32 count, then per user a flag byte, the name as an in-object string, u32 colour
0x1D8 Save history: u32 count, then one record per session (below)
0x1630B Label: u16 0x7B7B, u32 count n, then n pairs of key and value, each a flag byte and an in-object string
0x21B03 UID list: articles, in order (below, articles)

Document label. IDML writes Document/Properties/Label with one KeyValuePair (Key, Value) per stored pair, in stored order, with the strings as stored. Without the chunk there is no Label. Evidence: 436 of the 438 trustworthy pairs whose IDML has a document label match (one differs, one has no chunk). The flag byte is 1 on 4 keys in 4 pairs, all others 0; the 3 of these pairs whose IDML has a document label write the key without the $ID/ prefix of built-in names.

Script byte of the user names. The second byte of each user name's in-object string (the byte after the string tag) is a script code: 0 in documents in Latin script, 1 in all 9 trustworthy pairs with Japanese user or assignment names, 7 in a Russian, 25 in a Simplified Chinese and 29 in a Czech document. The same codes are font writing scripts (1 for Japanese fonts, 25 for Simplified Chinese fonts). All users of a document have the same byte, except in one pair with users of bytes 0 and 7. The converter uses the byte of the last user to choose font family names (fonts.md, native family names).

Other in-object strings carry the same kind of byte, so a search for a string must accept any second byte. In the 149 pairs typeset in Japanese it is 1 for most user-made names, and 3, 5, 7, 0x19 and 0x1D also occur, in style names, style GUIDs, layer names and ruby font styles. Layer names and style GUIDs (below) rely on this.

Document users. IDML lists one DocumentUser per user in chunk 0xA443, Self being dDocumentUser and the index in hexadecimal (491 of 495 trustworthy pairs have as many users as the chunk; the other 4 are DOM 7 and 16 files with one user more in the IDML). A user with flag 0 has its stored name as UserName (1,724 of 1,724). Flag 2 marks the placeholder for an unknown user, stored with a name such as Unknown User Name or the same words in the language of the computer that saved it; IDML writes $ID/Unknown User Name for 495 of the 586 such users, and the stored name for the other 91. The rule is the saving edition's name for an unknown user (saving edition, below): IDML writes $ID/Unknown User Name for every user, of either flag, whose stored name is that edition's, and the stored name for every other user, also a flag 2 user named in another language (for example Unknown User Name in a document last saved by a Korean edition). Without a black name the converter writes $ID/Unknown User Name for every flag 2 user (the schema requires UserName). The colour UID names an interface colour, but the IDML UserColor does not follow from it (users stored with 0.6, 0.4, 0 are BrickRed in 4 files and Gold in 1), so it is left out of the conversion and of the measurement (measurement.md).

Save history (chunk 0x1D8). A u32 count, then one record per session that saved the document, oldest first:

Field Contents
u16 kind (not used)
u16 platform: 0 or 3 (style shortcuts, below)
u16, u16 not identified
u16 language code (below)
flag byte, in-object string application version, such as 16.1.0.20
u16 build (not used)
u32, u32 FILETIME of the session, high part first (not used)

Evidence: the layout parses every record of 4,431 of the 4,439 distinct valid corpus files outside the privately held samples (4,272 little-endian, 159 big-endian), from InDesign 3.0 to 21. Of the other 8, six are InDesign 2.x files whose strings have another tag (in-object strings, above) and two (one 3.x, one 13.x) have no chunk. All 803 pairs parse.

Language code. The u16 of the last record is 0x0100 in 4,018 of those files, 0x0101 in 335, 0x0103 in 53 and 0x0400 in 25. It follows the language edition of the application of that session:

  • All 149 pairs typeset in Japanese that the corpus gained in 2026-10 have 0x0101; so do 11 earlier pairs, among them the 7 whose default story tag name (preferences chunk 0xBF4F) is Japanese or Chinese. No document with a tag name in another language (Korean, German, French, Russian, …) has 0x0101 (654 pairs before 2026-10).
  • The values IDML writes in the exporting InDesign's language follow it (below): in 0x0101 documents the flattener resolution, the index title and separator and the endnote separator are those of a Japanese edition.
  • 0x0103 occurs in documents in Latin and Hebrew script; it gives the same values as 0x0100 in all 12 pairs that have it.

The converter reads the code of the last record only, and only uses whether it is 0x0101.

Application version. The version string of the last record can be later than the version in the header: InDesign 13.1 saved files whose header says 13.0. IDML writes some values only from 13.1, and follows the application, not the header. Over the trustworthy pairs of version 12.0 to 14.0 (corpus after 2026-10), the document's TextFramePreference has the Footnotes… values:

Header Last session IDML DOMVersion Pairs With the values
12.0, 12.1 same same 72 0
13.0 13.0 13.0 42 0
13.0 13.0 13.1 16 16
13.0 13.1 13.1 93 93
13.1 13.1 13.1 148 148
14.0 14.0 or 14.3 14.0 43 43

The 16 were exported by InDesign 13.1 without saving, which the INDD cannot show. The converter takes a 13.1 boundary as reached when the header or the last session is at least 13.1: for the Footnotes… values of the document, of text frames and of object styles, and for MergeConsecutiveParaBorders. This adds 93 to 253 values for each of these keys and no wrong or extra value. The record count is checked against the chunk size; a chunk that does not parse gives no code.

Values that follow the language of the last session. Over all 803 pairs (160 with code 0x0101):

Value 0x0101 Other codes
Spread FlattenerPreference resolutions, no chunk 0x10833 400, 400 300, 150
IndexOptions BetweenEntriesSeparator, no chunk 0x13010 (preferences.md) 、 in 157 of 159 ; in 632 of 632
IndexOptions Title, no chunk 0x13010 索引 in 158 of 159 Index in 624 of 632, and Indice, Rejstřík, Índice, Указатель
EndnoteOption EndnoteSeparatorText and EndnoteMarkerPositioning, no chunk 0x2261E (footnotes.md) U+3000 and RubyMarker in 17 of 18 tab and SuperscriptMarker in 123 of 123
EndnoteOption EndnoteTitle, no chunk 0x2261E 文末脚注 (15, DOM 13), 後注 (2, DOM 19 and 20), Endnotes (1) Endnotes in 93 of 123, and 4 other titles
Assignment Name $ID/UnassignedInCopy in 157 of 160 $ID/UnassignedInCopy in 612 of 643

One trustworthy pair from version 16.1 has code 0x0101 but the values of another language in every row (flattener 300 and 150 on its 9 spreads, Index, ; , tab, Endnotes). Its IDML is dated 55.5 hours after the last session in the INDD, while the IDMLs of 9 other 0x0101 documents are dated 0 to 40 seconds after it (plus their time zone). So that IDML was exported in a session the INDD does not record, by an application of another language.

The converter uses the code where it decides the value: the flattener resolutions, the index separator and the endnote separator. The index title, the endnote title and marker position and the unknown user follow the saving edition (below). It writes no assignment Name: names that are not $ID/UnassignedInCopy occur with every code.

Saving edition (the XMP black name). The XMP packet of the INDD lists the document's colours in xmpTPg:Colorants, each with xmpG:swatchName, xmpG:mode, xmpG:type and its values (cyan to black in percent, red, green, blue 0 to 255). Tints have an xmpG:tint and keep the stored name of their base colour. The black swatch is listed with the name the InDesign that saved the document gives it: Black, 검정, 黒, 黑色, Schwarz, Noir, Nero, Zwart, Černá, Preto, Черный. The converter takes as the black name the swatchName of the one colorant that is not a tint, is a process colour, has the mode and values of the document's black colour (Color/Black, as IDML writes its values) and whose name no other colour of the document has. Over the 1,251 trustworthy pairs of the corpus after 2026-10 there is exactly one such colorant in each: 502 검정, 431 Black, 126 黒, 93 黑色, 45 Schwarz, 44 Noir, 4 Nero, 3 Zwart and one each of Černá, Preto and Черный.

This is a rule over stored data: the packet records the edition of the last save, and IDML follows the edition that exported it. Where a document was exported by another installation than the one that saved it last, the IDML has the other edition's values; the exceptions below are such documents.

IDML writes these values in the language of that edition:

Black name Tint of black Unknown user Endnote title (no chunk 0x2261E) Index title (no chunk 0x13010)
Black [Black] 40% Unknown User Name Endnotes Index
검정 [검정] 40% 알 수 없는 사용자 이름 미주 색인
黒 不明なユーザー名 文末脚注 (DOM 13), 後注 (DOM 19, 20) 索引
黑色 [黑色] 40% 不明的使用者名稱, 未知用户名 索引
Schwarz [Schwarz] 40% Unbekannter Benutzername Endnoten Index
Noir [Noir] 40% Nom d'utilisateur inconnu Notes de fin Index
Nero Nome ut. sconosciuto Note di chiusura Indice
Zwart Onbekende gebruikersnaam Eindnoten Index
Černá Neznámé jméno uživatele Rejstřík
Preto Nome de usuário desconhecido Índice
Черный Неизвестное имя пользователя Указатель

An empty cell has no sample. The endnote marker is RubyMarker for 黒 and SuperscriptMarker for every other black name.

With these rules the converter reproduces, over the trustworthy pairs:

Value Reproduced Before (assignment name and code rules)
Tint elements and their names (tints of black) 204 of 204 tints, no extra tint 171, and 409 extra values in 27 documents
DocumentUser UserName 3,208 of 3,212 3,000
EndnoteOption EndnoteTitle 917 of 918 692 (no title without the chunk)
EndnoteOption EndnoteMarkerPositioning 916 of 918 876
IndexOptions Title 1,250 of 1,251 1,162

The remaining differences are the 16.1 document above (exported by another edition: three users, its endnote title and its index title), one 20.0 document whose black name is Black but whose IDML writes the German name of the unknown user as $ID/Unknown User Name (two users), and DOM 7 documents whose IDML lists one user more than the INDD. In 8 stale pairs the rule loses 1 to 3 values each: their IDML was exported by another edition than the one that saved the INDD later (for example a Dutch endnote title in a document whose last save has Black).

Not explained by the black name: BaselineFrameGridColor, ColumnGuideColor, the grid and gutter defaults and the print marks of the Korean documents with code 0x0101 whose IDML has the values of a Roman edition (preferences.md, values of the exporting edition), the language quotes and the trimmed language lists.

Spreads (0x501) and master spreads (0x1401)

Chunk Contents
0x503 u32 self, u32 0, UID list of spread layers
0x56E Matrix: ItemTransform
0x1B8 u32: BindingLocation
0x1A8 u16: 0 = AllowPageShuffle="true", 1 = false
0x10833 Flattener settings (below)
0x14580 Tab orders: u32 count, then per page u32 page UID and a UID list (the page's TabOrder)
0x140D Master spreads: u16, 0 = ShowMasterItems="false"
0x140A Master spreads: u32 story of the primary text frame (below)
0x2050C Page transition (12 bytes): u32 type code, u32 40, u32 direction code (below)
0x2056D Timing lists (animation and timing, below)

Evidence, over the 5,129 spreads and 914 master spreads of the 495 trustworthy pairs:

  • AllowPageShuffle: 0x1A8 is 0 in 5,064 spreads, all true, and 1 in 53, all false. The 12 spreads without the chunk (in 7 documents) are all false.
  • ShowMasterItems of master spreads: 913 have no chunk 0x140D and are true; the one with the chunk (0) is false.
  • PrimaryTextFrame of master spreads, over all pairs of the corpus of 2026-10: IDML writes n when chunk 0x140A is absent (1,471 master spreads) or holds 0 (6). Otherwise it names the text frame on that master spread whose ParentStory is the chunk's story and whose PreviousTextFrame is n (50 of 50; in 40 of them the story has a second frame on the spread, which is not the primary one). IDML of DOM 7 has no PrimaryTextFrame (9 master spreads). The attribute is the last one of MasterSpread. The converter writes it from DOM 8 and leaves it out when the spread has no such frame: 1,521 of 1,521 values over all pairs with the same major version.
  • TabOrder of pages: the list for the page in its spread's chunk 0x14580 equals the IDML list for 9,367 of 9,367 pages (8 with a tab order); pages not in the chunk have an empty TabOrder.

Page transitions. Chunk 0x2050C gives PageTransitionType and PageTransitionDirection. Over the 11,676 spreads of the distinct little-endian pairs with the same major version (corpus after 2026-10):

u32 at 0 PageTransitionType u32 at 8 PageTransitionDirection Spreads (documents)
no chunk None NotApplicable 11,646 (1,453)
0 None 0 NotApplicable 12 (2)
0x205C8 BlindsTransition 0xB Horizontal 8 (4)
0x205CA CombTransition 0xB Horizontal 2 (2)
0x205CC DissolveTransition 0 NotApplicable 4 (4)
0x205CF PushTransition 1 Down 2 (2)
0x205D0 SplitTransition 0xD HorizontalIn 2 (2)

The u32 at 4 is 40 in every chunk, and every spread has PageTransitionDuration="Medium" (idml-values.md), so the field is not mapped. Master spreads have neither the chunk nor the attributes (2,395 of 2,395). The converter writes the two attributes on spreads for these codes, and leaves out an attribute whose code is not in the table.

Flattener settings. Every IDML spread has a FlattenerPreference child. Chunk 0x10833 (52 bytes) is in 20 spreads of 5 trustworthy documents, always with the same bytes: f64 0.5 at offset 8, f64 400 at offsets 20 and 28, 2 at 36 and 800 at 44. Their IDML has LineArtAndTextResolution and GradientAndMeshResolution 400 and RasterVectorBalance 50. In the corpus of 2026-10, 182 spreads of 20 trustworthy documents store 150 at 20 and 300 at 28, and their IDML has LineArtAndTextResolution="300" and GradientAndMeshResolution="150" (182 of 182): the f64 at 28 is LineArtAndTextResolution and the f64 at 20 GradientAndMeshResolution. Without the chunk, the IDML has 400 and 400 when the last session of the save history (document, above) has code 0x0101, and 300 and 150 otherwise: 7,481 of the 7,490 spreads of all 803 pairs match, the other 9 being the spreads of the pair exported in a session the INDD does not record. No stored resolution decides it: the bytes of 400 as f64 occur in 1 of the 10 such documents of the 654 pairs before 2026-10, and no byte of the spread chunks separates the two groups. The converter writes the resolutions by this rule, and none when the history cannot be read. The other four values are the same in every IDML (idml-values.md).

Spread layers (0x301) hold the items of one document layer on one spread. Chunk 0x302: u32 document layer UID, u16 1 for the layer's guide part. Chunk 0x303: u32 spread, u32 spread, UID list of children. Pages are children of the spread layer for the internal pages layer.

Guides (0x3301)

Ruler guides are objects of class 0x3301. They are children of a spread layer (listed in its chunk 0x303), like page items, and their chunk 0x15B names the spread and the spread layer. The spread layer's document layer is IDML ItemLayer. IDML writes a guide as a Guide element inside a Page element. Chunk 0x3308 (52 bytes):

Offset Contents IDML
0 f64 position in spread coordinates: y for a horizontal guide, x for a vertical one Location (below)
8 u32 owner: a page of the spread, or the spread itself the Page element the guide is in
12 u16 orientation: 1 horizontal, 0 vertical Orientation
14 f64, 0.05 in every sample ViewThreshold="5" in every sample
22 u32, 6 in every sample GuideColor Cyan in every sample
26 u16 fit to page: 1 true, 0 false FitToPage
28 f64, not identified
36 u32, not identified (24, 25, 30 or 31)
40 u32 guide type: 0 ruler, 1 liquid GuideType (Ruler, Liquid)
44 f64, 1 in every sample

Evidence. The 137 distinct little-endian files hold 847 guides; 815 have this 52-byte record. The other 32 are in one InDesign 7.0 file with no IDML and have a 40-byte record, the first 40 bytes of the layout above; the InDesign 3.0 and 4.0 files have it too (big-endian.md). The converter reads it and leaves out GuideType. In the corpus pairs, 71 IDML guides in 33 distinct files have an INDD object with the same UID. Two more pairs have the same number of guides on both sides but different UIDs (the IDML was exported from another save) and are not used. For the 71:

  • Orientation: 71 of 71 (50 horizontal, 21 vertical).
  • FitToPage: 71 of 71 (49 true, 22 false).
  • GuideType: 71 of 71 (59 ruler, 12 liquid).
  • ItemLayer: 71 of 71.
  • Owner: the 49 guides owned by a page are in that page's element, the 22 owned by the spread are in the spread's first page (71 of 71). All 22 spread guides have FitToPage="false" and all 49 page guides FitToPage="true".
  • The view threshold and colour have one value each in the INDD and in IDML, so the fields are not proven. The converter writes ViewThreshold="5" only for 0.05 and GuideColor Cyan only for 6.

Location. IDML measures Location from the ruler origin (ViewPreference RulerOrigin, chunk 0x808 of the preferences, preferences.md). It is the stored position minus the origin's y (horizontal guides) or x (vertical guides). A page's corner is its GeometricBounds corner mapped by its ItemTransform. The origin is:

  • SpreadOrigin: the top-left corner of the spread's pages (the smallest left and top edge of any page).
  • PageOrigin: the top-left corner of the guide's own page; for a guide of the spread, the corner of the spread's pages as with SpreadOrigin.
  • SpineOrigin: for vertical guides on a spread of two pages, the left edge of the right page (x = 0 in the samples); otherwise as with SpreadOrigin.

IDML computes the difference after adding the spread's translation (ItemTransform of the spread) to both values: (position + t) − (origin + t). This only changes the last bits, but it decides whether a guide on the origin gets 0 or a remainder such as −1.1e-13. Over the 1,252 trustworthy pairs it gives the IDML number exactly for 8,580 of the 9,127 guides in SpreadOrigin documents (7,782 without the translation); the others differ only in the last digits.

Evidence. All 553 guides of the 23 trustworthy pairs with PageOrigin follow the rule: 435 page guides (304 horizontal, 131 vertical, on spreads of one, two and five pages) and 118 spread guides (116 horizontal, 2 vertical on one-page spreads). The 9,127 guides of SpreadOrigin documents follow it but for 25 (below), including pages whose bounds do not start at 0. The one SpineOrigin file (a stale pair, InDesign 15.0) has three vertical guides: on a two-page master spread at stored −552.76 and 42.52 with IDML −552.76 and 42.52 (from x = 0), on a one-page master spread at stored 0 with IDML 297.64 (from the page's left edge at −297.64); its horizontal guides are measured from the top of the pages. No spread of more than two pages with SpineOrigin was seen.

Guides at the spread origin. In 5 trustworthy pairs (InDesign 17.0, one collection), 5 guides each that belong to a page with FitToPage="true" have Location values that put them at 0 in spread coordinates: vertical guides stored at −457.14 and −58.47 get the spine's position, a horizontal guide stored at −9.92 gets y = 0. The stored positions lie inside their pages. No field of the guide record or the guide's other chunks separates them from the other guides of the same documents (unknowns.md). The converter writes the stored position.

Spread guides outside the pages. IDML leaves out a guide owned by the spread when its position lies outside the bounding box of the spread's pages (each page's corners mapped by its ItemTransform; the bleed does not count): for a horizontal guide when its y is above the top or below the bottom, for a vertical one the same with x. Over the 489 trustworthy pairs before 2026-10: 84 of 85 such guides are left out (positions such as −15, −66 or 1215 on pages 1200 wide), all 1,198 spread guides inside are written, and all 5,740 page guides are written wherever they are. With the bleed added, 30 of the left-out guides would be inside. The exception is a horizontal guide at −9 on a master spread, which IDML writes; its object has chunks 0x1424 and 0x1425, which no left-out guide has. The converter leaves out such guides (with a tolerance of 1e-6).

Other settings. A guide has chunks 0x2C2D (Locked) and 0x1424 (OverriddenPageItemProps) as page items do (Page item settings), and the f64 at offset 44 of the 52-byte record is GuideZone. Over the 7,003 guides of the trustworthy pairs: Locked 7,003 of 7,003 (3 locked), GuideZone 6,988 of the 6,988 with a 52-byte record (464 with 0), OverriddenPageItemProps 6,988 of 6,988; the 15 guides with a 40-byte record have neither attribute in IDML.

PageIndex counts from the spine of the spread: 0 for a guide of the spread itself; for a page guide, the pages left of the spine are −1, −2, … (counting outwards) and those right of it 1, 2, …, the spine being after BindingLocation pages; on master spreads it is at the left edge. This gives 6,998 of 7,003 (1,215 spread guides 0; 2,266 of 2,269 page guides on document spreads, 473 of them −1 and 12 −2; 3,517 of 3,519 on master spreads).

Layers (0x302)

Chunk 0x304:

Offset Contents IDML
0 u16 Locked (1 = true)
2 u16 Visible
4 u16 Printable
6 u16 LockGuides
8 u16, 1 in every sample
10 u32 UID of an interface colour LayerColor (below)
14 u16 UI
16 u16, 1 in every sample
18 u8 flag, in-object string Name
after the name u16 IgnoreWrap

The internal layer is the first UID of the document's layer list (chunk 0x301 of UID 1) and has no IDML element: in 489 of 489 trustworthy pairs that layer is not written. It is usually named Internal_pages_layer_name (467), but also Pages (20) or has an empty name (2), so the name does not identify it. In all 1,053 layers of the trustworthy pairs the name starts at offset 19, and each field above equals the IDML value for 1,053 of 1,053 layers (127 locked, 55 hidden, 59 not printable, 4 with locked guides, 1 without UI, 2 ignoring text wrap). In the corpus of 2026-10, the string at offset 19 gives the IDML Name of 1,683 of 1,683 layers in all pairs, whatever its second byte (in the trustworthy pairs, 188 layers have a byte other than 0, all with the IDML name). The converter reads the name at offset 19 when byte 19 is the string tag, and otherwise searches for a string from offset 18. ShowGuides and Expendable are true in every layer; the two fields that are 1 in every sample may hold them. The converter reads the fields only when the name starts at offset 19 (in all little-endian corpus pairs, 1,465 layers).

Pasted smooth shades (0x5533)

Objects of class 0x5533 hold shadings. Chunk 0x5531: a flag byte (1 = built-in key) and the name, then a u32. Chunk 0x5532 holds the shading; a constant shade has 92 bytes, with u32 28 (the length of what follows) at offset 60, then a u32 and three f64. IDML writes it as a PastedSmoothShade with ContentsType="ConstantShade" and Contents the base64 of the same u32 and three f64 in big-endian order (AAAAAUBv4AAA… for 1 and 255, 0, 0).

Every trustworthy pair has one constant shade in IDML, and it is the class 0x5533 object of lowest UID with a constant shade (495 of 495); in 84 pairs the INDD has two more that IDML leaves out. The converter writes that one shade, and matches the IDML on all values in 495 of 495 (name $ID/ from flag 1 and an empty name; two contents values, 255 and 1).

Axial shades. Chunk 0x5532 in general: u32 0 at 0; six f64 at 4 (a matrix); u32 0 at 52; u32 shading type at 56; u32 n at 60; n bytes of shading data from 64, to the end of the chunk. A constant shade has type 0 and n = 28. Type 5 is an axial shade, which IDML writes as ContentsType="AxialShade" with ContentsMatrix the six f64 and Contents the base64 of the shading data with every field converted to big-endian. The data is a sequence of fields:

shading:
  f64 ×6                      coordinates
  u16 ×4                      (0 or 1)
  u32 colour space            (2 in every sample)
  u32 function count F
  function ×F
  u32                         (4 in every sample)
  f64 ×6
  u32                         (2 in every sample)
  u16 ×2                      (0 or 1)
function:
  u32 function type           (0 in every sample)
  u32 inputs, u32 outputs     (1 and 1 in every sample)
  u16, u32 c, f64 ×2c         domain
  u16, u32 c, f64 ×2c         range
  u32, u32 c, f64 ×2c         encode
  u32 c, f64 ×2c              decode
  u16
  u32, u32 bits per sample (8 in every sample), u32 byte count B
  u8 ×B                       samples, not swapped

Over all pairs of the corpus of 2026-10 the INDD files hold 3,725 axial shades (3,704 in 37 trustworthy pairs); the grammar consumes every chunk to its end. IDML has 900 axial shades (891 in 12 trustworthy pairs), and the converter's Contents, ContentsMatrix and other attributes equal IDML's for all 900. The name chunk is that of constant shades ($ID/). The other attributes are those every IDML has on an axial shade (idml-values.md), and SwatchColorGroupReference from DOM 12 as for other swatches. Type 6 also occurs (43 objects in trustworthy pairs); IDML writes none of them, so its layout is not needed. A shading with another value where the grammar names the value of every sample, or with bytes left over, is left out with a warning.

Which axial shades IDML writes. The rule of unnamed colours (colours, below): a shade is written when a value in the package refers to it, or when the page item defaults name it (chunk 0x6E07 or entry 0 of chunk 0x6E06, by class 0x5533). In the trustworthy pairs IDML writes 891 of the 3,704 axial shades, all 891 that the rule selects and none of the other 2,813. Of the 891, 884 are referred to by a page item's FillColor (attribute 0x6E68 of the item's chunk 0x6E03 holds the shade's UID; 744 rectangles of spreads and 140 of master spreads) and 7 are named by the defaults only. All references are rectangle fills.

Order. In Graphic.xml the shades follow the inks in UID order (the constant shade has the lowest UID), before Swatch/None: 12 of 12 trustworthy pairs with axial shades.

Index sort options

Chunk 0x1307E of the preferences object (class 0x2202) holds the index groups. A "string" is a flag byte and an in-object string; a "u32 string" is a u32 length in UTF-16 units and text segments.

u32 group count
group:
  string     group name (kIndexGroup_Symbol, kWRIndexGroup_GreekAlphabet, ...)
  u8         include
  u8         (not identified)
  u16        header variant
  u16        (not identified)
  u32        variant count
  variant:
    string      internal name
    string      UI string
    u32 string  document string
    u8          1 = visible
    u8          (0)
    u32         section count
    section:
      u32 string  sorting string
      u32 string  document header string
      string      UI header string
      u16         language

Every chunk of the 654 pairs parses to its end with this layout. The variants and sections have the same fields as the list that IDML writes under IndexHeaderSetting (preferences.md), which the converter takes from chunk 0x1300E. The converter uses the name, include byte and header variant of each group, and the internal name of the variant that the header variant indexes in the group's variant list.

IDML writes an IndexingSortOption per group, in the stored order: Self dIndexingSortOptionn and the name, Name $ID/ and the name, Include, Priority (the position, from 0) and HeaderType, which follows the internal name of the chosen variant:

Variant name HeaderType
IDX_Basic BasicLatin
IDX_Spanish Spanish
IDX_Czech Czech
IDX_Russian Russian
IDX_AllHira HiraganaAll
IDX_ChinesePinyin ChinesePinyin
IDX_ChineseStroke ChineseStrokeCount
IDX_KoreanConsonant KoreanConsonant
the group's own name (symbol, numeric, Greek, Arabic and Hebrew groups) Nothing

The converter leaves HeaderType out for other names. Evidence: the 495 trustworthy pairs before 2026-10 have 11 different lists (8 or 10 groups, in different orders, with different groups included). Over the 1,251 trustworthy pairs of the corpus after 2026-10 the converter reproduces all 12,472 HeaderType values. The variant index decides where the list order differs: the Chinese group has variant 0 in every file, but in 83 documents its list starts with IDX_ChineseStroke, and their IDML has ChineseStrokeCount (83 of 83); a table by group and variant number, used before, gave ChinesePinyin there. Over all 654 pairs before 2026-10 the Alphabet variant is 0 in 652 files, 3 and 5 in one each, and the Cyrillic variant is 2 in all.

Numbering lists (0x1A483)

Chunk 0x1A49B of the preferences object: u32 UID of the default list, u16 count n, n list UIDs, i32 −1. Each list has chunk 0x1A49A: a flag byte (1 for a built-in key; 0 and 2 plain) and the name, then u8 ContinueNumbersAcrossStories and, two bytes after the name, u8 ContinueNumbersAcrossDocuments (1 true); the rest is not identified.

IDML writes one NumberingList per list in designmap.xml, the default ($ID/[Default]) first, then the n lists in stored order, with Self NumberingList/ and the name. The paragraph attribute 0x1A417 (AppliedNumberingList, a Properties child of type object) is the UID of a list. Evidence: 705 of 705 lists of the trustworthy pairs (953 of 953 in all pairs), names, both flags and order; AppliedNumberingList 519 of 519 paragraph styles and 489 of 489 text defaults.

Assignments (0x1BE01)

Every document has one object of class 0x1BE01, listed in chunk 0x1BE13 of the document; IDML writes it as an Assignment with Self its UID (495 of 495 trustworthy pairs). Chunk 0x1BE1B starts with a flag byte and the name in the language of the edition the document was made with (Unassigned InCopy Content, Contenu InCopy non affecté, …; the converter uses it for values of that edition, preferences.md), then two empty strings and fields that are the same in every pair. IDML names it $ID/UnassignedInCopy in 476 pairs and gives the stored name in 19, in files of several languages and versions, so the name follows the computer that exported the IDML; the converter leaves Name out (it is optional in the schema) and the measurement too. The language code of the save history does not decide it either (document, above). The other attributes are the same in every IDML (idml-values.md).

Articles (0x21B01)

Article list. Chunk 0x21B03 of the document object: u32 count, then that many article UIDs. IDML writes one Article element in designmap.xml per listed UID, in list order (not UID order). Evidence: the 19 pairs whose IDML has Article elements or ArticleChildrenList (DOM 8.0, 10.1, 13.x, 20.5): the list order equals the IDML order for all 31 articles; the chunk is in all 19 (count 0 in the 6 with no articles), and its length is exactly 4 + 4 × count. In all 66 corpus INDD files that have article objects (INDD 7.5 to 21.2, 203 articles), the list holds exactly the document's 0x21B01 objects.

Article object.

Chunk Layout IDML
0x13C flag byte, in-object string Name
0x21B02 u32 count, then that many page item UIDs one ArticleMember per UID, in order, ItemRef="u<hex>"
0x1A8 u16 not mapped (below)
  • Self is u<hex UID>: 31 of 31 in pairs.
  • Name: the flag byte is 2 in all 203 articles of the corpus, and the string ends at the chunk's end in all 203. 31 of 31 names match in pairs (Latin, Hangul and Han text; segments with 0x40 and 0x80 encodings).
  • Members: 31 of 31 lists match the IDML ArticleMember ItemRefs in order. Without chunk 0x21B02 (2 articles) or with count 0 (2 in pairs), the IDML Article has no children. In the corpus, members are page items (class 0x6201) or groups (0x401); no other class appears (201 lists).
  • ArticleMember Self is the article's Self, ArticleMember, and the member's index from 0: u281ArticleMember0, u281ArticleMember1. 44 of 44 members in pairs. No corpus IDML has an article with more than 10 members, so whether the index is decimal or hexadecimal is not shown; the converter writes it in decimal.
  • ArticleExportStatus is true on every Article of every corpus IDML (31 in pairs; no other value in 3,557 IDML files). No stored field is identified; the converter writes true (idml-values.md, defaults).
  • Chunk 0x1A8 (u16) is in 50 of 203 articles: 1 in 47, 0 in 3. The one in a pair has 1 and ArticleExportStatus="true", as do the articles without the chunk; it is not mapped.
  • No corpus IDML has an Article Properties/Label, so an article's label chunk is not shown.

Page items. Chunk 0x21B04 of a page item or group: u32 count and the UIDs of the articles the item is a member of. 44 of 44 members in pairs have count 1 and their article's UID; 331 other items have count 0. IDML has no attribute for it; the converter does not read it.

ArticleChildrenList on groups. Chunk 0x21B05 of a group (class 0x401): u32 count, then UIDs. IDML Group has ArticleChildrenList="u<hex> u<hex> …" with these UIDs in order, exactly when the group has the chunk: 68 of 68 groups in 12 pairs; no group has the attribute without the chunk or the chunk without the attribute. The list is the group's children in reverse order of chunk 0x15B in 68 of 68 groups in pairs and 259 of 259 in the files with articles. Groups with the chunk also occur in documents without articles (4 pairs of 13.x). IDML writes the attribute directly after Self (68 of 68).

Element order. In designmap.xml the Article elements come last, after Assignment (all 13 pairs with articles). The schema puts Article in the final interleaved group with Assignment and others, so writing them after the assignments is valid. Article allows Self, Name, ArticleExportStatus, Properties/Label, then ArticleMember* (Self and ItemRef, both required).

Versions. Article objects occur in INDD 7.5 to 21.2. Pairs show DOM 8.0, 10.x and 20.x; no 7.x INDD with articles has an IDML. The converter writes articles for every version.

Damaged input. The converter writes each listed article once and skips listed UIDs that are not articles. An article without a readable name or member list is left out with a warning. A member that is not written as a page item element is left out with a warning, and so is an ArticleChildrenList UID that is not a child of the group.

Named grids (0xCD12)

Chunk 0xCD28: u32, a flag byte (1 = built-in key) and the name ([Page Grid], IDML $ID/[Page Grid]). IDML writes a NamedGrid per object, in UID order, with a GridDataInformation:

  • A grid made by the user has its own chunk 0xCD02, with the layout of the page chunk (layout grid, below), and IDML writes those settings.
  • The built-in [Page Grid] has only chunk 0xCD28. Its GridDataInformation equals the document's layout grid preference (LayoutGridDataInformation, chunk 0xCD2F, preferences.md) in every attribute that preference has: 803 of 803 pairs of the corpus of 2026-10 (606 trustworthy). It does not always equal the pages' grid: 4 of the 574 trustworthy pairs whose pages all have the same grid differ.

The converter writes each named grid with its own settings, or with the layout grid preference. Over all pairs: 876 of 876 named grids, and every attribute of their GridDataInformation (AppliedFont 875: one family that IDML names in another form, fonts.md); 38 pairs have grids made by the user (2 or 3 named grids).

Applied named grid (chunk 0xCD32). A story (class 0x201) or object style (class 0x1B901) that uses a named grid has chunk 0xCD32: u16 1, then the UID of the named grid object (6 bytes). An object style can also have u16 0 (2 bytes). IDML writes AppliedNamedGrid as the grid's Self (NamedGrid/<name>, NamedGrid/$ID/[Page Grid] for the built-in grid), and n for u16 0 or without the chunk. Evidence over all pairs of the corpus of 2026-10, compared by compare.py:

  • Stories: 26,805 of 26,805 (19,424 of 19,424 in the trustworthy pairs). 106 IDML stories name a grid made by the user (two grids, in 13 pairs of version 12.1), and their INDD stories have the chunk with that grid's UID.
  • Object styles: 3,515 of 3,515 (2,661 of 2,661 trustworthy). 55 name [Page Grid] (u16 1); the others have u16 0 or no chunk and n, among them all root styles [None] but one, which names [Page Grid].

Over the whole little-endian corpus, every story chunk 0xCD32 has 6 bytes, u16 1 and the UID of a named grid object. The converter writes n for u16 0 or no chunk, and the grid's Self for u16 1 with the UID of a named grid of the document; otherwise it leaves the attribute out.

Table of contents styles (0x11605)

Chunk 0x11605: a flag byte (1 = built-in key) and the name, a u16 (0 in every style), a u16 IncludeBookDocuments and a u32 CreateBookmarks (1 = true), the u32 UID of the title's paragraph style, a flag byte and the title, a flag byte and a string not identified, then u16 fields: at 0 SetStoryDirection (0 Horizontal, 1 Vertical), at 2 NumberedParagraphs (0 IncludeFullParagraph, 2 ExcludeNumbers), at 4 MakeAnchor and at 6 RemoveForcedLineBreak (1 = true; the chunk of older files ends before the fields IDML does not have yet), then the entries. IDML writes one TOCStyle per object in Styles.xml.

A story made by a table of contents has chunk 0x8C40, the UID of an object of class 0x8C20 whose chunk 0x11613 is the TOC style; IDML writes that style as the story's AppliedTOCStyle, and n for other stories.

Evidence over the trustworthy pairs: the 511 TOC styles the converter writes match on Name, Title and TitleStyle (511 of 511), NumberedParagraphs (511, one ExcludeNumbers), SetStoryDirection (620 of 620 in the corpus of 2026-10; over all its pairs 823 of 824, 2 Vertical in two pairs of version 18), MakeAnchor (445 of 445 from DOM 9 on, 4 true) and RemoveForcedLineBreak (340 of 340 from DOM 13 on, 4 true); AppliedTOCStyle matches for 18,923 of 18,923 stories (21 made by a table of contents). IncludeBookDocuments and CreateBookmarks match all 1,520 TOC styles of the corpus of 2026-10 whose IDML style has the same name (1,304 trustworthy; 15 with IncludeBookDocuments="true", one with CreateBookmarks="false", in a stale pair). The flagged string after the title is the path of a book file in some of these styles, but it does not decide IncludeBookDocuments.

Entries. After the u16 fields (two before version 9, three before 13, four from 13) the chunk holds a u16 entry count and the entries:

Field IDML
flag byte, in-object string Name: the paragraph style's name, with $ID/ first for flag 1; the group separator U+E00B is written :
flag byte, in-object string a document path; not in IDML
u32 FormatStyle: paragraph style UID
u16 Level
u16 0 in every entry of the pairs; 1 in some entries of files without a pair (not mapped)
u16 PageNumberPosition: 0 AfterEntry, 1 BeforeEntry, 2 None
u32 PageNumberStyle: character style UID
u32 n, segments Separator
u32 SeparatorStyle: character style UID
u16 0 in every entry
u32 n, segments ; , ; or 、; not in IDML
u16 1 in every entry

IDML writes each entry as a TOCStyleEntry child of its TOCStyle: Self is u, the TOC style's UID in hexadecimal, TOCStyleEntry and the entry's index (0 to 5 in the samples, so whether the index is hexadecimal is not shown), then Name, Level, PageNumberPosition, Separator, SortAlphabet="false" (every entry), and Properties with FormatStyle, PageNumberStyle and SeparatorStyle: a user style as type="object" and its Self; the root style as type="string" $ID/[No paragraph style] or $ID/[No character style]; UID 0 as type="string", $ID/kSameStyleWithBracket for FormatStyle and $ID/[Same Style] for the other two. Separator is $ID/ and the text, with tab written ^t, U+0008 ^y, line feed ^n, U+2003 ^m and U+2014 ^_.

Evidence: every TOC style with entries in the trustworthy pairs (versions 8.0 to 21.3) parses to the end of the chunk with this layout, and the converter reproduces all 255 TOCStyleEntry elements with all their values: Name, Level, PageNumberPosition, Separator, SortAlphabet and the three style properties, 255 of 255 each. SortAlphabet is false in all; neither constant u16 can be shown to hold it. A chunk whose entries do not parse to its end keeps its style and loses its entries, with a warning.

Two TOC styles of the corpus pairs have another value at the SetStoryDirection field: 0x40 with no SetStoryDirection in the IDML (version 15.0) and 0xF6FC with Horizontal (a stale pair of version 12.0). The converter writes the attribute for 0 and 1 only.

Languages (0x2D07)

Chunk 0x2D0F: a flag byte and the name (English: USA), a flag byte and the primary name (English), a flag byte and the secondary name (USA, often empty), u16 Id, then two vendors, each a flag byte, a u32 and a string: first the spelling vendor, then the hyphenation vendor (Hunspell, Proximity, Duden, WinSoft); last the locale (en_US).

IDML lists the language objects in UID order as Language elements at the start of designmap.xml: Name, PrimaryLanguageName and SublanguageName are $ID/ and the stored names, except that the language named Neutral is $ID/[No Language] in all three. Evidence over the trustworthy pairs: in 488 of 495 the IDML list equals the INDD objects in that order; in the other 7 the INDD has 4 to 61 language objects and the IDML lists only some of them (1 or 2), for no reason found. For the 1,249 IDML languages the names and Id are equal in 1,249. HyphenationVendor is the second vendor and SpellingVendor the first when their flag is 1 (1,146 and 1,166 of 1,249); otherwise the stored string is empty or names a vendor the IDML does not show, and IDML gives $ID/, $ID/InDihyph or a vendor such as Hunspell that depends on the computer that exported it.

Vendors without a stored name. Over the 3,139 language objects of the corpus of 2026-10 matched with an IDML Language by name, an empty vendor (flag 0, u32 0x01000000, empty string) is written $ID/ for every language whose vendor of that kind is never stored with flag 1 anywhere in the corpus: hyphenation 914 of 914 (847 trustworthy), spelling 894 of 895 (the other, in a stale pair, has Hunspell). For the languages that have a stored vendor in some document, an empty vendor is written as the exporting computer's dictionary (Hunspell 14 and 19, Duden 1 and 1, $ID/ 1 and 1), which no stored value shows; the converter leaves those out. The two lists of languages without a stored vendor:

  • Hyphenation (33): Albanian, Arabic, Byelorussian, Chinese: Hong Kong, Chinese: Simplified, Chinese: Taiwan, Chinese: Traditional, Icelandic, Japanese, Korean, Neutral, Vietnamese, cy_GB, en_US+Medical, eu_ES, fo_FO, fy_NL, ga_IE, gl_ES, gv_GB, ko_KR, la_VA, lb_LU, mk_MK, mn_MN, ms_MY, ne_NE, oc_FR, sr_RS, sr_RS-Cyr, sr_RS-Lat, tk_TM, uz_UZ.
  • Spelling (29): the same without Arabic, Vietnamese, en_US+Medical and ko_KR.

Two other hyphenation vendor flags occur: flag 3 with the text DefaultLinguistic is written $ID/ (24 of 24, Korean and Chinese: Traditional), flag 10 with InDihyph is written $ID/InDihyph (2 of 2). Two spelling vendors with flag 1 and the text InDitect are Hunspell in IDML; the converter writes the stored text for flag 1.

Quotes (chunk 0x2D26). 34 language objects of the corpus have a second chunk 0x2D26: a flag byte, the language name as an in-object string, then four UTF-16 units, the two single quotes and the two double quotes. IDML writes them as SingleQuotes and DoubleQuotes: 34 of 34 (Japanese ‘’ “”, Romanian ‘’ »«, Hebrew ’’ ””, Korean). Without the chunk, the quotes come from observation (idml-values.md, language quotes).

Interface colours (0x1F11)

Layers, pages and XML tags name their colour by the UID of an object of class 0x1F11. Chunk 0x1F01 of that object: u32 5 (RGB), u16 3, three f64 fractions. IDML writes the colour as one of its named colours, or, for other colours, as a list of three numbers (0 to 255):

Red, green, blue IDML Red, green, blue IDML
0.31, 0.6, 1 LightBlue 1, 0.6, 0 Gold
1, 0, 0 Red 1, 0.4, 0 Orange
0.31, 1, 0.31 Green 0, 0.33, 0 DarkGreen
0, 0, 1 Blue 0.6, 0.6, 1 Lavender
1, 1, 0.31 Yellow 0.67, 0.64, 0.71 Charcoal
1, 0.31, 1 Magenta 0.6, 0.2, 1 Violet
0, 1, 1 Cyan 1, 1, 1 White
0.5, 0.5, 0.5 Gray 1, 0.6, 0.8 Pink
0, 0, 0 Black 0.61, 0.87, 0.61 GridGreen
0.6, 0, 0 BrickRed 0, 0, 0.53 DarkBlue
0.6, 0.8, 0 GrassGreen 0.81, 0.51, 0.71 Lipstick
1, 0.71, 0.42 GridOrange 0.97, 0.35, 0.42 Fiesta
0, 0.6, 0.6 Teal 0.73, 0.73, 0.73 LightGray
0.48, 0.73, 0.85 GridBlue 1, 0.6, 0.6 Peach
0.6, 0, 0.2 Burgundy

Evidence: in the layers and pages of the trustworthy pairs every colour object with these components has this name (1,107 layers and pages; from 491 LightBlue down to 1 Teal). The last four are from the guide, grid and pasteboard colours of the preferences (preferences.md), where every colour with these components has this name. Two other colours occur, 1, 0.4863, 0.651 (3 layers) and 0.9412 three times (1 layer); IDML writes them as the lists 255, 124, 166 and 240, 240, 240, the components times 255. The converter writes such a list for a colour whose components are whole multiples of 1/255 and that is not in the table, and leaves the colour out otherwise. XML tags use the table but no list, as before.

Pages (0x50F)

Chunk Contents
0x140F u32 applied master spread, u16 (unknown), matrix MasterPageTransform
0x5CC Matrix: ItemTransform
0x5DD Four f64: left, top, right, bottom. IDML GeometricBounds is top, left, bottom, right.

Files from InDesign 3.0 and 4.0 store the page transform and bounds in chunks 0x151 and 0x154, and chunk 0x140F has no matrix (big-endian.md).

Page settings.

Chunk Contents IDML Without the chunk
0x1404 u32 count; if not 0, a UID list of master page items and a UID list of their overrides OverrideList: each item and its override (n for 0) empty
0xCD04 6 bytes: u32 at 0, then u16 GridStartingPoint (u32: 0 TopOutside, 4 CenterVertical; below), UseMasterGrid (u16, 1 = true)
0x563 u32, u32 code: 1 Recenter, 2 ObjectBased, 3 Scale, 4 GuideBased, 5 UseMaster LayoutRule Off
0x5FF u32: 0 Nothing, 1 UseMasterColor, else an interface colour PageColor UseMasterColor

Evidence over the 9,366 pages (document and master pages) of the trustworthy pairs that the converter writes: OverrideList, UseMasterGrid and PageColor 9,366 of 9,366 each, LayoutRule 9,347 of the 9,347 pages that have it. Of the 9,367 IDML pages, 1,352 have overrides and 2,445 UseMasterGrid="false"; 5,111 have no chunk 0x563 and Off, 4,117 UseMaster, 92 ObjectBased, 24 GuideBased, 3 Recenter and 1 Scale; 9,260 have no chunk 0x5FF, 44 code 1, 5 code 0 and 58 an interface colour. LayoutRule is in IDML from DOM 8 on (no page of the DOM 7 files has it).

Layout grid starting point. The u32 at 0 of chunk 0xCD04 is GridStartingPoint. Over all pairs of the corpus of 2026-10, 13,458 of 13,458 pages that the converter writes match (10,080 of 10,080 in the trustworthy pairs): 13,430 have 0 and TopOutside, 28 have 4 and CenterVertical (master pages in 14 pairs of version 18.4). Every page in the corpus has the chunk. Codes 1, 5 and 6 occur only in files without an IDML (versions 3, 6, 19 and 21), so their values are not shown; the converter leaves the attribute out for them. | 0x51A | Margins: four f64 (left, top, right, bottom), u16 own-margins flag | | 0x528 | Columns: u32 count n, n f64 column edges, f64 gutter, u16 own-columns flag, u16, u16 column direction (1 vertical, 0 horizontal) | | 0xCD02 | Layout grid (GridDataInformation, below) |

Master spread colour. IDML gives each MasterSpread a PageColor property equal to the PageColor of its pages, which is the same for all pages of a master in all 1,359 master spreads of the 654 pairs (UseMasterColor in 1,326, a named colour or Nothing in the others). The converter writes the pages' colour. Over all pairs this reproduces 1,352 of 1,352 compared values.

Margins and columns. IDML writes them as MarginPreference. The column edges are ColumnsPositions (left and right edge of each column, so ColumnCount is n/2), the gutter is ColumnGutter. A flag of 1 means the page has its own values. With 0, or without the chunk, the page shows the values in effect on its master page: the page at the same position, counted from the left by ItemTransform, in the applied master spread, or that spread's only page. That master page can itself take them from its own master. The stored values of such a page are often stale.

Evidence: all 325 IDML pages of the same-version pairs that have an INDD page with the same UID (document and master pages):

  • Margins: 156 pages with flag 1 match their own values; 169 take them from a master page (146 directly, 23 through two or three masters) and match. 325 of 325. Without the rule, 72 pages with flag 0 differ.
  • Columns, gutter and positions: 156 with flag 1, 169 from a master page, 325 of 325. Without the rule, 83 differ.
  • The order of the margins: the four values differ in many pages (for example 56.69, 42.52, 56.69, 56.69 with IDML Top="42.51968503937008").

In the 250 distinct little-endian files, 2,246 pages hold 0x51A in 2,160 (34 bytes each, flag 0 or 1) and 0x528 in 2,211 (always 18 bytes after the positions). The last u16 of 0x528 is the column direction: IDML ColumnDirection is Vertical where it is 1 and Horizontal where it is 0, taking it from the master page with the columns (above). Evidence: 9,274 of 9,274 pages of the trustworthy pairs (14 vertical, in 3 documents), 12,224 of 12,224 over all pairs. A page whose flag is 0 takes the direction from its master page: 44 such pages store 1 but have horizontal columns in IDML, like their master pages.

Layout grid (chunk 0xCD02). u32 font family UID, a flag byte (1 = built-in key, $ID/), the font style as an in-object string, five f64, four u32. IDML writes GridDataInformation:

Field IDML Evidence
Font family AppliedFont (Properties, the family name) 283 of 325 (below)
Font style FontStyle 325 of 325 (Regular, Roman)
f64 1 to 5 PointSize, CharacterAki, LineAki, HorizontalScale (×100), VerticalScale (×100) see below
u32 1 to 4 LineAlignment, GridAlignment, CharacterAlignment; one not identified see below

In the first corpus the numbers were 12, 0, 9, 1, 1 and the codes 3, 0, 3, 1 in all 2,246 pages of the 250 distinct little-endian files, and all 832 GridDataInformation elements of the corpus IDML files had PointSize="12", CharacterAki="0", LineAki="9", scales of 100, LineAlignment="LeftOrTopLineJustify" and AlignEmCenter for both alignments. The numbers 12 and 9 occur once, so those fields were located. The corpus of 2026-10 confirms them: pages with other sizes (such as 9.2126 and 6.9094) are in many pairs typeset in Japanese, and PointSize and LineAki match in 13,458 of 13,458 pages of all pairs. Named grids made by the user (above) locate CharacterAki: 37 of them over all pairs have a second f64 other than 0 (such as −0.354), and their IDML has the same value in 37 of 37. With the flag, FontStyle matches in all 13,458 pages (44 trustworthy pages have flag 1 and IDML $ID/ before the style). The scales and the codes still have one value only: the converter writes the scales only when they are 1, and the three alignments only when the codes are 3, 0, 3,

  1. The other 42 pages are in one pair whose IDML names the family Minion Pro (OTF) where the INDD family name is Minion Pro; its FontFamily element has the same difference (fonts.md).

Applied master of a master page. Pages of master spreads use the same chunk 0x140F. When it is absent or names UID 0, IDML writes AppliedMaster="n" and MasterPageTransform="1 0 0 1 0 0" (220 of 220 master pages in the corpus pairs; 2 of them have the chunk with UID 0 and an identity matrix). In 147 master pages of 73 distinct INDD files without an IDML, chunk 0x140F names another master spread of the same document, never the page's own spread. No pair shows the IDML for this case; the converter writes it as AppliedMaster, as for document pages.

Page items

Frames, shapes and lines are all class 0x6201; groups are 0x401.

Chunk Contents
0x151 Matrix: ItemTransform
0x40D Groups without chunk 0x151: the matrix (ItemTransform)
0x162B Path geometry (below)
0x15B Hierarchy: u32 spread, u32 parent, UID list of children
0x6E03 Attribute list: local formatting (see attributes.md)
0x1B916 u32: applied object style

Content type. A rectangle, oval or polygon with a placed graphic is ContentType="GraphicType". Without one, chunk 0x1623 (u16) decides: 1 is GraphicType (an empty graphic frame), 0 or no chunk Unassigned. In 200 of the trustworthy pairs, the 757 empty shapes with GraphicType all have 1, and the 15,768 with Unassigned have 0 (13,226) or no chunk.

Groups store their matrix in chunk 0x40D when they have no chunk 0x151: with it, the ItemTransform of all 5,670 groups of the trustworthy pairs (8,788 of 8,789 over all pairs) matches; without it, 5,277 of them were written as the identity, though they have a translation in IDML.

Path geometry: u32 path count; per path: u32 point count, points, u16 1 if the path is open. Each point is a u32 type, then f64 values: type 2 = anchor (x, y) only; types 0 and 1 = left direction, anchor, right direction. All 3,191 path chunks in the samples parse exactly, and the points of every page item path match the IDML PathPointType values.

IDML element type. A frame is a TextFrame if a child of class 0x263 exists. Otherwise chunk 0x6204 (u16, then u32) gives a shape code: 1 GraphicLine, 2 or 3 Rectangle, 4 or 5 Oval, 0 and 6 to 8 Polygon; code 9 means none. With code 9 or without the chunk the converter uses the path: two points and open → GraphicLine; four corner points on two distinct x and y values → Rectangle; four points with direction points, all of point type 0 → Oval; anything else → Polygon. Path points of type 1 have direction points too, and a closed four-point path with one or more of them is a Polygon in IDML (1,672 shapes in the trustworthy pairs).

Evidence over the 62,908 rectangles, ovals, polygons and lines of the trustworthy pairs: the code gives the IDML element for 22,579 of 22,587 shapes that have one (7 polygons have code 2 or 3, 1 rectangle code 4); the path for 40,070 of 40,321 without one. Most of the others (215) are polygons whose four points of type 0 form an ellipse, as ovals do.

Text frames: the frame's child of class 0x263 (multi-column frame) has a child of class 0x227 (frame column). Chunk 0x220 of the column holds the frame list (class 0x228). Its chunk 0x205: u32 story, then a UID list of the columns of all threaded frames in order, which gives PreviousTextFrame and NextTextFrame.

Page item labels. A page item's Properties/Label has the layout and rule of the document label: u16 0x7B7B, u32 count, then flagged key and value strings, written in stored order as stored. It is stored in:

Item Chunk Offset
Frames and shapes (class 0x6201) 0x6204, after the shape code 6
Groups (0x401) 0x2C0B 0
Buttons (0x1450C) and multi-state objects (0x145D8) 0x14582 0

Without these bytes the item has no Label. In Properties the Label comes first. Evidence: all 278 labelled items of these kinds in the IDMLs of all pairs (258 in 27 trustworthy pairs: 108 rectangles, 44 text frames, 40 lines, 36 groups, 18 buttons, 9 multi-state objects, 3 polygons) have the bytes and match key for key; no item has the bytes without a Label in IDML. Flag 1 appears on labelled frames whose IDML keys and values have no $ID/ prefix.

Page item settings

Every page item element in IDML (TextFrame, Rectangle, Oval, Polygon, GraphicLine, Group) has the attributes below. Each is stored in a chunk of the item (class 0x6201 or 0x401), or in its attribute list (chunk 0x6E03, attributes.md); without the chunk the IDML value is the default in the table.

Chunk Contents IDML Without the chunk
0x2C10 (groups: 0x418) u8 1 if a built-in key, then an in-object string Name: the string, or $ID/ and the key $ID/
0x2C32 u16, 0 = hidden Visible true
0x2C2D u32, 1 = locked Locked false
0x142D u32, 1 = overrides not allowed AllowOverrides on items of master spreads (the spread in chunk 0x15B is a master spread): false for 1, else true; no item of a document spread and no placed graphic has it (11,791 of 11,791 trustworthy items) true on master spreads
0x21D4E u32 count n, n pairs of u32 ParentInterfaceChangeCount: the numbers empty
0x21D50 same TargetInterfaceChangeCount empty
0x21D53 same LastUpdatedInterfaceChangeCount empty
0x1424 u32 master page item, UID list OverriddenPageItemProps: the list in decimal; empty if the master item is 0 empty
0x22228 u8 flags HorizontalLayoutConstraints (bits 4–6), VerticalLayoutConstraints (bits 0–2): per bit FixedDimension if set, else FlexibleDimension as 0x22
0x324 u32 at 0, a layer or spread layer UID BeforeGroupingLayerReference, from 21.4 (below) none
0x324 i32 at 4 BeforeGroupingLayerPosition, after ItemTransform, from 21.4 (also on placed graphics) -1
Attribute IDML Without the attribute
0x5520, 0x551F, 0x551E GradientFillStart, GradientFillLength, GradientFillAngle 0 0, 0, 0
0x5526, 0x5525, 0x5524 GradientStrokeStart, GradientStrokeLength, GradientStrokeAngle same
0x5522, 0x5523 GradientFillHiliteLength, GradientFillHiliteAngle 0
0x5528, 0x5529 GradientStrokeHiliteLength, GradientStrokeHiliteAngle 0

Rules the IDML follows, over the 92,409 page item elements of the 495 trustworthy pairs:

  • Locked is on the 36,817 items that are children of a spread or anchored in text, and on none of the 55,592 items inside a group or another page item.
  • ItemLayer is on the 35,276 items that are children of a Spread or MasterSpread (35,276 of 35,276), and on none of the items inside a group (48,289 of 48,291), inside a rectangle, oval or polygon (2,925 of 2,925) or anchored in text (1,999 of 1,999). The layer of a nested item always equals its parent's. Counted over the 489 trustworthy pairs of the corpus without the privately held samples.
  • The change counts, OverriddenPageItemProps and the layout constraints are in IDML from DOM 8 on: every page item of the distinct corpus IDML files from DOM 8 on has them, none of the DOM 7 files does (145 text frames, 335 rectangles, 61 groups).
  • A group has no gradient attributes of its own (no group in the pairs has 0x551E to 0x5529). IDML gives it, for each gradient attribute, the value all its child items have, and leaves the attribute out when they differ: 58,068 of the 58,080 gradient values of the 5,808 groups.

Evidence: the INDD values, decoded as above, against the IDML of the same item, over the page items of the trustworthy pairs that have an INDD object:

IDML attribute Equal
Name 92,264 of 92,402
Visible 92,402 of 92,402
Locked 36,810 of 36,810
The three change counts and OverriddenPageItemProps 91,812 of 91,812 each
Both layout constraints 91,812 of 91,812 each
Gradient start and length, fill and stroke (four attributes), items other than groups 86,594 of 86,594 each
Gradient angles and highlights (six attributes) all, 92,396 to 92,402 per attribute (groups by the rule above)

The 138 names that differ belong to groups that are the states of form fields; IDML names them by their state type (form fields).

Values other than the default: 206 items with a name given by the user, 176 hidden, 1,241 with change counts, 1,113 with overridden properties. Flags 0x22 are in 66,820 items, 0x55 (FixedDimension FlexibleDimension FixedDimension both ways) in 643 and 0x02 (FlexibleDimension three times horizontally) in 13; with another bit set the converter leaves both attributes out. In 14,918 items with chunk 0x1424 the master item is 0; in 197 of them the list still holds IDs, and IDML writes the attribute empty.

Layer position before grouping. From 21.4 every page item and placed graphic in IDML has BeforeGroupingLayerPosition; no IDML before 21.4 has it (13 distinct corpus IDML files from 21.4, none of the 1,673 earlier ones). Its value is the i32 at 4 of chunk 0x324, or −1 without the chunk. The converter writes it for files saved by 21.4 or later: 1,793 of 1,793 values over the trustworthy pairs (1,308 polygons, 241 text frames, 131 rectangles, 53 groups, 38 images, 16 EPS, 3 graphic lines and 3 SVG).

Chunk 0x324 of page items and placed graphics:

Offset Contents IDML
0 u32 UID: 0, a layer (class 0x302) or a spread layer (class 0x301) BeforeGroupingLayerReference
4 i32 BeforeGroupingLayerPosition
8 u8 0, 1 or 2, then bytes not decoded (in some items an in-object string with a layer name)

BeforeGroupingLayerReference is the layer the UID gives: the UID itself for a layer, the u32 at 0 of the spread layer's chunk 0x302 for a spread layer. 0, no chunk or another class give no attribute. Over the 1,831 page items and placed graphics of the 12 DOM 21.4–21.5 pairs:

Chunk 0x324 IDML Items
u32 at 0 is 0 no BeforeGroupingLayerReference 1,667 of 1,667
a spread layer that spread layer's layer 36 of 36
a layer that layer 14 of 15
no chunk no reference, position −1 113 of 113

The exception is one rectangle on a master spread whose chunk names a layer and position 1; its IDML has position −1 and no reference. No field that sets it apart was found. The converter's output has 50 of the 50 references of the pairs (19 polygons, 15 rectangles, 10 text frames, 6 groups) and no other.

Stroke weight without an attribute. An item whose attribute list has no stroke weight (attribute 0x6E65) takes it from the document's base list (class 0x6E02, attributes.md, values an item does not store): 1 in most documents, 0.2835 in others. IDML writes it when it differs from the object style's, so items with [None] (stroke weight 0) have it. Groups vary (1,166 without the attribute, 625 with 1 and 30 with other values, in 200 of the pairs) and get none.

Overprint. The attribute list of a page item holds the overprint flags of the fill (0x6E6A) and the stroke (0x6E67), u16 1 true, as in object styles (object style settings). IDML writes OverprintFill on a rectangle, oval, polygon, graphic line, text frame or EPS text when its fill puts ink on the page, by the object style rule: the fill colour (the item's 0x6E68, else its object style's) is not None, Paper or a white process colour, and the tint is not 0. The value is the item's flag; an item without the flag has false, which IDML writes only when the object style turns the fill category off (as for the fill colour, attributes.md, values an item does not store). OverprintStroke follows the same rule with the stroke colour (0x6E64), tint (0x6E66) and category. Trustworthy pairs: the rule reproduces all 3,315 Polygon, 64 Rectangle, 33 TextFrame, 33 EPSText and 3 Oval OverprintFill values and all 68, 30, 20, 2 and 1 OverprintStroke values of polygons, graphic lines, rectangles, ovals and text frames, with no extra value. Of the items that store 0x6E6A, 27 have a Paper fill and no OverprintFill.

A group stores no flag. IDML gives it the flag that its children share, counting only children whose fill (for OverprintFill) or stroke (for OverprintStroke) puts ink on the page by the rule above: the child's own flag, false without one; for a child group, its shared flag. A group whose children with ink differ, or that has none, gets no attribute, and neither does a group whose shared flag equals its object style's value (false where the style has none). In documents saved by 21.4 or later, where every object style has the overprint attributes (object style settings, overprint), children without ink count too, with their own flag, else their style's value. Over all 1,462 pairs this gives 320 of 320 OverprintFill values of groups (313 in 82 trustworthy pairs) and 2 of 2 OverprintStroke values, all true, with no extra value; 4 more are written in a stale pair on groups that its IDML does not have. 75 of the 320 groups have a child that has no attribute in IDML. The 21.4 case rests on one group of one trustworthy pair, whose child without ink has the style value false and whose IDML has no attribute; before 21.4 a child whose stroke is Paper under a style with OverprintStroke="false" does not count (one group).

Object export options

Page items (class 0x6201 and groups, 0x401) may have chunk 0x1E206, the alternative text and tagging settings that IDML writes in ObjectExportOption:

Size Contents IDML ObjectExportOption
4 u32 alternative text source: 0 SourceCustom, 5 SourceXMLStructure, 8 SourceDecorativeImage AltTextSourceType
flagged string custom alternative text CustomAltText
flagged string Properties/AltMetadataProperty NamespacePrefix
flagged string Properties/AltMetadataProperty PropertyPath
4 u32 actual text source: 0 SourceCustom, 5 SourceXMLStructure, 6 SourceXMPAltText ActualTextSourceType
flagged string custom actual text CustomActualText
flagged string ×2 Properties/ActualMetadataProperty (as above)
4 u32 tagging: 0 TagFromStructure, 1 TagArtifact ApplyTagType
rest 64 bytes (DOM 8–9), 83 (10–20), 88 (21) not decoded

A flagged string is a u8 (1: a built-in key, written $ID/ and the string; 2: a plain string) and an in-object string. An empty key is $ID/.

Evidence: 69,814 page items with the chunk in the trustworthy pairs; all eight values match in 69,814 of 69,814 (other than the default: 30 custom and 199 decorative alternative text sources, 197 custom and 14 XMP actual text sources, 205 artifacts, 31 custom alternative texts, 197 custom actual texts). The 22,005 items without the chunk all have the values SourceXMLStructure, $ID/ and TagFromStructure. The chunk parses in all 363,145 page items of the distinct little-endian corpus files. The converter leaves out an attribute whose code is not in the table. Which other attributes ObjectExportOption has depends on the version (idml-values.md, export options of page items).

Object styles (class 0x1B901) may have chunk 0x1E206 with the same layout, and IDML writes its first eight values in the style's ObjectExportOption the same way. In the 1,503 pairs outside the privately held samples, 3,643 object styles have the chunk: 20 store tagging 1 and have ApplyTagType="TagArtifact" (20 of 20, in 2 DOM 20 pairs); all others store the default values and have them in IDML. One privately held sample adds 1 object style with source 0 and a custom alternative text: AltTextSourceType="SourceCustom" and the text in CustomAltText (1 of 1). Styles without the chunk have the defaults.

Export size (chunk 0x1E22B). A list of keys and values: u32 count; per entry a u32 length and the key in text segments, a flag byte, two bytes, a u16 value count and the values, each a u8 length, a u8 and that many bytes of text. The keys are UseOrigImage, CustomSizeType, CustomSizeValue and CustomContentConversion. CustomSizeType is IDML SizeType: 1 DefaultSize, 2 FixedSize, 3 RelativeToTextFlow, 4 RelativeToTextSize; an item without the chunk has DefaultSize.

Generated alternative text. From 21.4 page items have three more chunks:

Chunk Contents IDML ObjectExportOption
0x1E260 u16: 1 true, 0 false AltTextGenerationError
0x1E261 four f64 AltTextCropSyncRect: empty when all four are 0, else the four numbers (below)
0x1E262 u16: 1 true, 0 false AIGeneratedAltText

Without the chunk the values are false, false and empty; the converter also writes these for another u16 or a chunk too short for its values. Evidence, the 1,701 page items other than groups of the 12 DOM 21.4–21.5 pairs: AltTextGenerationError 1,701 of 1,701 (22 true), AIGeneratedAltText 1,701 of 1,701 (3 true), AltTextCropSyncRect 1,701 of 1,701 (8 not empty, two distinct rectangles). Items with a true flag have AltTextSourceType="SourceCustom" and the generated or error text in CustomAltText (chunk 0x1E206); the tail of chunk 0x1E206 is the same in all of them and does not hold the flags. Object styles have AltTextCropSyncRect="" (49 of 49).

AltTextCropSyncRect writes each f64 with exactly 8 decimals, cut, not rounded, from the shortest decimal form, joined by commas: 415.60850393700787 gives 415.60850393 (rounding would give …394), 306.7741732283466 gives 306.77417322, 370.32 gives 370.32000000.

Groups have no AIGeneratedAltText and AltTextGenerationError in their ObjectExportOption: none of the 53 groups of the 7 trustworthy documents from 21.4 has them. The converter leaves them out on groups, which removes 106 extra values.

Text wrap

Page items (class 0x6201 and groups, 0x401) and placed graphics have chunk 0x3703 (44 bytes):

Offset Contents
0 u32 wrap mode: 0 None, 1 JumpObjectTextWrap, 3 BoundingBoxTextWrap, 6 Contour
4 u32 UID of the wrap path object (class 0x3702), or 0
8 Four f64 offsets: left, top, right, bottom (IDML TextWrapOffset)
40 u16 master page flag: 1 ApplyToMasterPageOnly="false", 0 true
42 u16 TextWrapSide: 0 BothSides, 1 LeftSide, 2 RightSide, 3 SideTowardsSpine, 4 SideAwayFromSpine, 5 LargestArea

Wrap path. Every item with wrap mode 1, 2, 3 or 6 (and the codes 0x10003 and 0x10006) has a wrap path object; mode 0 items have none (9,061 objects in 735 files of the corpus of 2026-10). The u32 at 4 equals the object's UID in 8,824 of the 8,824 objects whose owner was found. Its chunks:

Chunk Contents
0x162B Path geometry, the layout of page items. Parses in 8,846 of the 8,846 little-endian objects that have it; 18 have none
0x3709 10 bytes: u32 UID of the item (9,061 of 9,061), u32 0 (9,061 of 9,061), u16 custom path flag
0x2C0B, 0x2C2D, 0x377A On 4,813 of 9,061; not read

IDML writes the path as TextWrapPreference/Properties/PathGeometry, before TextWrapOffset, only when the custom path flag is 1. Over the 2,342 IDML wrap elements that have a wrap path object (1,412 in trustworthy pairs):

u16 at 8 of 0x3709 IDML PathGeometry All pairs Trustworthy
1 present 35 of 35 32 of 32
0 absent 2,307 of 2,307 1,380 of 1,380

The 35 are 28 polygons (22 BoundingBoxTextWrap, 6 Contour), one rectangle, one group, one text frame (JumpObjectTextWrap) and 4 images (Contour). In all 35 the IDML paths equal the 0x162B paths: number of paths (1 to 3), point count, Anchor, LeftDirection and RightDirection from the point's anchor, left and right, and PathOpen from the u16 after the points (0 false). The numbers are the same (tolerance 1e-6), so no transform applies: the path is in the item's inner coordinates, those of its own PathGeometry or, for a placed graphic, of its GraphicBounds (before the graphic's ItemTransform). It already includes the wrap offsets: the path of an image with a 8.5 pt top offset and a scale of 0.40885 extends 20.79 (8.5 / 0.40885) beyond the graphic bounds on each side.

With flag 0 the object still stores a path: for frames and groups the item's path bounding box grown by the offsets (1,538 of 1,538 cases compared; in about 500 more the box is also grown by 0.25 to 1.5 pt on each side), for contour wraps of images the computed contour. IDML omits these, and the converter writes the path only for flag 1.

Placed graphics also have chunk 0x373D, the contour (IDML ContourOption). See "Contour" below.

Evidence from the pairs. For every element with a Self in the corpus pairs, the IDML TextWrapPreference was compared with chunk 0x3703 of the INDD object with that UID. Same-version pairs first, then the pairs whose IDML is from an older version:

INDD IDML Same version Older IDML
Mode 0 TextWrapMode="None" 2,625 of 2,625 615 of 615
No chunk 0x3703 TextWrapMode="None" 1,468 of 1,468 873 of 873
Mode 1 TextWrapMode="JumpObjectTextWrap" 2 of 2 (one file) 1, matched by geometry (below)
Mode 3 TextWrapMode="BoundingBoxTextWrap" 1 of 1 (an image) none
Mode 6 TextWrapMode="Contour" 3 of 3 (one file) 1 of 1 (an image)
Offsets as left, top, right, bottom TextWrapOffset 2,631 of 2,631 616 of 616
u32 at 40 = 1 (little-endian) Inverse="false", ApplyToMasterPageOnly="false", TextWrapSide="BothSides" 2,630 of 2,630 616 of 616
0x373D type 5 ContourType="SameAsClipping" 224 of 225 (1 has no ContourOption) 75 of 75

Contour. Chunk 0x373D of placed graphics (29 bytes) holds the contour that IDML writes as ContourOption. The preferences chunk 0x373F (preferences.md) and the object style chunk 0x3777 (object style settings, below) have the same layout.

Offset Contents
0 u32 contour type: 0 BoundingBox, 1 DetectEdges, 2 AlphaChannel, 3 PhotoshopPath, 4 GraphicFrame, 5 SameAsClipping, 6 SelectSubject
4 f64: 5 in every placed graphic and the preferences, 5 or 8 in object styles
12 u8: 25 everywhere
13 00 00 FF FF everywhere
17 u8 IncludeInsideEdges: 0 false, 1 true
18 11 zero bytes

Evidence, over the placed graphics of the 1,251 trustworthy pairs (corpus of 2026-10) whose IDML has a ContourOption:

INDD IDML Graphics
Type 5 ContourType="SameAsClipping" 2,693 of 2,698 (5 have no ContourType, below)
Type 2 AlphaChannel 13 of 13
Type 1 DetectEdges 8 of 8
Type 0 BoundingBox 4 of 4
Type 6 SelectSubject 1 of 1
Byte 17 = 1 IncludeInsideEdges="true" 1 of 1 (type 2)
Byte 17 = 0 IncludeInsideEdges="false" every other graphic with ContourType

Types 3 and 4 occur in no pair: no IDML in the corpus has either code. The IDML schema's ContourOptionsTypes list leaves PhotoshopPath and GraphicFrame as the two names without a code, and the INDD shows which is which:

  • The graphic's chunk 0x1635 holds path data in the layout of chunk 0x162B (an outline of the picture content). All 5 type 3 graphics of v7.0 and later files have it (3 images, 2 EPS, 5 files); none of the 12 type 4 graphics (3 files) does. Types 1, 2 and 6 have it too (118 of 118 sampled), types 0 and 5 do not (56 of 56 sampled).
  • The wrap outline (chunk 0x162B of the 0x3702 object) of a type 4 graphic is the frame outline grown by the Top offset on every side. Two graphics have a frame that differs from the image bounds (one crops the image, one is wider than the placed bounds); both outlines follow the frame, not the image. The wrap outline of a type 3 graphic is its 0x1635 path, simplified and grown by the Top offset (3 of 3 with an outline; one is 2.1 units short at the bottom), not the image box.

So type 3 is drawn from a path of the picture (PhotoshopPath) and type 4 from the frame (GraphicFrame). The converter leaves the ContourOption of other codes out.

Contour parameters. From DOM 21.4 every ContourOption has ContourTolerance="5", ContourThreshold="25", ContourAlphaIndex="0" and ContourPathIndex="-1", after ContourPathName: 211 of 211 elements in the 12 corpus IDML files of DOM 21.4 and 21.5 (graphics, frames, object styles and preferences), all with these values. No ContourOption of an earlier DOM has them (32,227 elements in the 1,444 IDML files of DOM 7 to 21.3). Every ContourOption of DOM 21.4 and later also has ContourType. The contour chunks (graphic 0x373D, object style 0x3777, preferences 0x373F) may hold them as the f64 at 4, the u8 at 12 and the i16 at 13 and 15, in the layout of the clipping chunk 0x2C1A (f64 tolerance, u8 threshold, i16 index): the 102 contour chunks of the DOM 21.4–21.5 pairs hold 5, 25, 0 and −1 there. Over all 1,462 pairs, the only other value is f64 8 in 72 object style chunks (24 files of DOM 10.0, 10.2 and 17.0), whose IDML has no ContourTolerance, so the assignment is not shown. The converter writes the four values on every ContourOption with a ContourType from DOM 21.4. A ContourOption with only ContourPathName has no sample from DOM 21.4; the converter writes it without them.

ContourPathName is not in the chunk. Every ContourOption of the corpus IDMLs has it (25,551 of 25,551 in 1,693 IDML). It is $ID/ in 25,525; the other 26 name an alpha channel of an image: 13 images with ContourType="AlphaChannel" and their 13 frames, in five documents. The name comes from image chunk 0x177C:

Offset Contents
0 u32 channel count n (0 in most images, which then have 4 bytes)
4 per channel: a flag byte (3 or 0; meaning unknown), an in-object string (the channel name), then bytes not decoded

For example 01 00 00 00 | 03 | 02 03 03 00 | 03 80 and 3 UTF-16 units. Over the images of the pairs that have a ContourOption:

Image ContourPathName Images
Type 2, n ≥ 1 the first channel name 13 of 13
Type 2, n = 0 or no chunk $ID/ 10 of 10
Any other type $ID/ all (8,629), including 1,075 images with 1 to 7 channels

No chunk of the type 3 graphics holds a path name (strings searched in all chunks), so the converter writes $ID/ for type 3 as for the other types.

Which channel a type 2 contour names when n > 1 is not shown (no sample); the converter takes the first. Image chunk 0x1714 is not the source: its alpha channel name is $ID/ in all 22 type 2 images.

A graphic without chunk 0x373D has the contour of the preferences chunk 0x373F, and without that chunk, type 5 and IncludeInsideEdges="false". Of the 9,535 graphics (images, EPS, PDF, SVG and imported pages) whose ContourOption the converter writes and the trustworthy IDMLs have, ContourType and IncludeInsideEdges are equal in all; this includes the 319 images without the chunk that have DetectEdges because their document's chunk 0x373F has type 1.

A frame with one placed graphic (Rectangle, Oval, Polygon) has the contour of its graphic, unless its object style turns the text wrap category on (all of 0x1B942, 0x37C8 and 0x37C9 in chunk 0x1B92E, IDML EnableTextWrapAndOthers="true"). Then its ContourOption has only ContourPathName: 517 of 518 such frames in the trustworthy pairs. In all corpus pairs, the value is $ID/ in all 568 ContourOption elements with only that attribute (554 frames and the 14 graphics below); the converter writes the name of the graphic's contour, which is $ID/ unless the graphic has type 2 and a channel (no sample of that in such a frame). The 8,965 other frames with ContourType take their graphic's type and IncludeInsideEdges in all cases, and the frames of the 13 named images their ContourPathName. Frames without a graphic have no ContourOption (all but one).

The IDML has no ContourType and IncludeInsideEdges on 14 graphics: 5 with type 5 in chunk 0x373D and 9 without the chunk. 12 of them are in frames whose object style turns the text wrap category on, but 495 graphics in such frames have both attributes. No INDD field is known that separates them, and the converter writes the type for all 14.

Master page flag and side. The 4 bytes at 40 are two u16 in the file's byte order. The big-endian pair shows it: its 261 page items store 00 01 00 00 (251, IDML ApplyToMasterPageOnly="false") or 00 00 00 00 (10, true), all with TextWrapSide="BothSides". In little-endian files the u32 1 is therefore the u16 1 at 40 and the u16 0 at 42. With this layout the converter reproduces, over the 1,251 trustworthy pairs of the corpus after 2026-10, all 256,651 ApplyToMasterPageOnly and TextWrapSide values of page items, form fields and placed graphics, where the u32 reading had left 6,322 of each out (items storing 0 at 40 or a side code). Side codes 1 to 5 occur on few items (14, 4, 9, 1 and 32 in the trustworthy pairs). Items without the chunk have false and BothSides.

Inverse is false on every item of the corpus IDML files (256,651 of 256,651 in the trustworthy pairs); no INDD field is known for it, and the converter writes false.

Order of the offsets. Most offsets in the pairs are 0, so the order rests on a few elements:

  • Offset 24 (third) is Right: the bounding-box image has 2.83 there and 0 elsewhere; its IDML has Right="2.834645669291339" and 0 for the other sides.
  • Offset 32 (fourth) is Bottom: both jump-object frames have 14.17 there and 0 elsewhere; their IDML has Bottom="14.173228346456694" and 0 for the other sides.
  • Offset 16 (second) is Top. In a pair whose IDML is from an older version (IDML 17.0, INDD 18.1), the INDD has one jump-object frame with 11.34 at offset 16 and 5.67 at offset 32. Its UID differs from the IDML element's, but its path and ItemTransform are identical to those of the IDML's only jump-object frame, which has Top="11.338582677165356" and Bottom="5.669291338582678". A sample and its print PDF agree; see below.
  • Offset 8 (first) is therefore Left. It is 0 in every sample that has a reference.
  • The two contour frames have the same value at all four offsets, as in their IDML.

Evidence from a sample and its print PDF. The sample has frames with mode 1. Offset 8 is 0 in all of them; offset 16 is 0, negative or positive. With jump-object wrap, no text is set beside a frame, and text above the frame must end above the top of the wrap area. Text line positions in the PDF were taken from pdftotext word boxes and compared with the frame bounds:

  • Where offset 16 is 0, the body line above a frame ends at most 1.5 pt below the frame's top edge.
  • Where offset 16 is negative, the body line above may end inside the frame, never further below its top edge than the offset's size plus 1.5 pt. Where the next line position would end further down than that, it is left empty.
  • A line that lies wholly between a frame's top and bottom edges falls inside the band that a large negative offset opens.

So the value at offset 16 moves the top edge of the wrap area, and a negative value lets text into the frame from above.

Other values. One image in the same-version pairs has 0x40001 at offset 40 and TextWrapSide="SideAwayFromSpine"; no other value is shown, so the converter writes the side and inverse settings only when the u32 at 40 is 1. Modes other than 0, 1, 3 and 6 have no IDML evidence; the converter leaves out TextWrapPreference for them.

Frame fitting

The frame fitting settings are attributes in the page item attribute list (chunk 0x6E03, attributes.md). Object styles hold all of them in chunk 0x1B956 (a u16 count, then records of the same layout).

ID IDML FrameFittingOption attribute Encoding
0x6E83 AutoFit u32: 0 false, 1 true
0x6E7E LeftCrop f64
0x6E7F TopCrop f64
0x6E80 RightCrop f64
0x6E81 BottomCrop f64
0x6E7C FittingOnEmptyFrame u32: 0 None, 1 ContentToFrame, 2 Proportionally, 3 FillProportionally
0x6E7D FittingAlignment u32: 0 TopLeftAnchor, 1 TopCenterAnchor, 3 LeftCenterAnchor, 4 CenterAnchor

Evidence, from the same-version pairs:

  • Object styles. All 337 object styles paired by name hold all seven IDs in chunk 0x1B956, and all seven match the style's IDML FrameFittingOption in 337 of 337 (FittingAlignment 4 in 313 styles, 0 in 24).
  • Crops. Each crop ID is told apart by non-zero values: wherever IDML writes the attribute, the frame's own value, or its style's if the frame has none, matches: left 429, top 397, right 433, bottom 451, no mismatch. Non-zero values: left 235, top 204, right 239, bottom 258.
  • Fitting on an empty frame. 301 of 301; codes 0, 1, 2 and 3 occur (1,154, 9, 77 and 16 values).
  • Alignment. 200 of 205. The other 5 are frames in one file with the style [None], no local value and a style value of 0, where IDML says CenterAnchor; not explained. Code 0 is shown in 9 frames, code 4 in object styles. Other codes are left out.
  • AutoFit. 0 and false wherever IDML writes it (200 of 200); other values are left out.

Codes 1 and 3 of FittingAlignment and code 1 of AutoFit come from the corpus after 2026-10, over all pairs (item and object style lists against their IDML): AutoFit 1 true in 927 items and styles, 0 false in 2,548; FittingAlignment 1 TopCenterAnchor in 21 object styles of one 14.0 document, 3 LeftCenterAnchor in 1 item. Codes 2 and 5 to 8 do not occur; the converter leaves them out.

Where IDML writes it. Only on rectangles, ovals and polygons, never on text frames (1,154) or lines (136), even when their list has these attributes. The rule depends on the applied object style's category list (chunk 0x1B92E, object style settings):

  1. Fitting category off. When the list lacks 0x1B960 (EnableFrameFittingOptions), IDML writes all seven attributes: the item's value where its list has the ID, the style's otherwise. This holds for the root [None] too, although its IDML element has no Enable… attributes. In the trustworthy pairs of the corpus after 2026-10, the root style's list lacks 0x1B960 in 22 documents, and all 9,560 items there that use the root style have all seven attributes; in the other 883 documents with such items, no item that uses the root style has all seven.
  2. Otherwise, let D be the item's local attributes whose value differs from its object style's. IDML writes D; with D empty it writes no element. An object style without a category list (older files) gives all seven of its values when D is empty, unless it is the root [None].

Over the trustworthy pairs, the converter reproduces 33,274 of 33,702 Rectangle/FrameFittingOption elements, 13,131 of 13,648 for polygons and 6,929 of 7,207 for ovals, with every attribute of the written elements except 131 FittingAlignment values and 7 values of each of three crops. Of the elements not reproduced, 585 belong to items the converter does not write with that tag, and 632 are on items that use the root [None] (style value 0) and do not store 0x6E7D, where IDML writes only FittingAlignment="CenterAnchor" (609 of them in one 20.3 document); 6 rectangles remain. The 131 differing values are of the same kind, on items of other styles. No stored value tells these items apart from the items where IDML writes the style's value; the converter writes the style's value.

Clipping path settings

Images, PDF and EPS graphics may have chunk 0x2C1A (37 bytes):

Offset Contents IDML ClippingPathSettings
0 u32: 0 None, 1 DetectEdges, 2 AlphaChannel, 3 PhotoshopPath ClippingType
4 f64 Tolerance
12 f64 InsetFrame
20 u8 Threshold
23 i16 Index (not for type 2, below)
25 u8 flags: 0x02 UseHighResolutionImage; 0x01 and 0x08 InvertPath and RestrictToFrame
26 11 bytes, 0 in every sample

Evidence: 75 of 235 images in the same-version pairs have the chunk, and all 75 match on the tolerance, inset, threshold and index (tolerance 2 or 0, threshold 25 or 0). PDF (153 of 206) and EPS (6 of 18) graphics have the chunk with the same values as images that use the defaults. Graphics without the chunk (160 images, 53 PDF, 12 EPS) have UseHighResolutionImage="true", Threshold="25", Tolerance="2", InsetFrame="0" and Index="-1" in IDML, and the converter writes those values for them.

Over the trustworthy pairs of the corpus after 2026-10, every graphic with the chunk was compared with its IDML element (2,686 graphics):

INDD IDML Graphics
Type 0 ClippingType="None" 2,655 of 2,655
Type 1 DetectEdges 2 of 2 (2 pairs)
Type 2 AlphaChannel 1 of 1
Type 3 PhotoshopPath 28 of 28 (12 pairs)
Flags 0x02 UseHighResolutionImage="true", InvertPath="false", RestrictToFrame="false" 2,680 of 2,680
Flags 0x00 UseHighResolutionImage="false", InvertPath="false", RestrictToFrame="false" 5 of 5
Flags 0x09 UseHighResolutionImage="false", InvertPath="true", RestrictToFrame="true" 1 of 1 (type 1, threshold 111, tolerance 3.9)
i16 at 23, types 0, 1 and 3 Index (-1, or 0 in 9 type 3 images) all

Bits 0x01 and 0x08 are set together in the one sample, so which is InvertPath and which RestrictToFrame is not shown. The converter writes both when the two bits are equal and leaves both out otherwise. Other type codes have no sample; the converter leaves out the element for them.

The one type 2 image stores -1 at 23, and its IDML has Index="0". No other field of the chunk differs from the type 1 and 3 images, so the index of the alpha channel is not in this chunk; the converter leaves Index out for type 2.

IncludeInsideEdges="false" has no identified field: all 11,823 ClippingPathSettings elements in the IDML files of the 1,462 corpus pairs have it, and the converter writes it.

Path name. AppliedPathName names the image's path or channel:

Type AppliedPathName Graphics
0 $ID/ all 12,280 None elements of the corpus IDML files
1 $ID/ 2 of 2
2 the first channel name of image chunk 0x177C (text wrap, contour) 1 of 1
3 the name in key 0x7D of image chunk 0x1708 17 of 17 with an ASCII name

Key 0x7D of the image properties (13 bytes in all samples) holds a u8 length n, n bytes of name, then 6 bytes (00 00 33 33 00 01 or 00 00 00 00 00 01). The name bytes are not Unicode. The other 11 type 3 images name their path in a legacy code page: in 5 (Korean documents) key 0x7D holds bytes that decode in code page 949 to the IDML name; the other 6 (Japanese documents) have no key 0x7D, and key 0x80 of the same chunk holds the name as bytes that decode in Shift-JIS. None of these INDD files has the name as UTF-16 or UTF-8 text, except two where it is part of a longer text in another record. The file does not record the code page, so the converter writes the name only when every byte is printable ASCII (0x20 to 0x7E) and leaves AppliedPathName out otherwise.

Geometry. IDML writes Properties/ClippingPathGeometry for every graphic of type 1, 2 or 3 (31 of 31 images, 13 pairs), and for no graphic of type 0. The paths are those of the graphic's own chunk 0x162B, in the layout of page item paths: the converter's output equals the IDML element exactly, number for number, in all 31 (1 to 8 paths of 4 to 179 points). The 2,655 graphics of type 0 with chunk 0x162B (1,797 images, 329 PDF, 528 EPS, 1 WMF graphic) have no ClippingPathGeometry. IDML puts it before GraphicBounds.

Placed pages. IDML has ClippingPathSettings on every ImportedPage (42 in 8 pairs, 38 in 7 trustworthy pairs). No placed page has chunk 0x2C1A, and all 42 have the values of graphics without the chunk; the converter writes those values for them.

ImageIOPreference. Chunk 0x1714 of an image:

Offset Size IDML ImageIOPreference
0 u32 72 in all 1,300 images with the chunk
4 u16 ApplyPhotoshopClippingPath: 1 true, 0 false
6 u16 1 in all (AllowAutoEmbedding="true" in all IDML)
8 flagged string AlphaChannelName (an empty key is $ID/)

Without the chunk, IDML has ApplyPhotoshopClippingPath="true" and AlphaChannelName="$ID/". Evidence: 3,607 of 3,607 images of the trustworthy pairs for both attributes (14 false, 92 $ID/kNoneName, 2 plain names). Chunk 0x8C39 (u16 at 0), which looked like the clipping flag in fewer samples, gives the wrong value in 6 images and is missing in 549. AllowAutoEmbedding="true" is written from observation.

Placed graphics

Images (0x1702), PDF (0x2501), EPS (0x6601) and SVG (0x6639) are children of a frame (in its 0x15B list) and share these chunks:

Chunk Contents
0x151 Matrix: ItemTransform (437/437 match)
0x1633 Four f64: GraphicBounds left, top, right, bottom
0x8CBC link list (story links and placed text, link lists): the link is the first UID, at offset 8

Links (0x8C42). Links of linked stories and linked page items have another class with the same chunks (story links and placed text). LinkClassID is the class of the link object in decimal: 2,386 of 2,386 IDML links in the 158 little-endian documents whose UID is a link object in the INDD (19 more UIDs hold other objects, all in stale pairs). Chunk 0x8C9B:

Offset Size Contents IDML Link
0 4 0 in all links
4 4 0x101 in all links (LinkClientID="257")
8 4 UID of the link resource (class 0x8C41)
12 4 1 or 0 LinkResourceModified: 1 false, 0 true
16 4 UID of the graphic (or story)
20 2 1 or 0 ShowInUI: 1 true, 0 false
22 6 three u16, 1 in all links
28 4 0 in all links
32 4 + text import stamp: u32 length, then text segments LinkImportStamp
then 8 modification time of the file (FILETIME) LinkImportModificationTime
then 8 time the file was placed or updated (FILETIME) LinkImportTime

A FILETIME here is the count of 100 ns intervals since 1601-01-01 UTC, stored as two u32: the high half first, then the low half (each in the file's byte order). Evidence: the stamp text is file <n> <size>, and <n> equals the first time value in 4,686 of 4,686 links with a stamp. A link with an empty stamp (length 0) has neither LinkImportStamp nor LinkImportModificationTime in IDML, but has LinkImportTime (13 of 13).

Chunk 0x1B6 of a link (u32, on 59 links) is PDFIdentifier, which IDML writes from DOM 21 on; links without the chunk have PDFIdentifier="0" (81 of 81 DOM 21 links).

Link resources (0x8C41): chunk 0x8C92 is a flag byte, u32 length, then the URI as bytes (LinkResourceURI).

After the URI, chunk 0x8C92 continues:

Offset after the URI Field
0 u8 1, u8 1, u16 0 (all resources)
4 u32 0 or 1, not identified
8 u32 stored state: 0 Normal, 2 Embedded, 3 Contained (StoredState, below)
12 u32 UID of a raw data object (class 0x129), or 0
16 stamp: u32 length, text segments (as in the link)
then modification time (FILETIME, as in the link)
then file size: u32 high half, u32 low half; LinkResourceSize is <high>~<low> in lower-case hexadecimal without leading zeros (0~42ebd)
then u8, 1 in all resources
then in-object string: the format name; LinkResourceFormat is $ID/ and the name, and the graphic's ImageTypeName is the same

Evidence over the 4,699 links of the trustworthy pairs (4,697 with a resource object), with the converter's output compared with the reference:

IDML Equal
LinkResourceModified all 4,699 (5 with 0 = true)
ShowInUI all 4,699 (2 with 0 = false)
LinkImportStamp 4,105 of 4,105 links with the same URI in the INDD and the IDML
LinkResourceSize, LinkResourceFormat 4,118 of 4,118 links with the same URI
PDFIdentifier 81 of 81

The resource's stamp differs from the link's in 184 links; IDML then has the link's stamp and the resource's size. All 63,470 link chunks and their resource chunks in the distinct little-endian corpus files parse with this layout.

Links resolved to another file at export. In 19 trustworthy documents, 529 links differ from the INDD: the IDML names the same file in another folder (344) or a newer file (185). InDesign wrote the location and state of the file it found on the exporting computer; the INDD keeps the state of its last save. These values cannot come from the INDD, and compare.py leaves such links out (docs/measurement.md).

Link times. IDML writes LinkImportTime and LinkImportModificationTime as YYYY-MM-DDTHH:MM:SS (seconds truncated) in the local time of the computer that exported the IDML:

  • IDML equals the INDD's UTC time plus a whole number of hours in 9,009 of 9,385 time values; the other 376 belong to links resolved to another file at export or have no stamp.
  • The offset differs between documents (−8 to +13 hours) and, in 71 of 284 documents, between links of the same document in step with the season (for example 1 and 2 hours, −5 and −4, +10 and +11), with the larger offset on summer dates of that hemisphere: the daylight-saving rule of the exporting computer's time zone, which the INDD does not store.

The converter estimates the offset from the dates of the XMP packet that have a UTC offset (xmp:CreateDate, xmp:MetadataDate, xmp:ModifyDate, every stEvt:when): it takes the offset of the date nearest to the link time in day of the year (difference of the days of the year, not wrapping at the year end; ties: the latest date), and UTC when there is no such date. Over the trustworthy pairs this gives LinkImportTime for 3,886 of 4,446 links and LinkImportModificationTime for 3,316 of 4,434 (links with the same URI: 3,748 of 4,118 and 3,019 of 4,105). Other rules give less: UTC about 155 values of 9,385, the offset of xmp:ModifyDate 6,488, the same rule with the day difference wrapping at the year end 3,840 import times. compare.py leaves both times out of the value coverage (docs/measurement.md).

Embedded links. A link is embedded (StoredState="Embedded") when its resource names a raw data object at offset 12. That object holds the linked file's bytes, which IDML writes as the graphic's Contents.

Evidence:

  • In the 245 distinct little-endian files there are 883 link resources. The field at offset 8 is 2 in 123 of them, and exactly those 123 name a raw data object at offset 12. The other 760 have 0 at offset 12 (742 with 0 at offset 8, 18 with 3).
  • In the corpus pairs, all 10 resources of embedded links (12 links) name a raw data object, and none of the 369 resources of normal links do.
  • For all 12 embedded links, the raw data object's bytes equal the base64-decoded Contents of the IDML graphic (JPEG, PNG, PDF, EPS and SVG files, 2 KB to 11 MB).

Contained links. The field at offset 8 is 3 on exactly the 50 links IDML marks StoredState="Contained": 30 linked stories, 17 stories placed from Word and 3 linked page items. It is 0 on 2,237 Normal links and 2 on 99 Embedded links (the 158 little-endian documents whose IDML has a story link, a link source ID, style mappings or import options; 19 more Normal links have a UID that holds another object, in stale pairs).

Settings shared with page items. Images, PDF, EPS and SVG graphics carry the page item setting chunks (page item settings, above): 0x2C10 name, 0x2C32 visibility, 0x21D4E, 0x21D50 and 0x21D53 change counts, 0x1424 overridden properties, 0x22228 layout constraints, and 0x1B916 object style (AppliedObjectStyle). Many graphics (2,396 images) lack 0x2C10 and 0x2C32; the defaults of the page item table then apply. Graphics never have Locked. Evidence over the 5,131 graphics of the trustworthy pairs: Visible, Name and AppliedObjectStyle 5,131 of 5,131; the change counts, OverriddenPageItemProps and both layout constraints 5,079 of 5,079 from DOM 8 on, and absent in all 52 DOM 7 graphics. Images also have the five fill gradient attributes (GradientFillStart, …Length, …Angle, …HiliteLength, …HiliteAngle) from their attribute list (chunk 0x6E03) with the defaults of page items, and FillColor when the list has attribute 0x6E68 (77 of 77 images; no image without it has FillColor). PDF, EPS and SVG graphics have no gradient attributes.

ImageTypeName is $ID/ and the format name of the link resource (links, above), on graphics with a link only: 4,696 of 4,699 linked graphics; no graphic without a link has it (308 images, 111 PDF, 12 EPS).

Image properties (chunk 0x1708 of an image). u32 count, then per record u32 key, u32 data length n, a u8 (meaning unknown), n bytes; then 4 zero bytes:

Key Data Meaning
0x64 u32 width in pixels
0x65 u32 height in pixels
0x67 u32 colour space: 1 grey, 2 RGB, 4 CMYK
0x6C u32, 16.16 fixed point horizontal resolution (ppi)
0x6D u32, 16.16 fixed point vertical resolution
0x6F colour table present only for indexed colour

In all 3,607 images of the trustworthy pairs, GraphicBounds width and height equal pixels × 72 / resolution. All 29,055 image property chunks of the distinct little-endian corpus files parse. IDML writes these values only on images with a link (3,299 of 3,299; no image without a link has them):

IDML Rule Equal
Space 1 $ID/#Links_Grayscale, 2 $ID/#Links_RGB, 2 with key 0x6F $ID/#Links_Indexed RGB, 4 $ID/#Links_CMYK 3,299 of 3,299
ActualPpi both resolutions rounded half up to integers (72.009 → 72) 3,299 of 3,299
EffectivePpi each ActualPpi value divided by the image's scale on the spread, rounded half up 3,299 of 3,299

The scale on the spread: multiply the ItemTransform of the image with those of all its ancestors (frames, groups, the spread; for an item anchored in text, its own chain only) to get a b c d tx ty. The horizontal scale is √(a² + b²); the vertical scale is |ad − bc| divided by the horizontal scale. Using √(c² + d²) for the vertical scale fails on 87 skewed images; rounding half to even fails on one image whose value is exactly 76.5 (IDML: 77).

Profile (Properties/Profile of Image, chunk 0x7C0F): u32 at 0 is 3 → $ID/Embedded, 1 → $ID/Use Document Default; 0 or no chunk → $ID/None. A profile name follows as an in-object string. 3,607 of 3,607 images (751, 1,652 and 1,204).

Vector colour policies of PDF and EPS graphics (chunk 0x7C42). 16 bytes, four u32. Offset 4 is RGBVectorPolicy, offset 12 CMYKVectorPolicy: 1 IgnoreAll, 3 HonorAllProfiles. Offset 0 is 1 and offset 8 is 3 in all 334 graphics with the chunk. Without the chunk the policies follow the document's colour policies (chunk 0x7C44 of the preferences, preferences.md): RGBVectorPolicy is IgnoreAll when RGBPolicy is ColorPolicyOff, else HonorAllProfiles; CMYKVectorPolicy is IgnoreAll for ColorPolicyOff and CombinationOfPreserveAndSafeCmyk, HonorAllProfiles for PreserveEmbeddedProfiles and ConvertToWorkingSpace. Evidence: with the chunk 334 of 334 graphics; without it 1,005 of 1,005 graphics in 128 documents (5 combinations of document policies).

PDF placement (chunk 0x251B of a PDF).

Offset Size IDML PDFAttribute
0 u32 PageNumber
6 u8 TransparentBackground: 1 true, 0 false
8 u32 PDFCrop: 0 CropContentVisibleLayers, 2 CropArt, 3 CropPDF, 4 CropTrim, 6 CropMedia, 7 CropContentAllLayers

Evidence: 492 of 492 PDFs with the chunk (28 bytes in 486, 64 in 6), all three fields. Without the chunk, IDML has PageNumber="1", TransparentBackground="true" and PDFCrop="CropContentVisibleLayers" in 507 of 509 PDFs; the other 2 (one document) have CropArt, not explained. Every PDF has PDFAttribute (1,001 of 1,001).

Graphic layers (chunk 0x177A of images, PDFs and imported pages).

Offset Size Contents
0 2 1 if an image has a GraphicLayerOption
2 8 unknown
10 4 layer count n
14 n layer records, in IDML order

A layer record is a flagged string (Name; a key is written with $ID/), u32 layer ID (Id), u32 original and u32 current visibility (1 = visible: OriginalVisibility, CurrentVisibility), i32 ID of the parent layer (−1 for a top-level layer), and u32 flags: 0x01 SeparatorLayer, 0x04 FXLayer, 0x08 Locked. A layer whose parent ID is p is a child element of the GraphicLayer with Id p. Self is the graphic's Self, GraphicLayerOption1, and i and the layer ID in hexadecimal for each layer from the top level down (u5dbcGraphicLayerOption1i92i8e is layer 0x8E inside layer 0x92).

Evidence: all 1,064 GraphicLayer elements of the trustworthy pairs (679 PDF, 291 image and 94 imported page layers, 262 of them nested): name, Id, Self, both visibilities and nesting 1,064 of 1,064; flag 0x04 ↔ FXLayer="true" 11 of 11; flag 0x08 ↔ Locked="true" 37 of 37; flag 0x01 ↔ SeparatorLayer="true" 1 of 1. Flags 0x400 (10 group layers) and 0x800 (5) have no IDML counterpart. AdjustmentLayer, HasViewState, ViewState, HasExportState, ExportState, HasPrintState and PrintState are false in all 1,064. GraphicLayerOption with UpdateLinkOption="KeepOverrides" is on every PDF and imported page (1,039 of 1,039, also when the layer count is 0) and on the images whose chunk has 1 at offset 0 (11 of 11; the 1,212 images with 0 there have no element). All 38,087 layer chunks of the distinct little-endian corpus files from InDesign 4.0 on parse; 172 in InDesign 3.0 files do not, and the converter leaves their layers out with a warning.

Layer comps. Images with a GraphicLayerOption also have LayerCompOption AppliedLayerComp: chunk 0x9209 of the image, i32 at offset 4 (−1, −2 or a comp number). 11 of 11.

Movies and sounds (classes 0x14801 and 0x14F01)

Evidence: 21 Movie and 8 Sound elements in 17 trustworthy pairs (DOM 8.0: 2 pairs, 10.2: 11, 11.0: 1, 13.1: 1, 18.0: 2), and 128 movies in 42 files and 42 sounds in 12 files of the corpus (distinct, little-endian, InDesign 3.0 to 18.2; no big-endian sample).

Where they are. A movie or sound is listed in the child list (chunk 0x15B) of a spline item (class 0x6201) and is that frame's only child (170 of 170 objects). Its own chunk 0x15B names the frame as parent (29 of 29 paired) and lists its poster, if any. IDML writes it as a Movie or Sound element, the last child of the frame's Rectangle (29 of 29), with Self the object's UID. The frame is written as a frame without a graphic: ContentType="GraphicType" (its chunk 0x1623 is 1) and no ContourOption in its text wrap (29 of 29 frames).

Chunks.

Chunk Contents IDML Evidence
0x151 matrix ItemTransform; identity without the chunk 29 of 29 (one sound has no chunk and 1 0 0 1 0 0)
0x162B path geometry, as page items Properties/PathGeometry 29 of 29
0x1633 four f64 Properties/GraphicBounds (left, top, right, bottom) 29 of 29
0x8CBC link list, as placed graphics Link 29 of 29
0x15B hierarchy: spread, parent frame, children (the poster) 29 of 29
0x14004 playback settings (below) Name, Description, flags, ControllerSkin 29 of 29
0x1480C (movie), 0x14F03 (sound) label at offset 0, as group labels (u16 0x7B7B, u32 count, flagged key and value strings) Properties/Label 2 movies with one pair match; 6 with count 0 and 21 without the chunk have no Label
0x1B916 object style AppliedObjectStyle 29 of 29
0x21D4E, 0x21D50, 0x21D53, 0x1424, 0x22228, 0x2C32 page item settings change counts, OverriddenPageItemProps, layout constraints, Visible 29 of 29 each
0x3703 text wrap TextWrapPreference 29 of 29 (7 with mode 0; 22 without the chunk, all None with offsets 0)
0x6E03 attribute list TransparencySetting 1 movie with a gradient feather
0x2C10 name chunk of page items not used: flag 1 and an empty string where present (7 objects); Name comes from chunk 0x14004

Not read: 0x14022 (below), 0x8C39, 0x8C24, 0x1623, 0x2C5D, 0x14009, 0x6E20, 0x6EDD and the other page item chunks that 7 of the 29 paired objects carry (0x1E206, 0x1E22B, 0xB30A, 0x2056D, 0x2055F, 0x3723). IDML has no ObjectExportOption, AnimationSetting or TimingSetting on any of the 29 (all 0x2056D counts are 0 and all 0x2055F are 00 00).

Playback settings (chunk 0x14004). A sequence of lists, each a u32 count and that many entries of u32 key and a value whose type depends on the list: list 1 u16, list 2 u32, lists 3 to 6 unknown (count 0 in all 168 chunks that parse), list 7 a flag byte and an in-object string. The chunk ends after list 7 in 167 of 168; one 10.1 movie has one more list (count 1, key 0x14009, 16 bytes) with no IDML counterpart. A 3.0 movie uses keys 0x14800 to 0x14804 and another layout. Keys within a list are in no fixed order. Every u16 value is 1: IDML has true when the key is present and false when it is not.

Key List Movie Sound Evidence (paired)
0x14000 string Name, as stored Name 21 of 21, 8 of 8
0x14002 string Description; "" without the key Description (no sample with the key) 1 with the key, 28 without
0x14008 string ControllerSkin; "" without the key 19 of 19 (11 SkinOverAll, 1 empty, 7 without the key)
0x14003 u16 CustomPoster 21 of 21 (14 true)
0x14006 u16 PlayOnPageTurn PlayOnPageTurn 21 of 21 (3 true), 8 of 8 (7 true)
0x1400C u16 ShowController 19 of 19 (5 true)
0x1400E u16 MovieLoop="true" and PlayMode="RepeatPlay"; without it false and Once SoundLoop 21 of 21 (2 with the key), 8 of 8 (5 true)
0x14004 u16 EmbedInPDF (never stored on a movie: false in 21 of 21) EmbedInPDF 8 of 8 sounds have it and true
0x1400D u16 StopOnPageTurn 8 of 8 (2 true)
0x140FF u16 not identified (1 movie; no attribute differs)
0x14007 u32 not identified (0 in 139, 5485 in one unpaired movie)
0x140FE u32 not identified (5 in all 170)

The 14 movies with CustomPoster="true" have a poster without a link, the 7 with false a linked poster; the converter takes the key. A chunk whose lists 3 to 6 are not empty gives the flags without the strings and a warning; a damaged chunk gives the defaults and a warning.

Values without a stored field. These are the same in every IDML of the corpus with these elements (19 files, paired or not: DOM 8.0, 10.1, 10.2, 11.0, 13.1, 18.0). No stored field was found for them; the converter writes them as defaults.

Element Attribute Value Samples
Movie FloatingWindow false 27 of 27
Movie FloatingWindowPosition Center 27 of 27
Movie FloatingWindowSize Full 27 of 27
Movie ShowControls false 26 of 26 (DOM 8.0 to 13.1)
Sound DoNotPrintPoster false 13 of 13
both LocalDisplaySetting Default 40 of 40

ShowControls, ControllerSkin and ShowController are on all 26 movies of DOM 8.0 to 13.1, also on the 7 whose chunk has neither key 0x14008 nor 0x1400C, and on none in the one DOM 18.0 file. They follow the version, not the stored keys. No IDML of DOM 14 to 17 has a movie; the converter writes them below DOM 18.

FilePath is the LinkResourceURI of the media's own link as a native path: without file:, percent-decoded as UTF-8, and with \ for / in a path that starts with a drive letter (C:/). From the IDML's own link URI this gives FilePath in 29 of 29 (25 Windows paths, 4 Mac paths). From the INDD's link it gives 8 of 29: the other 21 links were resolved to another file on the exporting computer, and the IDML has that file's path in both Link and FilePath. A media object without a link has no FilePath.

Children. IDML order (29 of 29): Properties (PathGeometry, GraphicBounds, then Label), TransparencySetting, TextWrapPreference, the poster Image, Link.

  • Text wrap: as for placed graphics (chunk 0x3703; without it mode None and offsets 0), 29 of 29. ContourOption is in the wrap of every movie and sound with a poster (26 of 26) and of none without (3 of 3), as a frame has one only with a graphic. All 26 are SameAsClipping, false, $ID/; no media object has chunk 0x373D, and the poster's contour and the preferences' contour agree in all 26, so either can be the source. The converter uses the poster's.
  • Poster: 125 of 128 movies and 9 of 42 sounds list one child, an image (class 0x1702). IDML writes it as an Image child (26 of 26 paired), like any image: 12 linked, 14 with their file in the document (Properties/Contents). Its EffectivePpi uses the transforms of the image, the movie or sound, the frame and their ancestors (12 of 12 linked posters).
  • Link: the layout of image links (chunks 0x8C9B and 0x8C92). For the 8 links whose URI is the same in INDD and IDML, LinkResourceFormat ($ID/Flash H264 Video, $ID/MP3, $ID/Flash Video, $ID/SWF (Shockwave Flash)), LinkResourceSize and LinkImportStamp match 8 of 8.

Media file properties (chunk 0x14022). The same kind of typed list, with list types u16, u32, u64, f64, four f64 and flagged string (29 of 29 paired chunks end after the sixth list). Keys seen: 0x14002 and 0x14004 (u16); 0x140FE, 0x14F00 (sounds: 44100, the sample rate) and 0x14F02 (sounds: 128) (u32); 0x14000 (u64); 0x14006 (f64, movies: the duration in seconds); 0x14001 (four f64, movies: the frame size, for example 0 0 640 640); 0x14003 and 0x14005 (strings; 0x14005 of sounds is an older import path that matches neither link URI). IDML writes none of these: no IDML in the corpus has IntrinsicBounds, CanChoosePosters or PosterAvailable, a NavigationPoint or a Movie URL.

References. MovieBehavior/@MovieItem (6 in 5 pairs) and SoundBehavior/@SoundItem (2 in 1 pair) name a Movie or Sound of the same IDML (8 of 8); see button behaviours. TimingTarget elements with TargetRole 132354 (3 movies) and 132356 (7 sounds), in 9 pairs, name a written Movie or Sound in 10 of 10; see timing lists.

Text on a path (class 0xB320)

A shape or text frame with text on its path names a text path object in chunk 0xB30A (600, 392 or 336 bytes). Items without text on their path can have the chunk too, with 0 in the first u32.

Offset in 0xB30A Contents IDML TextPath
0 u32 text path UID (class 0xB320), 0 for none Self
4 u32, the same UID
8 u16 1, u16 4, u32 3 in all 41 PathAlignment="CenterPathAlignment", TextAlignment="BaselineTextAlignment", PathEffect="RainbowPathEffect", PathSpacing="0" (which field is which is not known)
16 u8: 1 Flipped, 0 NotFlipped FlipPathEffect
18 f64 StartBracket
26 f64 EndBracket

The text path object has chunk 0xB334: u32 (its own UID), u32 0, then a UID list with one multi-column frame (class 0x263). That frame's 0x15B child list holds a column of class 0xB318, which gives the story and the thread as the column of a text frame does (text frames, below): ParentStory, PreviousTextFrame and NextTextFrame (n in every sample).

IDML writes TextPath as a child of its shape or frame, directly after Properties, with the attributes in the order of the table (then the two thread attributes). The converter writes the four constant values only when the bytes at 8 are those of every sample.

Evidence: 42 TextPath elements with an INDD object in the pairs (36 in trustworthy pairs; parents: polygons, an oval and text frames), all values equal in 42 of 42, both FlipPathEffect values occurring.

EPS text (class 0x660B)

Text kept from a placed EPS or PDF graphic as text that cannot be edited. IDML writes it as an EPSText page item. It is listed in the 0x15B child list of a spread layer or a group (483 of 634 are in groups), and has the usual page item chunks (0x151 transform, 0x6E03 attributes, 0x1B916 object style, 0x3703 text wrap, 0x2C10 name, …) but no path.

Chunk Contents IDML
0x151 Matrix ItemTransform
0x154 Four f64: left, top, right, bottom Properties/PathBoundingBox Left, Top, Right, Bottom
0x6612 60 bytes: four f64 in the same order, then f64 72 and zeros (not identified) Properties/EPSTextAttributeBounds Top, Left, Bottom, Right, from the four f64
0x6611 Text record (below) Properties/EPSTextData

Text record (chunk 0x6611). u32 version (0x00010002 in all 634), a flagged in-object string (the font name), nine f64 (a matrix of font size, 0, 0, font size, x, y, then three numbers), a flagged in-object string (the text) and a tail of 210 bytes: u32 at 0 (16 in all), zeros to 72, u32 at 72 (varies), u16 at 76 (0 or 1), u32 at 78 (14 in all), zeros to 210.

IDML EPSTextData is this record in big-endian byte order, without the u32 at 72 and at 78 of the tail, in base64 in lines of 76 characters: each number big-endian, each string as in big-endian data (tag 2, flag, the byte after the tag, u16 length, each segment header big-endian, byte segments copied and UTF-16 code units big-endian), and the zero areas copied. So EPSTextData is 8 bytes shorter than the chunk.

IDML writes Properties (PathBoundingBox, EPSTextData, EPSTextAttributeBounds) and then TextWrapPreference; EPSText has no ContentType, no path and no export options. Its other attributes are those of other page items (page item settings, above); the values that every EPSText has come from element_values.xml.

Evidence: 634 EPSText elements in 14 pairs (633 in 13 trustworthy pairs), versions 8.1 to 20.5. The transform, both bounds, the text data and the text wrap equal the IDML in 634 of 634. StrokeType (634), OverprintFill (33) and StrokeDashAndGap (7) are not reproduced yet: IDML writes StrokeType="StrokeStyle/$ID/Solid" on 627 items whose attribute list has no stroke type.

Form fields and multi-state objects

Seven classes are page items that IDML writes as interactive elements:

Class IDML Elements (documents)
0x1450C Button 284 (43)
0x1450D CheckBox 72 (5)
0x1450E RadioButton 11 (4)
0x1450F TextBox 27 (4)
0x14511 ComboBox 1 (1)
0x14512 SignatureField 2 (2)
0x145D8 MultiStateObject 18 (16)

Counts are over the pairs of the corpus of 2026-10: 48 documents, all trustworthy, saved by InDesign 8 to 20. Each element's Self is the object's UID (415 of 415). A field is listed like any page item, in the child list of its spread, group or anchor, and its fields and states nest (a button inside a group inside a multi-state object's state).

Fields with states (button, check box, radio button, multi-state object) have no chunk 0x15B and no 0x151:

  • Chunk 0x14521: u32 active state ID, u32 count, then per state u32 state ID, u16 enabled (1, or 0 for Enabled="false"), u16 key, u16 (0). IDML writes one State per entry, in order (705 of 705), with Self the field's Self, i and the state ID in hexadecimal, Active="true" for the active state ID and Enabled from the u16 (705 of 705; 4 not enabled).
  • Chunk 0x14526: u32 spread, u32 parent, u32 count, then per key u32 key, u32 k, k UIDs: the items each state shows, by its key (one group per state in 705 of 705). The chunks parse to their end in all 385 fields. The spread decides AllowOverrides as chunk 0x15B does for other items.
  • Chunk 0x14527: six f64, the transform (ItemTransform, 385 of 385).

State types. Properties/Statetype follows from the state ID. For a multi-state object it is the ID itself (type="long", IDs 9 to 15; 72 of 72 states). For the others it is an enumeration (633 of 633):

ID Statetype States Name of the state's group without a name of its own
0 Up 284 $ID/$$$/StateType/Normal
1 Rollover 109 $ID/$$$/StateType/Over
2 Down 61 $ID/$$$/StateType/Down
3 UpOn 83 $ID/$$$/StateType/NormalOn
4 UpOff 83 $ID/$$$/StateType/NormalOff
6 RolloverOff 7 $ID/$$$/StateType/OverOff
7 DownOn 3 $ID/$$$/StateType/DownOn
8 DownOff 3 $ID/$$$/StateType/DownOff

The key is not the state type: a button's second state has key 2 whether it is Rollover (ID 1) or Down (ID 2). ID 5 has no sample; a state with an ID not in the table is left out with a warning. A state's group has no name chunk (0x418), or one with flag 1 and an empty name; IDML names it by the state type, as in the table (633 of 633 groups of buttons, check boxes and radio buttons). The groups of multi-state objects have names of their own (72 of 72).

Fields with child items (text box, combo box, signature field) have the usual chunks 0x151 (transform) and 0x15B, whose children IDML writes inside the element: a Rectangle or TextFrame (30 of 30). Text boxes can be anchored in text, with the anchor's AnchoredObjectSetting.

Properties/PathBoundingBox. The bounds of the paths of the items the field shows, in the field's own coordinates: the curves through the anchor and direction points (not only the anchors) of the items of every state, or of the child items, each through its transform and those of the groups and fields between it and the field. Items inside a frame (an oval inside an oval) do not count. The converter takes each item's box in its own coordinates and the box around its corners through its transform, from the innermost item out: 415 of 415 equal to 6 significant digits, 379 of them as text (the others differ in the last digit or two). The field has no PathGeometry.

Attributes from the attribute list (chunk 0x6E03). Strings have value type 0x1451F or 0x1B02 (a flag byte and an in-object string), numbers 0x6E68 (f64), flags 0x6E65 (u16).

ID IDML On Evidence
0x14534 Name all 415 of 415, 237 distinct
0x14535 Description all but multi-state objects 397 of 397 (23 distinct); 3 multi-state objects have Description="" without it
0x1453D Required (1 true) check box, radio button, text box, combo box, signature field 113 of 113 (6 true); buttons have the attribute but IDML writes no Required
0x14550 ExportValue check box, radio button 83 of 83 (9 distinct)
0x14552 Multiline text box 27 of 27 (8 true)
0x14553 Scrollable text box 27 of 27 (9 true)
0x14540 FontSize text box, combo box 28 of 28 (4 distinct); signature fields have it, IDML writes none
0x1455F AppliedFont text box 24 of 24 (2 distinct); the 3 text boxes without it have neither AppliedFont nor FontStyle
0x14542 FontStyle text box with 0x1455F 24 of 24

The flags ReadOnly, PrintableInPdf, CheckedByDefault, Password, RightToLeftField, SortChoices, HiddenUntilTriggered, InitiallyHidden and VisibilityInPdf have one value in every sample, and so do the candidate u16 attributes (0x14539 to 0x1453C, 0x14545, 0x14549, 0x14551, 0x14554 to 0x14558, 0x145E1); which holds which cannot be shown. Where every IDML has the value, it comes from the value files (idml-values.md, form fields). ChoiceList of the combo box (0x1455D, one sample) is not decoded.

Values of the page item. Visible, Locked, the change counts, the layout constraints and ItemLayer follow the page item rules (page item settings). The gradient attributes are, as for a group, the values all the items the field shows directly have (the state groups or the child items), and IDML leaves an attribute out where they differ: the six gradient attributes are equal in 400 of 415 fields (4 of them without the start and length values). The fill, stroke and corner values in the field's attribute list are not IDML's: IDML's FillColor and corner values of buttons are not in the list, and other stored values differ, so they are not written. Fields with states have no object style chunk (0x1B916); IDML names [None] for 363 of their 385 and another style for 22, and where that is stored is not known, so AppliedObjectStyle is left out for them, and so are the anchor settings of such a field anchored in text, which IDML compares with the style (12 anchored check boxes and radio buttons with a style other than [None] have no AnchoredObjectSetting). A field has no ObjectExportOption.

Timing lists of buttons and animations: animation and timing, below.

Behaviours of buttons: button behaviours, below.

Button behaviours

Evidence: 206 behaviour elements in 193 buttons of 26 pairs (all trustworthy, versions 8.0 to 18.0), and 547 behaviour objects in 78 documents of the corpus (InDesign 3.0 to 18.2, both byte orders). The converter writes every behaviour type that has a paired sample, and compare.py finds all their values in its output.

Behaviour list (chunk 0x15601). A form field lists its behaviours by event:

u32 groups
  per group: u32 event code, u32 count k, k behaviour UIDs
  • The chunk parses to its end in 712 of 712 fields (all field classes; 271 have 0 groups). Only buttons have groups (441 buttons).
  • Every behaviour object is listed in exactly one group of one field (547 of 547). No group is empty.
  • IDML writes the behaviours as children of the button, in group order and, within a group, in stored order (193 of 193 buttons). In the five buttons with two groups the stored order is also ascending event code, so these two orders cannot be told apart.
  • They are the last children of the button, after every State (193 of 193). The schema allows them in any order there.
Event code BehaviorEvent Paired behaviours
0x15602 MouseDown 32
0x15603 MouseUp 145
0x15604 MouseEnter 29

Unpaired groups also have 0x15605 (31) and 0x15607 (1). Their events are not known: the behaviour is written without BehaviorEvent, with a warning.

Behaviour objects. Each behaviour type is a class. IDML Self is the object's UID (206 of 206); timing targets of role 132353 reference these UIDs (53 of 53 resolve in the converter's output). The object has one data chunk, and some also chunk 0x156E1, a label with the layout of the document label. Chunk 0x156E1 has count 0 in all 112 occurrences, and no IDML behaviour has Properties/Label; a label with pairs would be written there (no sample).

Class IDML element Data chunk Type code Objects (paired elements)
0x15613 GotoFirstPageBehavior 0x15614 0x15601 10 (7)
0x15614 (go to last page, no pair) 0x15619 0x15602 2 (0)
0x15615 GotoNextPageBehavior 0x1561A 0x15603 88 (21)
0x15616 GotoPreviousPageBehavior 0x1561B 0x15604 37 (24)
0x1561B GotoURLBehavior 0x15622 0x15605 45 (11)
0x1562C MovieBehavior 0x1562C 0x15606 99 (6)
0x15636 ShowHideFieldsBehavior 0x15634 0x15607 29 (26)
0x15664 ClearFormBehavior 0x15650 0x15609 3 (1)
0x1566E SubmitFormBehavior 0x1565A 0x1560A 5 (1)
0x15678 OpenFileBehavior 0x15664 0x1560B 1 (1)
0x156D3 GotoAnchorBehavior 0x156F0 0x15617 27 (18)
0x156DD GotoNextViewBehavior 0x15703 0x15619 12 (12)
0x156E8 (view zoom, no pair) 0x1570A 0x1561A 5 (0)
0x156F4 SoundBehavior 0x1571C 0x1561B 7 (2)
0x15625 GotoPageBehavior 0x156DE 0x1561C 54 (30)
0x1562F (animation, no pair) 0x1566C 0x1561D 16 (0)
0x1563F GotoStateBehavior 0x1566D 0x1561E 80 (37)
0x15643 GotoNextStateBehavior 0x1567D 0x1561F 17 (4)
0x15660 GotoPreviousStateBehavior 0x15680 0x15620 8 (4)
0x156F9 PrintFormBehavior 0x15721 0x15621 2 (1)

The class and the element match in 206 of 206 paired behaviours. The type code is constant per class in 547 of 547 objects. The three classes without a pair are named by their built-in name keys ($$$/Forms Action/GoTo Last Page, …/View Zoom, …/Animation); the converter leaves them out with a warning.

Data chunk. All data chunks start with a common header:

Field Contents Evidence
u32 UID of the field that owns the behaviour 206 of 206 equal to the IDML parent button
u32 type code (table above) constant per class, 547 of 547
flag byte, in-object string the name: flag 1 and a built-in key $$$/Forms Action/… flag 1 in 547 of 547
u16 EnableBehavior (1 true) 1 in 547 of 547; all 206 paired are true. That 0 is false is assumed

The type's fields follow (all u32 unless stated otherwise); the chunk ends after them in 546 of 547 objects. The exception is a 3.0 movie behaviour that ends after the operation. Big-endian objects (2 files of 8.0, 3 files of 4.0) parse to their end with the flag and string tag swapped (big-endian.md).

Type Fields IDML Evidence
first, last, next, previous page, next view navigation kind (0 first, 1 last, 2 previous, 3 next, 5 next view), zoom ZoomSetting from the zoom kind constant per class, 203 of 203 objects; zoom 64 of 64
go to page navigation kind 6, page index, zoom PageNumber = index + 1, ZoomSetting 30 of 30 (pages 1 to 6)
go to anchor flag byte (0 in 27 of 27), in-object string, anchor u32, zoom FilePath, ZoomSetting, Properties/AnchorItem (type="long") 18 of 18
go to URL flag byte, in-object string URL 11 of 11, plain and navto:// URLs
open file flag byte, in-object string FilePath 1 of 1
submit form u32 (0 in 5 of 5), flag byte, in-object string URL 1 of 1
clear form, print form none 1 and 1
show/hide fields count n, n × (field UID, action: 0 hide, 1 show) FieldsToHide, FieldsToShow 26 of 26
go to state, next state, previous state multi-state object UID, kind (0, 1, 2; constant per class, 105 of 105), u16 (0 in 105), u16 (1 in 45 paired, 0 in 3 unpaired), i32 state ID (-1 for next and previous) AssociatedMultiStateObject; go to state Properties/Statetype (type="long") = state ID 45 of 45; state IDs 37 of 37
movie movie UID, operation (0 Play), i32 navigation point Operation, NavigationPointID 6 of 6 (all -1)
sound sound UID, operation (0 Play, 1 Stop), f64 (1.0 in 5, 0.0 in 2 of 7), u32 (0 in 7) Operation 2 of 2
view zoom (no pair) u32 (0 in 5)
  • Zoom codes: 0 InheritZoom (every page navigation behaviour and 8 anchors), 2 FitWindow (10 anchors). No other code occurs. Movie operation 3 (2 unpaired objects) and sound operation 2 (1) are not known. An unknown code leaves the attribute out, with a warning.
  • FieldsToHide lists the UIDs with action 0 and FieldsToShow those with action 1, each in stored order, as references separated by spaces. With no such UID the attribute is written empty. The action is 0 or 1 in all 149 corpus entries.
  • AnchorItem is the stored u32 when FilePath is not empty (5 of 5, anchors in another file). When FilePath is empty it is 0 (13 of 13): the stored u32 is 0 in 8, and in 5 it is a UID with no object.
  • In the converter's output the button (206 of 206) and every AssociatedMultiStateObject (45 of 45), FieldsToHide UID (124 of 124) and FieldsToShow UID (25 of 25) exist as Self.
  • MovieItem and SoundItem are the stored movie and sound UIDs: each names a Movie or Sound of the same IDML (6 and 2 of 6 and 2; movies and sounds). A UID that is not a written movie or sound is left out.
  • The sound's f64 and last u32 and the submit u32 have no IDML attribute.

Values with no stored field. These are the same in every sample, and no stored field was found for them. The converter writes them as defaults:

IDML Value Samples
GotoAnchorBehavior AnchorName $ID/ 18 of 18
GotoStateBehavior GoBackOnRollOff false 37 of 37
GotoNextStateBehavior, GotoPreviousStateBehavior LoopsToNextOrPrevious true 8 of 8

The second u16 of a state behaviour is 1 in all paired samples, which is consistent with LoopsToNextOrPrevious="true" but does not prove it.

Name. No behaviour has a name of its own: the name is a built-in key with flag 1 in all 547 objects. IDML writes the key's name in the language of the exporting InDesign, which follows the saving edition (the XMP black name, saving edition): in all 26 pairs the edition matches the language of every behaviour name (1 English, 7 Korean and 18 Chinese documents). The converter writes the names below and leaves Name out for a key or edition without a sample. A name with flag 0 (no sample) would be written as stored.

Key ($$$/Forms Action/…) English Korean Chinese
GoTo Anchor Go To Destination (10) 대상으로 이동 (8)
GoTo First Page 첫 페이지로 이동 (3) 跳至第一頁 (4)
GoTo Next Page 다음 페이지로 이동 (1) 跳至下一頁 (20)
GoTo Previous Page 이전 페이지로 이동 (1) 跳至上一頁 (23)
GoTo Next View 다음 보기로 이동 (12)
GoTo Page 跳至頁面 (30)
GoTo URL 前往 URL (11)
SwitchToMSOState 상태로 이동 (13) 跳至狀態 (24)
SwitchToNextMSOState 다음 상태로 이동 (1) 跳至下一個狀態 (3)
SwitchToPrevMSOState 이전 상태로 이동 (1) 跳至上一個狀態 (3)
Movie 影片 (6)
Sound 聲音 (2)
Show/Hide Fields 顯示/隱藏欄位 (26)
Open File 開啟檔案 (1)
Submit Form 送出表格 (1)
Reset Form 清除表格 (1)
Print Form 列印表格 (1)

The Chinese names are Traditional Chinese. Of the 93 trustworthy pairs with the black name 黑色, 92 name their paper swatch 紙張 (Traditional Chinese) and one has no paper swatch; the corpus has no Simplified Chinese saving edition.

Attribute order. The type's attributes first, in schema order, then Name, EnableBehavior and BehaviorEvent. Example: <GotoPageBehavior Self="u762" ZoomSetting="InheritZoom" PageNumber="1" Name="跳至頁面" EnableBehavior="true" BehaviorEvent="MouseUp" />.

Not shown. Behaviours of other field types (the schema allows most types on check boxes, radio buttons, text boxes, combo boxes, list boxes and signature fields; the corpus has none, and the converter leaves them out with a warning); AnchorItem of a live anchor in the same document; URLs stored with flag 1 (6 unpaired objects, key $$$/Dialog/Behaviors/GoToView/DefaultURL, and one empty submit URL), which the converter leaves out.

Animation and timing

Spreads and buttons keep timing lists, page items an animation, and the document a list of motion presets. Evidence: the 43 pairs of the corpus whose IDML has any of these elements (little-endian, versions 8.0 to 18.0; all trustworthy). The layouts are the same in all versions. A sweep of the first occurrence of each chunk in the spreads, buttons, spline items, groups and preferences of all 1,251 trustworthy pairs found non-empty timing lists, preset lists or animations only in these 43 documents. The converter writes all of them by the rules below, and compare.py finds all 3,783 of their values in its output for these 43 pairs.

Strings below:

  • Text string: u32 length in UTF-16 code units, then text segments.
  • Name: a flag byte (1 = built-in key, $ID/ in IDML) and an in-object string.

Timing lists (chunks 0x2056D and 0x2056E)

Spreads keep their timing lists in chunk 0x2056D, buttons (class 0x1450C) in chunk 0x2056E. Most page items also have chunk 0x2056D, with a count of 0.

u32 lists
  per list:   u32 trigger, u32 groups
    per group:  u32 targets
      per target: u32 UID, u32 role, u32 action, u32 (0 in all 163), f64 delay
    then:       u32 plays, u16 (0 in all 159)

The chunk parses to its end in 96 of 96 owners. IDML writes a TimingSetting exactly when the list count is not 0: 43 of 43 spreads and 53 of 53 buttons with lists have one; 20 spreads and 119 buttons with count 0 have none.

IDML Source Evidence
TimingList Self owner Self + TimingSetting1TimingList + list index (from 0) 96 of 96
TriggerEvent trigger code: 1 OnPageLoad, 5 OnClick, 6 OnRelease, 7 OnRollover 43 / 2 / 45 / 6; spreads all 1
TimingGroup Self list Self + TimingGroup + group index (from 0) 159 of 159
Plays u32 plays 159 of 159 (all 1)
TimingTarget Self group Self + i + target UID in hex 163 of 163
DynamicTarget u + target UID in hex 163 of 163
DelaySeconds f64 delay 163 of 163 (0 and 0.25)
TargetRole u32 role, in decimal 163 of 163
TargetAction u32 action, in decimal 163 of 163 (all 132353)
Placement target index in its group (from 0) 163 of 163

Roles by target class: 132353 button behaviours (classes 0x1562C, 0x1563F, 0x15643, 0x15660, 0x156F4; 53 targets), 132354 movies (3), 132355 spline items, groups and multi-state objects (100), 132356 sounds (7). The stored value is written as is.

Every target of the samples names an element the converter writes: a page item, a button behaviour, or a movie or sound (7 sound and 3 movie targets of 163; movies and sounds). The converter leaves out a target whose element it does not write, with a warning, and numbers Placement over the targets kept. A group or list left empty is left out too: no sample has an empty one (159 groups, 96 lists).

Example, a spread with one list, one group and one target: 01 00 00 00 | 01 00 00 00 01 00 00 00 | 01 00 00 00 | 63 04 00 00 03 05 02 00 01 05 02 00 00 00 00 00 | 00 00 00 00 00 00 00 00 | 01 00 00 00 00 00.

IDML writes the spread's TimingSetting after FlattenerPreference and before the pages, and the button's after TextWrapPreference and before the State elements (53 of 53). Multi-state objects have chunk 0x2056D with count 0 in all samples; where their timing lists would be stored is not shown.

Motion presets (class 0x20517)

Chunk 0x2053E of the preferences object (class 0x2202): u32 n, then n preset UIDs. IDML writes one MotionPreset in designmap.xml per UID, in this order, after the NamedGrid elements (63 presets in 30 documents; 5 more documents have the chunk with n = 0 and no MotionPreset).

Chunk 0x20532 of a preset:

Field IDML
text string Properties/Contents, as is (63 of 63; IDML writes it as CDATA)
4 bytes not mapped; they vary without pattern (00 00 00 00, 5C 00 50 00, …)
name empty, flag 1 in all 63
name Name: $ID/ and the string for flag 1 (63 of 63, all flag 1)

The chunk parses to its end in 63 of 63. The stored name is not always the one inside the preset's XML (appear stored, Appear in the XML's <name>); IDML takes the stored name (2 of 2).

Animation settings (chunk 0x2055F)

Every spline item (class 0x6201), group (0x401), button (0x1450C) and multi-state object (0x145D8) has chunk 0x2055F, and so do placed graphics. Two bytes 00 00 mean no animation: IDML writes no AnimationSetting (1,996 of 1,996 objects with this chunk in the 43 documents, items and graphics). A longer chunk means an animation, and IDML writes AnimationSetting (100 of 100: 57 rectangles, 22 text frames, 13 ovals, 6 multi-state objects, 2 groups). Longer chunks also occur in 12 objects that are not written as page items (classes 0x129, 0x1D6, 0x301, 0x3E03, 0x8C41, 0x8C4B, 0xCA8B).

Offset Type IDML Evidence
0 u16 not mapped 1 in 100 of 100
2 u16 HasCustomSettings: 1 true, 0 false 100 of 100 (20 true)
4 u32 Properties/Preset type="object": the preset UID 100 of 100
8 f64 Duration, in seconds 100 of 100 (1, 0.5833…, 1.0416…)
16 u32 not in IDML: 24 (frames per second) 100 of 100
20 u32 not in IDML: frames, Duration × 24 100 of 100
24 u32 DesignOption: 0 FromCurrentAppearance, 2 ToCurrentLocation 44 / 56
28 u32 not mapped: 0 in all 100 of 100
32 u32 Plays 100 of 100 (87 × 1, 13 × 2)
36 u16 not mapped: 0 in all 100 of 100
38 u32 EaseType: 0 NoEase, 4 CustomEase 3 / 97
42 2 × f64 TransformOffsets, each rounded to 6 significant digits 100 of 100 (0.499924 0.499886)
58 motion path key frames, motion path points, properties (below)

From offset 58:

u32 n             key frames of the motion path
  per key frame:  u32 frame, u32 (2 in all 155), f64 x, f64 y
u32 m             points of a motion path without key frames
  per point:      u32 (2 in all 4), f64 x, f64 y
u32 p             animated properties
  per property:   text string (name), text string (the same name again),
                  u32 k keys, per key: u32 frame, u32 (6 in all 528), f64 value

The chunk parses to its end in 100 of 100.

  • Properties/MotionPath: one AnimationDataPathKeyFrameType KeyFrame="frame" per key frame, with PathPoint Anchor="x y" LeftDirection="x y" RightDirection="x y" (98 of 98 with n > 0; left and right direction equal the anchor in all 155 points). No MotionPath when n = 0 (2 of 2).
  • Properties/MotionPathPoints: when m > 0, a PathPointArray with one PathPointType per point, anchor and both directions x y (2 of 2; both have n = 0).
  • Properties by name: Alpha_Amount → OpacityArray, Rotation_Z → RotationArray, Scale_X → ScaleXArray, Scale_Y → ScaleYArray; each key is AnimationDataKeyFrameType KeyFrame="frame" Value="value" (all 396 arrays). A property with no keys has no element (1 of 1), and neither has a property that is not stored (4 items have no Alpha_Amount, and no OpacityArray). The second name equals the first in 396 of 396.
  • Properties children are in the order Preset, MotionPath or MotionPathPoints, OpacityArray, RotationArray, ScaleXArray, ScaleYArray (100 of 100).

Numbers other than TransformOffsets are in the shortest form (764.0000000000001, -552.6140386840932, 0.5833333333333334; all 100 elements). IDML writes AnimationSetting after ObjectExportOption and before child items and placed graphics, and after the State elements of a multi-state object (100 of 100).

Values without a stored field

These attributes have one value in every sample, and no stored field was found for them. The converter writes that value:

Attribute Value Samples
TimingGroup/@PlaysLoop false 159
TimingTarget/@ReverseAnimation false 163
AnimationSetting/@PlaysLoop false 100
AnimationSetting/@InitiallyHidden false 100
AnimationSetting/@HiddenAfter false 100
MotionPreset/@EditLocked, @DeleteLocked, @NameLocked false 63 each
MotionPathPoints/@PathOpen true 2

Candidate fields are 0 in every sample: in a timing target the u32 after the action (ReverseAnimation?), after a group's plays the u16 (PlaysLoop?), in chunk 0x2055F the u32 at 28 (InitiallyHidden and HiddenAfter?) and the u16 at 36 (PlaysLoop?). Mapping them needs a sample with a true value.

Not shown

  • Codes without samples: DesignOption 1 (the schema's third value is ToCurrentAppearance), EaseType 1 to 3, trigger codes other than 1, 5, 6 and 7. The converter leaves such an attribute out with a warning.
  • Curved motion paths: every path point has u32 2 before its coordinates and left and right directions equal to the anchor.
  • Chunk 0x2056C of spreads (a UID list), the 4 bytes after a preset's contents and the frame fields at 16 and 20 of chunk 0x2055F are not needed for IDML.
  • Big-endian files: no samples.

Placed InDesign pages (class 0x6607)

A placed page of another InDesign document is a child of a frame, like an image, and has the chunks of placed graphics (transform 0x151, bounds 0x1633, link 0x8CBC, text wrap). IDML writes it as ImportedPage. Chunk 0x2505 (68 bytes) holds the page: its u32 at 0 plus 1 is PageNumber.

The converter writes ImportedPage with PageNumber, the attributes of placed graphics (ImageTypeName from the link format, $ID/InDesign Format Name), Properties/GraphicBounds, TextWrapPreference and Link. Not decoded, and left out: ImportedPageCrop (41 of 42 are CropContent, 1 CropBleed; the byte at 18 of 0x2505 is 0 in 28 and 1 in 13 CropContent items, so it is not that field), MetadataPacketPreference (an XMP packet of an object of class 0x12609 that chunk 0x12629 names), GraphicLayerOption and PDFAttribute. ClippingPathSettings is described under clipping path settings.

Evidence: 42 ImportedPage elements in 8 pairs (38 in 7 trustworthy pairs). ItemTransform, GraphicBounds and PageNumber equal the IDML in 42 of 42.

A graphic with no link (its chunk 0x8CBC names no link) can hold its file itself:

Class Chunk Contents
Image (0x1702), EPS (0x6601) 0x8C23 u32 raw data object (0 = none)
PDF (0x2501) 0x2521 u32 raw data object (0 = none)

EPS graphics (class 0x6601) without a link name their raw data object in chunk 0x8C23 too: over the trustworthy pairs of the corpus after 2026-10 the converter reproduces 497 of the 515 EPS Contents (483 were missing before; 18 differ and are not examined). Linked graphics can have the chunk as well; their IDML has no Contents, and the converter does not use it for them.

Evidence from the corpus pairs: the raw data object equals the IDML Contents for 124 of 124 PDFs and 2 of 2 images without a link. In the whole corpus, two linked and embedded PDFs also have a 0x2521 object, different from the link resource's; with no pair to compare, the converter uses the link resource's.

Images that keep their file in their preview

An image (class 0x1702) without a link whose chunk 0x8C23 is 0 or absent keeps its file in its preview (next section): chunk 0x170D names an object of class 0x1708, whose chunk 0x119 names a raw data object. IDML writes that object's bytes as Contents. The converter does so only for images, and not for an image whose chunk 0x8C1B names an object (see the end of this section). Linked graphics, EPS and PDF graphics do not use their preview as Contents.

Evidence, over the 9,608 graphics (Image, EPS, PDF, SVG, WMF, ImportedPage) in the reference IDMLs of the 1,252 trustworthy pairs, each paired with its INDD object by Self:

Images Count IDML Contents Preview data equals Contents
No link, 0x8C23 = 0 359 359 359
No link, no chunk 0x8C23 17 17 17
No link, 0x8C23 names a raw data object 77 77 4 (the 0x8C23 object equals it in 77)
Linked, embedded 101 101 38
Linked, not embedded 6,886 0 –
  • The 376 images of the first two rows are in 31 pairs, InDesign 8.0 to 18.x. None of them lacks Contents in its IDML. Of the 362 that the converter writes, 357 have chunk 0x8C1B set to 0 and 5 have no chunk 0x8C1B.
  • Over the whole little-endian corpus (5,734 distinct files), 2,456 images without a link have 0x8C23 = 0 or no 0x8C23. All of them have the complete chain: 0x170D names a class 0x1708 object whose chunk 0x119 names a raw data object. No image without a link has a 0x8C23 that names anything other than 0 or a raw data object. 1,773 of them, in 150 files (InDesign 3.0 to 21.x), have 0x8C1B = 0 or no 0x8C1B; the converter writes their preview data as Contents. 15 more are in 3 big-endian files (InDesign 8.0 and 11.x).
  • The 17 images with no chunk 0x8C23 have no chunk 0x8CBC either; 5 of them (InDesign 8.0 and 11.x) have only 11 or 12 chunks.
  • Every EPS (483) and PDF (111) graphic without a link names a raw data object, so the case occurs only for images. For EPS graphics without a link the preview never equals Contents (0 of 483).
  • Formats of the 376 Contents: 357 in the EPSImage form below, 17 JPEG, 2 TIFF. Of the 2,456 in the whole corpus: EPSImage 1,539, JPEG 514, TIFF 391, PNG 12.
  • The converter reproduces 362 of 362 such Contents that it writes in the trustworthy pairs, in 20 documents, with no Contents where the reference has none. The other 14 images belong to structures the converter leaves out.

The EPSImage form. 357 of the 376 Contents start with the 8 ASCII bytes EPSImage, then five u32 (little-endian): bytes per row, width, height, bits per channel, channels. Pixel data follows, height × bytes per row bytes, with nothing after it: the length is 28 + height × width × channels in 357 of 357 (8 bits per channel in all; 3 channels in 182, 4 in 175). All 357 have 0x8C23 = 0. The converter copies the bytes and does not read this form.

Images that name an old link object. 762 images without a link and with 0x8C23 = 0 or no 0x8C23, in 79 files of InDesign 2.0 to 5.0 (683 images in 53 little-endian files, 79 in 26 big-endian files), have no chunk 0x8CBC, and their chunk 0x8C1B (u32) names an object of class 0x8C01. That object's chunk 0x8C2A names the image back in 759 of 762. No file of these versions has an IDML pair, so it is not known whether IDML would write the preview as Contents. The converter treats these images as linked graphics whose link it does not read: no Contents, and the preview goes to Conversion::previews. In files of later versions, 0x8C1B of such an image is 0 or absent in every case.

Not known: why these images keep their file in the preview rather than in a raw data object named by 0x8C23. None of the 77 images whose 0x8C23 names a raw data object has an EPSImage Contents. The one WMF graphic without a link in the pairs has a Contents different from its preview; it is not examined.

Graphic previews

Placed graphics also have chunk 0x170D, the UID of an object of class 0x1708, whose chunk 0x119 names a raw data object. In the 245 distinct little-endian files, these objects are TIFF (613), JPEG (411), PNG (307), GIF (27) and one other. They equal the IDML Contents of embedded links in 38 of 101 and of EPS graphics without a link in 0 of 483, so they are most likely screen previews. The exception is the images of the previous section, whose preview is their file. The package does not include the other previews: IDML has no place for a preview. indd::convert returns the previews of graphics without Contents in Conversion::previews, so an application can show one when the linked file is missing. An image whose Contents is its preview's data is not in that list: the package holds its file.

Embedded data in IDML

The reference IDML files write Contents inside the graphic's Properties as base64 (with = padding) in lines of 76 characters joined by a line feed, with no line feed at the end. The text is split into CDATA sections of 262,144 characters. The converter writes the same form.

Stories (0x201)

Chunk 0x223: u32 length, u16, u32 first strand, UID list of more strands, then other fields. Each strand has chunk 0x261: u16 count, then (u32 length, u32 data object UID) pairs. Each data object has chunk 0x262:

Field Contents
u32 Kind: 0x202 text, 0x203 character style runs, 0x204 paragraph style runs
u32 Owning strand
u16 Run count
runs Each: u32 record size, then the record
u32 Total length

Each record starts with a u32 run length in UTF-16 code units. Text records continue with text segments. Style records continue with the style UID.

Paragraph-style records and paragraph ranges. Counts are over the INDD files of the 1,252 trustworthy pairs and the 37,156 stories that both IDMLs have.

  • Every paragraph-style record ends at a paragraph end (U+000D): 87,496 of 87,496 records.
  • After its text attribute list (attributes.md), a paragraph-style record has a u16 count and that many u32 values. In 82,842 of the 87,496 records they are the lengths of the record's paragraphs, in order, and add up to the run length. In the other 4,654 some values have high bits set (for example 0x10000F74). The converter does not read these values.
  • IDML starts a ParagraphStyleRange at every paragraph-style record, also between neighbouring records with the same style and the same decoded attributes. There are 2,496 such boundaries in 459 stories: 913 between two data objects of the strand and 1,583 within one. 153 of them are between records whose bytes after the run length are identical. Other rules split a record's range further (XML elements, xml.md; tracked changes, below).
  • With one range per record, the text lengths of the non-empty paragraph ranges equal the reference in 37,133 of 37,156 stories, including 455 of the 459 stories with equal neighbours. No story has more ranges than the reference. Merging neighbours with equal formatting matches 36,810 stories. Of the 23 other stories, 3 have different text and 20 have ranges that the reference splits inside one record (unknowns.md, resources and text).
  • Character-style records with the same style and decoded attributes are neighbours only across a data-object boundary: 3,288 boundaries in 533 stories, none within one data object. IDML splits there too. The converter writes a CharacterStyleRange per character-style record (and further cuts), and the character range lengths equal the reference in 525 of these 533 stories and in 37,112 of all 37,156.

Stories outside the document's list. The document's story list does not name the stories of text frames anchored in the XML backing story. IDML writes them like the others and lists them at the end of StoryList: one trustworthy document (in two pairs) has 9 such stories, whose frames are anchored in its backing story; its IDML has all 9 after the listed stories. The converter adds the stories of the text frames anchored in the backing story, and of frames anchored in those stories, after the listed ones, in text order. The order IDML gives them is not that order (it starts with a later one), so StoryList stays different there.

Story settings. Three chunks of the story object (trustworthy pairs, 18,610 stories):

Chunk Layout IDML Without the chunk Evidence
0xA44C flag byte (1 for a built-in key), in-object string Story StoryTitle ($ID/ and the key for flag 1) $ID/ 18,610 of 18,610 (30 with a name)
0x50F96 u16: 1 StoryPreference StoryDirection="RightToLeftDirection" LeftToRightDirection 18,610 of 18,610 (780 right to left, 10 documents)
0x2EE (16 bytes) u16 at 0; f64 at 2; u16 at 10 (not identified); u16 at 12 (1 true); u16 at 14 StoryPreference StoryOrientation (u16 at 0: 0 Horizontal, 1 Vertical), OpticalMarginSize, OpticalMarginAlignment, FrameType (u16 at 14: 0 TextFrameType, 1 FrameGridType) 12 (13 Q where text sizes are in Q, below), false, Horizontal, TextFrameType alignment 18,610 of 18,610; size below; orientation and frame type below

OpticalMarginSize over the 37,156 stories of the 1,252 trustworthy pairs of 2026-10 (DOM 8.1 to 21):

Story Stories IDML OpticalMarginSize
with chunk 0x2EE 3,805 the f64 at 2 (all)
no chunk, TextSizeMeasurementUnits Points 32,979 12 (all)
no chunk, TextSizeMeasurementUnits Q 372 (76 pairs) 9.2125984251969 (13 Q, all)

The Q documents are DOM 12.1, 13, 16.2, 18 and 20.3. The text size unit is the u32 at 12 of preferences chunk 0x1202 (preferences.md, view). The size of new frames in the preferences is not the source: in 3 pairs it differs from the stories without the chunk. Two DOM 8.1 pairs in points have 13 Q in the preferences and 12 in their 13 stories; one DOM 16.2 pair in Q has 12 in the preferences and 13 Q in its 3 stories. The text size unit gives the story value in all three. Another value of the direction or alignment u16 leaves the attribute out.

Orientation and frame type, over the 28,669 stories of all corpus pairs (stale pairs included), with chunk 0x2EE as (u16 at 0, u16 at 14):

Chunk Stories IDML FrameType, StoryOrientation
none 25,206 TextFrameType, Horizontal (all)
(0, 0) 3,359 TextFrameType, Horizontal (all)
(0, 1) 4 FrameGridType, Horizontal (all)
(1, 0) 47 TextFrameType, Vertical (all)
(1, 1) 53 FrameGridType, Vertical (all)

The vertical and frame grid stories are in documents typeset in Japanese (DOM 12, 13 and 18). Another frame type value leaves FrameType out. For another orientation value the converter uses the orientation of the story's frames (text orientation, below).

Frame grids. Over all pairs of the corpus of 2026-10:

  • Chunk 0xCD41 of a text frame's multi-column frame object (class 0x263, the child that the frame's chunk 0x15B lists) is 00 00 for a plain frame (23,537 of 23,537) and starts with u16 1 for a frame grid (248 of 248; 100, 146, 192 or 238 bytes). IDML writes an empty GridDataInformation in the TextFrame for exactly these 248 frames, after Properties, with GridView="GridViewEnum", CharacterCountLocation="BottomAlign" and CharacterCountSize equal to the CharacterCountSize of the document's story grid preference (chunk 0xCD2E, preferences.md): 248 of 248 in 39 documents. The rest of the chunk is not decoded.
  • The stories of these frames are the frame grid stories of chunk 0x2EE (above): 57 of 57. They have chunk 0xCD02 in the story object, with the layout of the page chunk (layout grid, below), and IDML writes a GridDataInformation in the Story, after StoryPreference and before InCopyExportOption, with the same values: 57 of 57 for every attribute. 223 other stories have the chunk but are not frame grid stories, and IDML writes no GridDataInformation for them. One frame grid story in the trustworthy pairs has the IDML element but no chunk.

The converter writes both elements by these rules.

Owned items (run kind 0x209). Each record: u32 run length, u16 count, then that many (u32 class, u32 UID) pairs, the objects owned by the text position at the start of the run. An item anchored in text has the character U+FFFC at that position and is owned through an object of class 0x262, whose chunk 0x2C8 (u32, u32, UID list) lists the anchored page item. IDML writes the page item element in place of the U+FFFC. A text variable instance (class 0xCA64) is owned by a U+0018 at its position; see text-variables.md. Footnotes (class 0x24F) and endnotes (class 0x2805) are owned by a U+0004 (footnotes.md), text and paragraph destinations through class 0x1353C by a U+FEFF (hyperlinks.md).

Text owners. The text-owner strand (run kind 0x2A4, tables.md) gives each stretch of a story's text an owner. In the 495 trustworthy pairs of the research run the owners were the story itself (19,418 stretches), a table (class 0xB608, 11,844), a deleted text (class 0xA40A, 1,889), a footnote (class 0x24F, 502) and a note (class 0xA429, 186). The cell field is 1 for footnotes and 0 for the story, deleted texts and notes. Each footnote, note and deleted-text stretch ends with U+000D (2,577 of 2,577), which IDML does not write, as for a table cell.

Ruby strand (run kind 0x420D). A story can list a strand of class 0x420C (chunk 0x4216: u32 data object, u32 story) whose data objects (class 0x42B9) have chunk 0x262 with run kind 0x420D. The runs cover the whole story text. After the run length a record has u16 1 if attributes follow (0 otherwise), a u16 count and text attribute records (attributes.md). Over the little-endian corpus: 911 stories, 11,514 runs, 7,442 with attributes. The records hold only ruby attributes, a copy of those on the character runs. IDML does not use the copy: all 185 IDML ruby ranges of the pairs have the character run's values, and where the two differ (5 ranges, whose strand string lacks the U+3000 separators; 16 ranges with 0x423E only on the character run) IDML follows the character run. IDs found only in the strand, such as 0x4232 in 6,176 records, are not in IDML. The converter skips this strand.

Notes (class 0xA429). A note is owned by a U+FEFF (186 of 186), and IDML writes a Note element in its place, inside the character range; the Note holds the note's text stretch as paragraph and character ranges. Chunk 0xA412: u32 length n and n UTF-16 units of text segments (the user name), then two FILETIME values (u32 high part, u32 low part; 100 ns since 1601-01-01 UTC), creation and modification, then u16 (0 in all 186). Attributes, in this order:

Attribute Value
Collapsed false in all; the trailing u16 may hold it, but it never varies
CreationDate, ModificationDate the two times as local time, by the link time rule below
UserName the user name; $ID/Unknown User Name when the first document user of that name has flag 2
AppliedDocumentUser dDocumentUser<index hex> of the first document user (document chunk 0xA443) with that name; n if none has it

Check: over all pairs the converter's notes equal the IDML notes on these five attributes in 211 of 211 (compared as multisets per pair, since Note has no Self).

Tracked changes. Deleted text is an object of class 0xA40A, owned by the character that follows the deletion (any character; 1,696 of 1,889 in the research run were U+F035). Its text is the stretch the text-owner strand gives to its UID, without the final U+000D. IDML writes it as <Change ChangeType="DeletedText"> inside the character range of the owning character, before that character and before any element that replaces it, holding the deleted text as paragraph and character ranges (one Change per object: 1,889 of 1,889 in 21 pairs).

A story strand of class 0xA465 has runs of kind 0xA466 that cover the whole story text (positions count characters). Each record: u32 run length, u16 entry count, then per entry a flag byte (0), a string (the user name, in-object form), u16 kind, FILETIME (u32 high part, u32 low part) and u16 (0). Kind 1 is a deletion at the start of the run, with the user and time of that deleted text; kind 2 marks the run's text as inserted, which IDML writes as <Change ChangeType="InsertedText"> around it (2,073 of 2,073 entries, one element each). Records of deleted-text stretches have no entries. Change attributes, in this order: Date, ChangeType, UserName, AppliedDocumentUser, the last two by the rule for notes.

Where IDML puts an inserted-text Change. IDML writes it at the lowest level that holds its whole extent, as for hyperlink sources (hyperlinks.md, extent and placement). The 3,962 Change elements of the 21 trustworthy pairs with tracked changes sit as follows:

Parent Content Elements
CharacterStyleRange inserted text within one range, also across a Br where the range goes on, and empty changes 1,989
CharacterStyleRange deleted text 1,887
CharacterStyleRange a HyperlinkTextSource with the change's extent 43
character-level HyperlinkTextSource inserted text from inside the source to its end 13
ParagraphStyleRange (story or cell) CharacterStyleRange children, and paragraph-level sources inside the extent 23
paragraph-level HyperlinkTextSource CharacterStyleRange children 4
Cell deleted text at the cell's end 2
Story ParagraphStyleRange children 1

So a change over several character ranges of one paragraph range is a child of the ParagraphStyleRange, one over several paragraph ranges a child of the Story, and one over several character ranges inside a paragraph-level source a child of the source. A change with the extent of a source holds it (hyperlinks.md, sources in tracked changes). The ranges are split at the ends of such a change, as at a source.

The converter writes deleted text before the owning character. It writes inserted text that lies in one text run in a Change inside the character range. Inserted text over several runs (once the runs are split at the paragraph-level sources) is written above them: as a child of the paragraph range, or of the story where the runs belong to more than one paragraph range, which then ends and starts again at the change's ends. Inside a lifted change the character ranges have no Change of their own. A table, an anchored item (the schema allows no page item in a Change) or an XML marker in the extent keeps the change inside each character range, opened again after the element; so does a change that does not nest with a paragraph-level source.

Over the 21 trustworthy pairs the output has 3,969 Change elements, and 3,960 of the 3,962 reference elements have an equal one (Date, ChangeType, UserName, compared as multisets per pair). The differences are the 4 changes of the export defect below and a few changes still split. compare.py gains 13 range starts at the ends of lifted changes. Where a hyperlink source starts with inserted text, IDML writes an empty Change before the source (hyperlinks.md, sources at inserted text).

Export defect. In one trustworthy pair, 4 inserted-text changes start inside a paragraph-level source and end after it. IDML writes each inside the source, holding the text past the source's end, and writes text after the source that the INDD stores once. The converter writes the INDD's text once, so this story counts as "story text differs" in compare.py.

A deletion owned by the U+000D that ends a table cell, which no character range holds, is the last child of the Cell, after its last ParagraphStyleRange (2 in one trustworthy pair, 1 in a stale pair; every other deletion of the corpus is owned by a character inside a range). With it the converter writes all 1,889 deleted-text Change elements of the trustworthy pairs.

Dates of notes and changes. IDML writes CreationDate, ModificationDate and Date as local time of the exporting computer, like link times: the converter applies the link time rule below (the offset of the XMP date nearest in day of the year). With it, 211 of 211 notes and 6,024 of 6,027 changes have an equal element in the output; the other 3 are deleted texts, not examined further. The 21 pairs with tracked changes come from at most two computers in one time zone, so the rule is checked on one time zone only.

Index markers (class 0x13006). An index marker is owned by a U+FEFF, which is not text in IDML: IDML writes a PageReference in its place. Its layout and attributes are in index.md.

Anchored object settings (chunk 0x2800). The anchor object (class 0x262), object styles and the preferences have a 62-byte chunk 0x2800:

Offset Contents IDML AnchoredObjectSetting
0 f64 AnchorYoffset
16 f64 AnchorXoffset
32 f64, the negative of the value at 0 in every sample
40 u16: 0 InlinePosition, 1 Anchored, 2 AboveLine AnchoredPosition
42 u16: 1 TextFrame, 2 PageMargins, 3 PageEdge, 4 AnchorLocation HorizontalReferencePoint
44 u16: 2 PageMargins, 3 PageEdge, 4 LineBaseline, 6 Capheight VerticalReferencePoint
46, 50 u16, u16 (below) AnchorPoint
48 u16: 0 RightAlign, 1 CenterAlign, 2 LeftAlign HorizontalAlignment
52 u16: 0 TopAlign, 1 CenterAlign, 2 BottomAlign VerticalAlignment
54 u16: 0 false, 1 true SpineRelative
56 u16: 0 false, 1 true PinPosition

AnchorPoint from the u16 at 46 and at 50: (0, 2) BottomRightAnchor, (2, 2) BottomLeftAnchor, (2, 0) TopLeftAnchor, (0, 0) TopRightAnchor, (2, 1) LeftCenterAnchor. The field at 46 is 0 for a right and 2 for a left point, the one at 50 is 0 for top, 1 for centre and 2 for bottom, as the alignment codes; the converter writes only these five combinations.

Evidence, corpus of 2026-10: the 6,363 object styles whose name matches one IDML style (5,457 in trustworthy pairs), the 1,076 anchored items matched by Self with their IDML element (944 trustworthy; where the item element lacks an attribute, its object style's value), and the 1,295 preference chunks (preferences.md). Every field above matches in every one. Codes seen: AnchoredPosition Anchored in 41 and AboveLine in 37 styles, in 116 and 2 items; SpineRelative true in 2 styles (the only ones with 1 at 54); HorizontalAlignment RightAlign in 24 and CenterAlign in 37 styles. On the items, 42 and 44 are (4, 6) in 4 items, (2, 2) in one, (3, 3) in one and (1, 4) in the others. The two fields change together in every sample, so which one is the horizontal point is assumed from the order of the IDML attributes; codes 2 and 3 mean the same in both.

IDML writes an anchored item's AnchoredObjectSetting by the category rule of other object style settings: every value when the item's object style turns the category off (EnableAnchoredObjectOptions, ID 0xCA2F missing from the style's category list; 670 items, all with every value), and otherwise the values that differ from its object style (406 items, of [None] or of styles with the category on). Where it writes every value, it also writes LockPosition="false" and AnchorSpaceAbove="0", the values of every such element in the corpus (idml-values.md, anchored object settings of page items).

Items inside an anchored item. The children of an anchored group (and the items inside them) have an AnchoredObjectSetting too. IDML applies the rule above to each of them with the anchor's chunk 0x2800 values and the child's own object style: every value where the child's style turns the category off, else the values that differ from that style. With this rule the converter writes 584 more AnchoredObjectSetting elements over the trustworthy pairs of the corpus after 2026-10 (344 on text frames, 114 ovals, 61 rectangles, 30 polygons, 22 graphic lines, 7 groups, 6 text boxes), with every value equal and no extra value; 6,503 values of these elements were missing before, and 388 in 2 or 3 documents per element still are (not examined).

Positions count characters. A text record's run length counts UTF-16 code units, but every other position counts characters, a surrogate pair being one: the lengths in a strand's chunk 0x261 (also for the text strand), and the run lengths of style runs, owned items and text owners. Evidence: the 6 stories of the little-endian corpus whose text has a character outside the Basic Multilingual Plane (emoji, all in one pair). In all 6 the text records add up to the number of UTF-16 units, and the other strands and all chunk 0x261 lengths to the number of characters; with that reading, each emoji gets the character style range IDML gives it (6 of 6). The converter applies the same reading to hyperlink range trees, for which no sample with such a character exists.

U+FEFF characters can be XML markers, which IDML does not write (xml.md).

INDD stores a forced line break as U+000A; IDML writes it as U+2028. The last paragraph return of a story is not written to IDML.

Story links and placed text

Stories placed from another story (linked stories), from a Word or Excel file, and the text frames that linked page items copy, carry the elements below. Evidence base: the 159 distinct corpus pairs whose IDML has any of them (158 little-endian), and for the presence rules all 45,640 stories of the distinct little-endian pairs. No story has an element below without its stored data, and none has the data without the element.

Chunk 0x8CBC is a list of link UIDs: 4 bytes (01 01 00 00), u32 count n, then n UIDs. It occurs on stories (0x201), spline items (0x6201), groups (0x401), graphics, link resources and more; the empty list (8 bytes) is the common case (28,569 spline items). Graphics and movies read the UID at offset 8, the first entry. No object in the corpus has more than one entry.

Story links

A story with a non-empty 0x8CBC list has a Link child in IDML, and Link Self is u and the listed UID in hexadecimal: 47 of 47 stories whose UID is in both files; no story with a link lacks the IDML Link, and none the other way round, over the 45,640 stories.

The link object has the layout of a graphic link (placed graphics, links), with the story's UID at offset 16 of chunk 0x8C9B (47 of 47), and its resource (class 0x8C41) the same chunk 0x8C92:

IDML Equal
LinkResourceURI 45 of 47 (2 links to another document, resolved to another path at export)
LinkResourceFormat ($ID/ and the format name) 47 of 47: Internal Linked Story 28, External Linked Story 2, Microsoft Office Word 2007 Import Filter 17
LinkImportStamp 47 of 47 (a plain number such as 1653409666 for linked stories, file … for Word files)
LinkResourceSize 47 of 47 (0~0 for linked stories, the file size for Word files)
LinkResourceModified, ShowInUI 47 of 47 each
StoredState="Contained" 47 of 47 (resource field 3, placed graphics, link resources)

RenditionData and PDFIdentifier follow the rules of graphic links: present on the 17 version-14 Word links and the 49 version-21.0 links, absent on the 30 version-10 links.

Link object classes (LinkClassID is the class in decimal):

Class LinkClassID Links URI
0x8C42 35906 all graphic links; 17 stories placed from Word file:
0x21D03 138499 30 linked stories idinternalcontent:<id>, idexternalcontent:<path>?<id>
0x21D32 138546 3 linked page items (text frame, group) idinternalSharedArticle:, idexternalSharedArticle:

The converter writes story links. Links of page items (class 0x21D32) are not written: their page item's LinkedPageItemOption was not studied.

idinternalcontent:<id> names the story a link copies by an ID, and that story has LinkResourceId="<id>". A text frame can have one too (the source of a linked page item). The IDs are in chunk 0x21D06 of the document object (UID 1):

Offset Type Contents
0 u32 not identified (non-zero even when the list is empty)
4 u32 count n
8 n × (u32, u32) ID, UID of a story or spline item

IDML writes LinkResourceId="<ID>" (decimal) on the element whose Self is that UID. In 36 of 36 distinct pairs whose IDML has any LinkResourceId, the set of (UID, ID) equals the chunk's list exactly (195 values: 189 Story, 6 TextFrame; 31 trustworthy documents). In the other 1,500 pairs the list is empty. Listed UIDs are stories and spline items, all TextFrame in IDML. IDs are below 32,768. The converter writes the attribute on stories and text frames; a listed UID that is not written is ignored.

Linked story options (chunk 0x21D12)

Chunk 0x21D12 (10 bytes) on a story. IDML writes Story/LinkedStoryOption when the story has the chunk and a link (30 of 30). Two stories with the chunk and no link have no LinkedStoryOption; stories placed from Word have no chunk.

Offset Seen IDML
0–5 00 00 01 00 00 00 in all 30 UpdateWhileSaving="false", WarnOnUpdateOfEditedStory="true", RemoveForcedLineBreaks="false" in all 30 (which byte holds which is not shown; the converter writes these values)
6 u32 ApplyStyleMappings: 1 true (28), 0 false (2)

The preferences object (0x2202) has the same chunk (00 00 01 00 00 00 00 00 00 00 in every document); the document's LinkedStoryOption is written from observed values (idml-values.md).

Style mappings (chunk 0x21D30)

Chunk 0x21D30 holds five lists. Each list: u32 count, then per entry a kind byte (2 or 3), an in-object string (source name), a kind byte (2), an in-object string (destination name) and a u32 rule.

List IDML
1 ParaStyleMapping
2 CharStyleMapping
3–5 empty in every sample (the schema has TableStyleMapping and CellStyleMapping; which list is which is not shown)
Rule MappingRuleType IDML name Seen
0 StyleMappingRule as stored 4
1 GroupMappingRule :* after source and destination 60
2 StyleToGroupMappingRule :* after the destination 30

The kind byte does not add $ID/ (kind 3 is on [Basic Paragraph] under a localized name). Group names may contain / (<group>/<subgroup>), written as stored. Attributes: Self is the owner's Self, then ParaStyleMapping or CharStyleMapping and the index in its list from 0; SourceStyleName, DestinationStyleName, MappingRuleType.

  • Story: a story chunk longer than 20 bytes gives the story's elements (32 of 32 stories; 107 elements equal, Self included). The empty form is 20 zero bytes (75 stories), and no story with it has mappings.
  • Document: chunk 0x21D30 of the preferences object (class 0x2202), in designmap.xml with Self="dParaStyleMapping<i>". Non-empty in 1 of 1,553 documents, the only one with ParaStyleMapping in designmap.xml (2 StyleMappingRule entries, equal). 1,431 documents have the empty chunk, 121 none.

Rule code 3 and entries in lists 3 to 5 are not seen; the converter leaves them out with a warning.

Import options of placed text (chunk 0x12202)

Story chunk 0x12202 is 8 bytes: u32 UID of an import options object, u32 0 (in all). The class of that object decides the Properties child:

Class IDML Stories
0x12210 WordRTFImportPreferences 39 of 39
0x12213 ExcelImportPreferences 9 of 9
UID 0 none 20

Word (class 0x12210). Chunk 0x12210: 19 u32 (s0 … s18). IDML writes a list of 19 items for versions 8 to 12 and 20 for 14 to 20 (no version-13 sample). This mapping reproduces all 39 stories (8 with 19 items, 31 with 20; 10 distinct option sets):

Item (20-item list) Type Value
0, 1 boolean s0 ≠ 0, s1 ≠ 0
2 enumeration s5: 0 PageBreak, 2 None (1 sample)
3 boolean true (no stored field)
4 enumeration UnformattedTable (no stored field)
5, 6 boolean s8 ≠ 0, s9 ≠ 0
7 boolean false (no stored field)
8, 9 enumeration s11, s12: 0 ResolveClashUseExisting, 2 ResolveClashAutoRename (1 sample each)
10 to 13 boolean s14, s15, s16, s17 ≠ 0
14 boolean false, only in the 20-item list (no stored field)
15, 16 boolean true (no stored field)
17 long s4 (1 or 2)
18, 19 boolean false (no stored field)

The 19-item list is the same without item 14. In every sample s0 = s1, s14 = s15 and s16 = s17, so the order within each pair is not shown, and items 0/1, 10/11 and 12 are told apart only by assuming the same stored layout in both list lengths. Code 1 of s5, s11 and s12 is not seen; the converter leaves the property out with a warning for a code not in the table.

Excel (class 0x12213). Chunk 0x12213:

Offset Type Seen IDML item
0 u32 1
4 u32 0
8 u32 3
12 u32 0
16 u32 0 or 1 3: 0 ExcelFormattedTable (5), 1 ExcelUnformattedTable (4)
20 u32 1
24 flag byte, in-object string flag 1, Sheet1 7: $ID/Sheet1
then flag byte, in-object string flag 0, the range (4 distinct values) 8: the range
then flag byte, in-object string flag 1, empty 6: $ID/
then u32 1

The strings are written as names ($ID/ and the string for flag 1). Every sample has the list Spreadsheet (enumeration), 3 (long), false, the table option, true, true, item 6, item 7, item 8, 1 (long). Items 0, 1, 2, 4, 5 and 9 have no identified field: the longs 3 and 1 equal the u32 at 8 and the last u32 in every sample, which does not show that they come from them.

Style mapping preferences (chunk 0x12216)

Story chunk 0x12216: u32 p, u32 c, then 2·p names (paragraph styles: source, destination, …) and 2·c names (character styles), each a flag byte (0 to 3) and an in-object string. When p + c > 0, IDML writes Properties/StyleMappingPreferences: a list of two lists of strings, the paragraph names and the character names (empty when c = 0), as stored (flag 1 does not add $ID/). 67 of 67 stories with the chunk (29 non-empty; p and c up to 13); no story has StyleMappingPreferences without the chunk. The import options come before it in Properties; no story has Excel options together with it.

Element order

In all 107 stories with these elements InDesign writes: Properties (import options, then StyleMappingPreferences), StoryPreference, GridDataInformation, LinkedStoryOption, InCopyExportOption, ParaStyleMapping, CharStyleMapping, Link, then the text. The schema allows this order (Story.rnc). In designmap.xml the document mappings follow the idPkg:Story references.

Plugin data

Stories of 39 version-14.0 documents also carry data of two third-party plugins (DocsFlowImportSettings, the WordsFlow… properties, the Story attributes Observers … ComponentId). The published IDML schema rejects it, and it follows the plugins of the exporting computer; the converter does not write it (unknowns.md, plugin data; docs/measurement.md).

Styles (0x205)

Paragraph and character styles share the class. Chunk 0x230: u32 next style (0 = itself), u32 based-on style, fields not yet identified, u16 1 for paragraph styles or 0 for character styles, u16 Imported (1 = true), u8 1 if the name is a built-in key ($ID/ in IDML), the name as an in-object string, then, in newer files, a GUID string (StyleUniqueId). The name's offset varies (23–26 bytes), so the converter locates it as a flag byte followed by a valid in-object string. All 486 style names and 291 NextStyle values in the pairs match.

Imported and unique ID. Over the 4,694 paragraph and character styles of the trustworthy pairs whose IDML style has the same name, the u16 after the kind equals Imported in 4,694 (180 imported). The GUID is a 36-character in-object string after the name's string; the byte after its string tag is not always 0. Every StyleUniqueId in the corpus IDML files is a GUID of lowercase hexadecimal digits in groups of 8, 4, 4, 4 and 12 (7,953) or $ID/ (4,299), so the converter accepts only that form, searching from the end of the name. A search from the name's own flag byte took a style name of 36 characters for the GUID.

IDML has StyleUniqueId on every paragraph and character style, the root styles included, when the document was saved by 11.2 or later (header or last session of the save history): the stored GUID, or $ID/ for a style without one. Earlier documents have none. Over the trustworthy pairs the converter reproduces 6,313 of 6,316 paragraph and 3,734 of 3,735 character style values. The exceptions are pairs whose IDML was exported by another minor version than the INDD records: four 11.4 documents whose IDML has DOM 11.0 and no StyleUniqueId (34 values written though the IDML has none), and one 11.0 document whose IDML (DOM 11.4) has $ID/ (3 values missing); one paragraph style has another GUID in IDML.

Kind field. The kind and the Imported u16 after it can be read as one u32 in most files, because the second u16 is 0. The InDesign 7.5 template fixture scml-template/scml.indt (no IDML) has 1 there in 600 of its styles: 151 have 00 00 01 00 before the flag and 449 have 01 00 01 00. The 151 are all listed in the tree of the root character style group (chunk 0x28C2 = 0xCA0D, below) and the 449 in the tree of the root paragraph style group, so the kind is the first u16 alone. Read as a u32, the 151 character styles were taken for paragraph styles, which gave ParagraphStyle/… references and a NextStyle that the schema does not allow on a character style. In every other distinct little-endian corpus file the u32 is 0 or 1 (2,125 styles), and the kind agrees with the root group in all of them. In the two big-endian files the u16 kind is also the first two bytes (00 01 for their three paragraph styles, 00 00 for their two character styles).

IDML writes a BasedOn of the root [No paragraph style] or [No character style] as a string ($ID/[No paragraph style]), and any other base as an object reference.

Attribute list (chunk 0x23F). The style's text attributes (attributes.md, text attribute lists). IDML writes on a style exactly the text attributes this list stores. It adds no value from the base style, and it writes a stored value also when it equals the base's. Evidence: the 11,983 paragraph and character styles of the trustworthy pairs that match an INDD style by kind and name. In every one, each stored ID with a known mapping is an attribute of the IDML style, and every IDML text attribute comes from a stored ID, except Label (6 styles) and HyphenQuality (7 styles).

Most lists are short. The root paragraph style stores the full list (287 to 362 IDs, more in later versions). Over all pairs, no other paragraph style stores more than 14 % of its root's list (the most is 41 of 289), and NormalParagraphStyle stores at most 21. The only other styles with a full list are 7 character styles, the same style object in 7 files of one document family (DOM 10.0 and 10.2): each stores 120 IDs, and IDML writes 126 or 128 attributes on them, almost all with the root values. Nothing else in these styles differs from the short-list styles: they have a base (the root character style), Imported is false, and their chunks are the same.

Keyboard shortcuts. Ten bytes before the name's flag byte is a u32 key; the two bytes 6 and 5 before the flag are modifier bytes m0 and m1. Evidence: the 6,957 paragraph and character styles of all pairs whose IDML style has the same name.

Key KeyboardShortcut ExtendedKeyboardShortcut
0 (5,272 styles) 0 0 0 0 0
0xC000xx, xx a digit 0–9 m0 + 256 × m1 and the code below 0 0 0
0x8000xx 0 0 m0 + 256 × m1, xx, then 1

The 103 styles with a key other than 0 are in 38 files. With key 0x8000xx, xx is a character code: over all pairs, the 21 styles of 11 trustworthy pairs with such a key and DOM 15 or later (codes 49 to 52, 66 and 73; modifiers 1, 17, 256 and 257) have this ExtendedKeyboardShortcut in IDML, for example 256 49 1 for m0 0, m1 1 and code 0x31.

The key code follows the platform of the last session of the save history (the second u16 of its record), not the style: with platform 0 digits 0 to 7 give 82 to 89, 8 gives 91 and 9 gives 92 (every digit occurs); with platform 3 the code is 96 + the digit. This is a rule of the exporting edition (preferences.md): over the trustworthy pairs of the corpus of 2026-10 it reproduces KeyboardShortcut for 3,154 of 3,154 character styles and 6,927 of 6,928 paragraph styles (a rule by m1 failed for 26 character and 33 paragraph styles with m1 0 and platform 3). The converter writes the attribute on every style other than the root styles. IDML has ExtendedKeyboardShortcut from DOM 15 on; the converter writes it from version 15.

Preview colour. Fourteen bytes before the name's flag byte is a u32: 0, or the UID of an interface colour (class 0x1F11). IDML writes it as the style's PreviewColor property: Nothing for 0, otherwise the colour named as for layers. Over all pairs of the corpus after 2026-10 (styles other than the root styles, matched by name): 8,457 of 8,457 paragraph styles and 3,638 of 3,638 character styles. Two character styles of one document (two pairs) have a colour: UID 0x20, RGB 0.5 0.5 0.5, Gray, and UID 0x35, RGB 0.48 0.73 0.85, GridBlue. The root styles have no PreviewColor in IDML. The converter leaves the property to the observed values when the u32 is neither 0 nor an interface colour.

Export settings (chunk 0x28F0). A u32 count of export tag maps, the maps, then u16 values to the end of the chunk:

Field Contents
u32 number of tag maps n
n maps export type, tag, class (three strings), u32 attribute count k, k pairs of strings
u16 SplitDocument (1 true, 0 false)
u16 EmitCss
u16 IncludeClass (DOM 13 on)
u16 … more values in later versions, not identified

A string is a u32 length in UTF-16 units followed by text segments (as the font version, fonts.md); an empty string is a length of 0. Export types are EPUB and PDF; tags such as p or H3 and classes may be empty. No map in the corpus has attributes, so the layout of the pairs is assumed and the converter writes no map that has them. The chunks of every paragraph, character and object style of all pairs parse.

IDML has SplitDocument and EmitCss when the document was saved by 10.1 or later, and IncludeClass from 13.0 (header or last session of the save history), on every paragraph and character style, the root styles included. Without the chunk the values are false, true, true. The trustworthy pairs include four whose INDD header says 10.0 and whose IDML (DOM 10.2) has the attributes, and six of 10.0 whose IDML (DOM 10.0) has none. Over the trustworthy pairs the converter reproduces SplitDocument and EmitCss of 7,287 of 7,287 paragraph styles and 4,067 of 4,067 character styles, and IncludeClass of 5,760 and 3,500, with no extra value.

Tag maps. IDML writes one StyleExportTagMap per map after the style's Properties, in stored order: Self="u<style UID in hex>StyleExportTagMapn<type>", ExportType, ExportTag, ExportClass, ExportAttributes="", and the style's SplitDocument and EmitCss. 306 of 306 elements in the trustworthy pairs, every attribute equal.

Empty nested, line and GREP styles. Paragraph styles have EmptyNestedStyles, EmptyLineStyles and EmptyGrepStyles (DOM 8.1, and 10 on). Each is false when the style's list of nested styles (attribute 0x1B75), line styles (0x1BBB) or GREP styles (0x1BBA) has items, where the list is that of the first style in the based-on chain that has the attribute; an empty list is stored as a count of 0. This gives the IDML value of 5,401 of 5,403 paragraph styles for each of the three (all pairs; the other 2 are not written).

Style groups and object styles

Root groups (class 0xCA8C for paragraph and character styles, 0x1B972 object styles, 0x20241 cell styles, 0x1044F table styles) are named in IDML by UID (RootParagraphStyleGroup Self="u7e"). Chunk 0x28C2 says which kind: 0xCA0C paragraph, 0xCA0D character, 0x1B924 object, 0xB669 cell, 0xB668 table (all 75 pairs). Children: chunk 0x28DC (text styles) or 0x1B95A (object styles), each u32, u32, UID list. A built-in root style such as [No character style] need not be listed.

Groups (class 0xCA8B): chunk 0x28D3 is parent, root, UID list of children; chunk 0x28D2 a flag byte and the name. IDML names every group $ID/<name> (20 of 21 groups), and a style inside groups is referenced as ParagraphStyle/<group>:<group>:<name> with : escaped as %3a. All 412 paragraph styles and 21 groups in the pairs match. A group inside another group is named by its full path from the top-level group, joined by :, as in its Self: Self="ParagraphStyleGroup/$ID/Page > Running Text%3aNotes" has Name="$ID/Page > Running Text:Notes". Over all pairs: 72 of 72 nested paragraph style groups, 25 of 25 character style groups and 2 of 2 object style groups (three levels at most); top-level groups have $ID/ and their name (622 of 622). A : inside a group's name is written \:, as in a style's own name (below): such a group has Name="$ID/<a>\: <b>" and Self="ParagraphStyleGroup/$ID/<a>\%3a <b>", and its styles have Name="<a>\: <b>:<style>". No pair of the corpus has such a group; this rests on one privately held sample (1 top-level paragraph style group with 6 paragraph styles, all matching). Cell style groups work the same way: the root cell style group's children (chunk 0x2024E) include groups of class 0xCA8B, and IDML writes each as <CellStyleGroup Self="CellStyleGroup/$ID/<group>" Name="$ID/<group>"> holding its styles, in the order of the children (2 groups with 6 cell styles in 1 trustworthy DOM 18 pair). No table style group occurs in the pairs; the converter writes them the same way.

Style names. Over the styles of the 489 trustworthy pairs, a style's IDML Name is its group path and its own name joined by : (1,170 paragraph, 759 character, 8 object and 6 cell styles in groups, such as Name="Listes:Liste non numérotée"), and its Self is the tag and that name with % written %25, : written %3a and CR written %0d. Two more rules:

  • A : inside a style's own name is written \: in Name, so \%3a in Self: Name="ss01\: People", Self="CharacterStyle/ss01\%3a People" (12 paragraph, 6 character and 3 object styles).
  • A built-in style inside a group has $ID/ before the whole path: ParagraphStyle/$ID/INDEX%3aIndex Section Head with Name="$ID/INDEX:Index Section Head" (one paragraph and one character style).

The same holds for object styles and cell styles in groups (ObjectStyle/Worksheet%3aworksheet, CellStyle/Standard Table%3aHeader Row). Elsewhere %3a stays plain: languages are Language/$ID/English%3a USA.

Object styles (class 0x1B901): chunk 0x1B907 is u32 based-on style, u8 1 for a built-in name, then the name. A page item's chunk 0x1B916 is its applied object style (AppliedObjectStyle, 671/671 rectangles). A style based on the root [None] has its BasedOn written as a string.

Object style settings

Object styles (class 0x1B901) hold their settings in these chunks. Evidence: the 337 object styles of the same-version pairs whose name matches an IDML ObjectStyle (259 of them other than [None]); all counts are matches of 337 unless stated.

Chunk Contents IDML
0x1B92B Attribute list, u16 count, page item records (attributes.md) FillColor, StrokeColor, StrokeWeight, StrokeType, CornerOption, CornerRadius, GradientFillAngle (0x551E), GradientStrokeAngle (0x5524)
0x1B956 Attribute list, frame fitting (see frame fitting) FrameFittingOption
0x1B924 Text frame settings (below) TextFramePreference, TextFrameFootnoteOptionsObject
0x285B u16 story orientation at 0, f64 at 2, u16 at 12, u16 frame type at 14 StoryPreference (OpticalMarginSize from the f64, OpticalMarginAlignment from the u16 at 12: 0 false, 1 true)
0x50F28 u16 story direction StoryPreference/StoryDirection
0x3776, 0x3777 Text wrap, as chunks 0x3703 and 0x373D of page items TextWrapPreference
0x1B92E u32 count, IDs of the categories the style turns on Enable… attributes (below)
0x1B946 u32 paragraph style, 0 = none AppliedParagraphStyle (n for none, and for a style without the chunk: 5,556 of 5,556 values of the trustworthy pairs of the corpus after 2026-10, 173 of them without the chunk)
0x1E244 78 bytes: six f64 at 30 FlexLayoutAttributeOption FlexPaddingTop, FlexPaddingRight, FlexPaddingBottom, FlexPaddingLeft, FlexGapRow, FlexGapColumn; without the chunk 12, 12, 12, 12, 20, 20 (below)
0xCD32 u16 0 for none, or u16 1 and the UID of a named grid AppliedNamedGrid (named grids, above)
0x1B94D u16, 1 = true ApplyNextParagraphStyle (below)
0x2800 Anchored object settings, as in the preferences AnchoredObjectSetting (below)
0x1B907 u32 based-on style, flag byte and name, u32 shortcut key BasedOn, Name, KeyboardShortcut (below)
0x1E234 52 bytes: u16 flags at 8, 10, 12 and 14, f64 at 16, 24, 32 and 40 TransformAttributeOption: TransformAttrX, TransformAttrY, TransformAttrHeight and TransformAttrWidth, each written when its flag is 1 (below)

Flex layout spacing. In chunk 0x1E244 the six f64 at 30 are the four paddings and the two gaps. A style without the chunk ([None] included) has 12 for each padding and 20 for each gap. With this the converter reproduces all 226 values of each of the six attributes in the trustworthy pairs (none was written before). The four paddings are equal in every sample, as are the two gaps, so the order inside each group follows the IDML attribute order and is not proven.

Settings found in the corpus after 2026-10. Object styles other than [None], matched by Self with their IDML style over the 1,251 trustworthy pairs (4,305 styles; with [None], 5,556):

Field IDML Matches
0x1B94D u16: 0 false, 1 true; no chunk false ApplyNextParagraphStyle 3,963 with 0, 3 with 1, 339 without the chunk; [None] has no attribute
0x1B907, u32 after the name: 0 KeyboardShortcut="0 0" every style with 0 (other keys are followed by two modifier bytes as for paragraph styles, but their codes differ from those of paragraph styles; the converter leaves them out)
0x3776 (44 bytes) u16 at 40: 1 false, 0 true; no chunk false TextWrapPreference ApplyToMasterPageOnly 3,914, 84 and 1,558 of 5,556
0x1B924 u16 at 140, 1 = true (142 bytes or more) TextFramePreference UseNoLineBreaksForAutoSizing 5,518 of 5,518 (24 true)
0x2800 f64 at 16 AnchoredObjectSetting AnchorXoffset 5,551 of 5,551 (28 not 0); 5 styles have no chunk
0x2800 u16 at 42: 1 TextFrame, 4 AnchorLocation AnchoredObjectSetting HorizontalReferencePoint 5,547 and 4

The converter reads the anchor fields wherever it reads chunk 0x2800: object styles, anchored frames and the preferences.

Attribute list. The IDs of page items carry over. CornerOption 0 is None and 0x5A16 InverseRoundedCorner (1 style). The two gradient angles are told apart by one style with −90 and 0. Each corner radius and corner option has its own ID, as in page items (attributes.md, corners), and the converter writes each corner from its ID.

Overprint. The attribute list holds the overprint flags of the fill (0x6E6A), the stroke (0x6E67) and the gap (0x6E8B), u16 1 true, 0 false. IDML writes OverprintFill only when the fill colour (0x6E68) puts ink on the page: it is not the swatch None or Paper, its tint (0x6E69) is not 0, and it is not a white process colour (CMYK 0 0 0 0, or RGB 255 255 255). The same holds for OverprintStroke with 0x6E64 and 0x6E66, and OverprintGap with 0x6E89 and 0x6E8A. The root [None] has none of the three. Documents saved by 21.4 or later (12 trustworthy pairs of 21.4 and 21.5) have all three on every object style, the root included, whatever the colours. Over the trustworthy pairs the converter reproduces 235 of 235 OverprintFill, 1,512 of 1,512 OverprintStroke and 49 of 49 OverprintGap values with no extra value. The white RGB case rests on 2 styles of two pairs of one 13.1 document (89 other RGB fills and strokes are written). Every object style flag in the corpus is 0. Page items use the same IDs (page item settings, overprint).

Export settings (chunk 0x28F0). Object styles have the chunk of paragraph and character styles (styles, export settings). IDML writes EmitCss (the second u16) for documents saved by 10.1 and IncludeClass (the third) for documents saved by 13.0, the root [None] included; there is no SplitDocument. Without the chunk both are true. Trustworthy pairs: EmitCss 5,031 of 5,031, IncludeClass 4,019 of 4,019 (every value is true). One 12.1 document has an object style tag map (ObjectStyleExportTagMap); it is not written.

ARIA label. From DOM 21.2 every ObjectStyle, [None] included, has EpubAriaLabel="" and EpubAriaLabelSourceType="NoneARIALabel", after EpubAriaRole: 178 of 178 styles in the 44 corpus IDML files of DOM 21.2 to 21.5. The 60 styles of the 15 files of DOM 21.1 have neither, nor does any style of an earlier DOM. No value varies, so no INDD field is identified; the converter writes both on every object style from DOM 21.2. They are attributes of the style. Its ObjectExportOption has EpubAriaLabel="$ID/" and EpubAriaLabelSourceType="AutomaticARIALabel" from DOM 21.1, as page items do (idml-values.md, export options of page items).

Optical margin (chunk 0x285B). The f64 at 2 is OpticalMarginSize and the u16 at 12 OpticalMarginAlignment (1 = true), as in the story chunk 0x2EE (stories). Over all pairs of the corpus of 2026-10, both match in 3,515 of 3,515 object styles (2,661 of 2,661 in the trustworthy pairs). The IDML sizes are 12 (3,172 styles), 9.2126 (336), 8 (4) and 9.9213 (3); 4 styles have OpticalMarginAlignment="true". The u16 at 10 is not identified.

Text frame settings (chunk 0x1B924). 222 bytes; 162, 142 or 106 in files from older versions (942, 48, 66 and 61 object styles in the little-endian corpus). The converter reads it only with these sizes. The InDesign 4.0 file has 104 bytes, with another layout; the converter leaves it out with a warning (big-endian.md). In the corpus after 2026-10, 1,129 object styles in 263 files of InDesign 4.0 to 6.0 have 104 bytes; none of these files has an IDML, so the layout cannot be checked.

Offset Contents Attribute
0 f64 TextColumnFixedWidth
8 f64 TextColumnGutter
32 u16, 1 = true VerticalBalanceColumns
34, 42, 50, 58 four f64, inset spacing InsetSpacing (below)
66 u32 TextColumnCount
70 u16, 1 = true UseFixedColumnWidth
74 u16, codes as for frames VerticalJustification
76 u16, codes as for frames, and 4 XHeight FirstBaselineOffset
116 u16, codes as for frames AutoSizingType
118 u16, codes as for frames AutoSizingReferencePoint
120, 122 u16 1 = true, f64 UseMinimumHeightForAutoSizing, MinimumHeightForAutoSizing
130, 132 u16 1 = true, f64 UseMinimumWidthForAutoSizing, MinimumWidthForAutoSizing
144 u16, 1 = true FootnotesSpanAcrossColumns, SpanFootnotesAcross
146 f64 FootnotesMinimumSpacing, MinimumSpacingOption
154 f64 FootnotesSpaceBetween, SpaceBetweenFootnotes
190 f64 ColumnRuleStrokeWidth
198 u32 swatch, 0 = n ColumnRuleStrokeColor
210 f64 ColumnRuleStrokeTint

The fields from offset 32 to 132 were found by testing every offset against the IDML style, over the 2,155 object styles of the trustworthy pairs that match an IDML style by name (1,000 with 222 bytes, 607 with 142 and 520 with 162). Each is the only offset that matches all styles of the 222- and 142-byte layouts:

Offset Values seen (222 / 142 bytes)
32 1 true in each layout, all match
70 142: 1 true; 222: all false
74 222: 4 CenterAlign; 142: 3 CenterAlign, 2 BottomAlign
76 222: 952 AscentOffset, 42 EmboxHeight, 6 XHeight; 142: 584, 1 and 22; 162: 516 AscentOffset, 4 EmboxHeight
116 3 distinct values in each layout
118 142: 5 distinct values
120, 122 142: 6 true, 6 distinct heights
130, 132 142: 2 true, 3 distinct widths

In the 162-byte layout the justification and auto-sizing fields have one value in every style, and in the 106-byte layout (28 styles) every field but offset 76 does; the converter assumes the offsets of the larger layouts for 162 bytes and reads only offset 76 from 106 bytes. IgnoreWrap, MinimumFirstBaselineOffset, VerticalThreshold, UseFlexibleColumnWidth, TextColumnMaxWidth and UseNoLineBreaksForAutoSizing have one value in every style (false or 0), so no field can be shown for them; the converter writes the observed value (idml-values.md). Code 4 of FirstBaselineOffset is shown only in styles; the converter reads it in frames too.

Footnote and column rule values: 305 of 305 styles whose chunk has them. The column rule colour maps one to one over 41 (file, UID) pairs. Only one style (3 copies) has unequal insets, and it shows only the top inset (offset 50), so the converter writes InsetSpacing only when all four are equal (334 of 337).

Story settings. Frame type: 0 Unknown, 1 TextFrameType, 2 FrameGridType. Orientation: 0 Unknown, 1 Horizontal. Direction: 1 LeftToRightDirection, 0 or no chunk UnknownDirection. 337 of 337 each. The f64 at 2 is 12 in every style, like OpticalMarginSize, and is not used.

Text wrap. 234 styles have chunk 0x3776 with mode 0, offsets 0 and the u32 at 40 = 1, and chunk 0x3777 type 5: IDML None with ContourType="SameAsClipping". 103 styles have neither chunk and IDML None. Chunk 0x3777 is the contour with the layout of chunk 0x373D (text wrap, contour). In the trustworthy pairs of the corpus of 2026-10, 3,965 object styles have it: 3,964 with type 5 and one with type 0, whose IDML style is the only one with ContourType="BoundingBox". Every other IDML object style, with or without the chunk, has SameAsClipping (5,555 of 5,556 styles), so a style without the chunk takes type 5. ContourPathName is $ID/ in every ContourOption of the object styles of the corpus pairs (7,423 of 7,423, DOM 7 to 21).

Categories (chunk 0x1B92E). An ID in the list means the attribute is true. Over the 1,684 object styles other than [None] of the trustworthy pairs whose name matches an IDML style (fewer for attributes that IDML has only from a later version), each attribute below equals the presence of its ID in every style:

ID Attribute From DOM
0x1B933 EnableFill 7
0x1B934 EnableStroke 7
0x1B935, 0x1B936 EnableStrokeAndCornerOptions 7
0x1B93E EnableTextFrameGeneralOptions 7
0xADC8 EnableTextFrameBaselineOptions 7
0xADC9 EnableTextFrameAutoSizingOptions 8
0x1B940 EnableStoryOptions 7
0x1B960 EnableFrameFittingOptions 7
0x1B93F EnableParagraphStyle 7
0xADCB EnableTextFrameColumnRuleOptions 15.1
0xCA2F EnableAnchoredObjectOptions 7
0x1B942, 0x37C8, 0x37C9 EnableTextWrapAndOthers 7
0xADCA EnableTextFrameFootnoteOptions 12
0x6EA1 to 0x6EA7 EnableTransformAttributes 13
0x1B97A, 0x1B97C to 0x1B97E EnableExportTagging, EnableObjectExportAltTextOptions, EnableObjectExportEpubOptions, EnableObjectExportTaggedPdfOptions 9
0x1B937 EnableTransparency of ObjectStyleObjectEffectsCategorySettings 7
0x1B948, 0x1B950, 0x1B958 EnableTransparency of the fill, stroke and content effects categories 7

Where a row has several IDs, they are all present or all absent in every style, so the corpus does not tell which one the attribute follows; the converter writes the attribute only when they agree.

The transparency categories do not change which transparency values IDML writes on a style (transparency.md, object styles).

Versions are those of the INDD header, major and minor. Over the 489 trustworthy pairs: EnableTextFrameColumnRuleOptions is on no style in the 42 documents of 15.0 (four builds), and on every style in the 7 of 15.1 and on all later ones. The footnote values of the text frame settings (FootnotesSpanAcrossColumns, FootnotesMinimumSpacing, FootnotesSpaceBetween of TextFramePreference) are on no style of DOM 12 (127 styles) or 13.0 (12 styles), and on every style from 13.1.

The root style [None] has none of the Enable… attributes and none of the four ObjectStyle…EffectsCategorySettings elements in 489 of 489 trustworthy references, though its INDD object has the category list. The converter still reads the list: the text frames that use [None] depend on it (text frame preferences). The four export attributes are equal in every style (84 true, 1,358 false). With the 88 pairs of the earlier corpus, fill and stroke, and the general and baseline frame options, were not told apart; the larger corpus has styles that differ in them (10 without fill, 13 without stroke, 506 without general options and 531 without baseline options).

Anchored object settings are in chunk 0x2800, as for anchors (see stories). A style without the chunk (6 styles of versions 10.1 and 10.2) has the values of preferences without it (preferences.md, anchored objects). The other values of object styles come from IDML observation (idml-values.md).

Transform attributes (chunk 0x1E234). Over the 1,251 trustworthy pairs after 2026-10, 2,426 object styles have the chunk, 52 bytes each. The u16 at 8, 10, 12 and 14 are 1 exactly where IDML writes TransformAttrX, TransformAttrY, TransformAttrHeight and TransformAttrWidth, and the f64 at 16, 24, 32 and 40 are their values: 3 of 3 X, 1 of 1 Y, 11 of 11 height and 30 of 30 width values (36 styles; 2,390 styles have all four flags 0 and no such attribute, though many store values other than 0). Bytes 0–7 and 48–51 are 0 in every chunk. IDML has the element from DOM 13 (idml-values.md); the converter writes the values the style sets into it.

Master spread names and sections

Master spread chunk 0x1402: a flag byte and the name prefix (A), a flag byte and the base name (Master). IDML Name is <prefix>-<base>, and the master's pages are named by the prefix (99/99 match).

Sections (class 0x4C01). The document's chunk 0x4C01 lists them. Section chunk 0x4C02:

Field Contents
u8, string SectionPrefix
u8, string Marker
u32 First page of the section; 0 for the section that starts at the document's first page
u32 Page number start (PageNumberStart)
u32 Page number style: 0x4C15 = Arabic, 0x4C17 = LowerRoman, 0x4C12 = Kanji, 0x4C13 = DoubleLeadingZeros, 0x4C16 = UpperRoman, 0x4C19 = LowerLetters, 0x4C1A = SingleLeadingZeros (below)
u32 Continue numbering (1 = true, ContinueNumbering)
u16 0 in every chunk
u16 Include section prefix (1 = true, IncludeSectionPrefix)
u8 flag, string AlternateLayout: the string, with $ID/ before it if the flag is 1

In the 546 sections of the trustworthy pairs, 539 chunks have all these fields; the prefix, marker and alternate layout equal the IDML values in 539 of 539 (417 named layouts such as Letter V, 82 empty, 40 $ID/). The 7 shorter chunks are in DOM 7 and 8 files and end after the second u32 above.

Include section prefix. Over the 1,345 sections of the 1,252 trustworthy pairs after 2026-10, 1,336 chunks have the u16 pair after continue numbering. The first u16 is 0 in all of them. The second is 1 in all 11 sections with IDML IncludeSectionPrefix="true" (10 distinct files) and 0 in all 1,325 with false. The other 9 chunks, one each in 9 DOM 7 files, end before the field; IDML gives them false.

Section name. IDML Name equals SectionPrefix in all 1,345 sections: 15 sections in 14 distinct files have a prefix, and 1,330 have an empty prefix and an empty name. The prefix does not depend on IncludeSectionPrefix (9 of the 15 include it, 6 do not).

Alternate layouts. A section with a layout name (not empty and not $ID/) starts an alternate layout, and so does the first section. AlternateLayoutLength of a section is the number of pages from its first page to the start of the next layout, or to the end of the document (538 of 539). The AppliedAlternateLayout of a document page is the section that starts its layout; master pages have n. Both are in IDML from DOM 8 on. Over the trustworthy pairs the converted AppliedAlternateLayout equals the IDML value for 9,347 of 9,347 pages.

Page descriptor. A document page has a Descriptor property, a list of the section prefix, the page number style, ContinueNumbering, IncludeSectionPrefix, the page number and the marker; from DOM 20 on the page number is in the list twice. Over the trustworthy pairs: 7,800 of 7,924 pages; 64 others are in sections with a style the converter does not know (IDML gives it as an empty string), and the converter leaves their descriptor out.

In the descriptor, a return (U+000D) in the marker is a paragraph separator (U+2029); the section's Marker attribute keeps the return. Over the 15,855 pages of the trustworthy pairs after 2026-10, 568 pages (6 distinct files) are in sections whose marker ends with a return, and their descriptors end with U+2029 in its place (568 of 568). No marker has a return elsewhere. 1,080 pages have a marker without a return, which the descriptor repeats as it is, and 14,207 have an empty marker.

Evidence:

  • In every corpus pair the first section's IDML PageStart is the document's first page, and its first-page field is 0. All but one pair have one section; one has four. All 79 sections that the converter writes match on PageStart, Length, ContinueNumbering and, where IDML writes it, PageNumberStart. IDML writes PageNumberStart only for sections with ContinueNumbering="false" (14 of 14); a continuing section can store a start number that IDML leaves out.
  • 84 distinct INDD files without an IDML have more than one section (254 sections). The first section listed has first page 0 in all 84. Each of the other 170 names a page of the document (170 of 170). The list is not always in page order, so the converter sorts sections by their first page. A section ends where the next one starts; that gives IDML Length.
  • The style is 0x4C15 in all 423 sections of the 250 distinct little-endian files, and those in the pairs are Arabic. The InDesign 3.0 file stores 0x4C06 (big-endian.md).
  • Style 0x4C17 is lower-case Roman. No pair has it. The evidence is a sample and its print PDF. The PDF's page labels (/PageLabels in the document catalog) give the pages of the sample's 0x4C17 sections style /r, lower-case Roman, and the pages of its 0x4C15 section style /D, decimal.
  • Style 0x4C12 has no pair either. The evidence is a sample typeset vertically and its print PDF. The folios on the pages of its 0x4C12 section are Chinese numerals written digit by digit (〇 一 二 … 九, so 10 is 一〇 and 100 is 一〇〇), counting from the section's start number. The PDF's page labels belong to a larger document and do not show the style. Kanji is the only value of the schema's PageNumberStyle enumeration that uses such numerals.

Pairs of the corpus after 2026-10 show four more codes. Over every valid distinct file, each section whose code the converter did not know was matched with the IDML Section of the same UID:

Code IDML PageNumberStyle Sections with an IDML section Sections without
0x4C1A SingleLeadingZeros 51 30
0x4C13 DoubleLeadingZeros 21 3
0x4C19 LowerLetters 14 2
0x4C16 UpperRoman 3 10

No section has another value for these codes. In the Descriptor of a page, whose second item is the section's style, IDML writes a page of a SingleLeadingZeros section with a string there, the section prefix again: 1,249 descriptors in the IDML files of the corpus (1,223 with an empty prefix), none with the enumeration value. 0x4C18 (one section) and 0x4C06 (InDesign 2.0 and 3.0 files) occur only in files without IDML. The converter writes PageNumberStyle for the seven codes and leaves it out (with a warning) for other codes.

The converter names document pages by their number in their section, counting on from the previous section when numbering continues. The section at the document's first page starts at its page number start even when it continues numbering: the document continues the numbering of a book. Over the 1,252 trustworthy pairs after 2026-10, the IDML page number of the first page equals that field in 1,252 of 1,252, including 18 documents (18 distinct files) whose first section continues numbering from a start above 1. The 49 later sections that continue numbering count on from the previous section (49 of 49), though 41 store another start. In a section with IncludeSectionPrefix, the page name is the section prefix followed by the number: 2-1, 2-2 for prefix 2-, and 1장_01 for a prefix 1장_ and style 0x4C1A. After these rules, page names and descriptors equal the IDML values on 15,855 of 15,855 pages of those pairs. In a section with style 0x4C17 it writes the number in lower-case Roman (i, ii, iii), as in the PDF labels above, and in a section with style 0x4C12 in Chinese digits, as the folios show. No pair shows IDML page names in such sections. It writes upper-case Roman numerals for 0x4C16, two and three digits with leading zeros for 0x4C1A and 0x4C13, and the letters a to z for 0x4C19 (later numbers as Arabic numbers); the page names of the pairs above measure these.

Document preferences (class 0x2202)

One object of class 0x2202 holds document-wide preferences. Chunk 0x533 (DocumentPreference): f64 page width at 0, f64 page height at 8, byte 58 2 for facing pages and 1 otherwise, four f64 bleeds from offset 70 (inside, top, outside, bottom; preferences.md), u32 intent at 142 (0 print, 1 web, 2 mobile). All values match the 75 pairs. Files from InDesign 7.0 and 7.5 have a 126-byte chunk with the fields at other offsets (preferences.md, document setup). Files from InDesign 3.0 and 4.0 have a 118-byte chunk with another layout; the converter leaves it out with a warning (big-endian.md).

Page binding (u16 at 64). 0 is PageBinding="LeftToRight", 1 RightToLeft. Evidence:

  • The u16 is 0 in all 247 distinct little-endian public files that have the 146-byte chunk. All 88 distinct corpus IDML files have PageBinding="LeftToRight", and in all 73 two-page spreads and master spreads of those files the first page lies left of the second.
  • A sample typeset vertically, whose print PDF shows columns ordered right to left, stores 1. In each of its two-page spreads and master spreads the first page lies right of the second: the book is bound on the right. The schema's other value, Default, has no sample.

The converter writes PageBinding from this field and leaves it out, with a warning, for other codes. Pages are written in the order the spread lists them, for both bindings.

Text frame preferences

From the frame's multi-column frame object (class 0x263):

Chunk Offset TextFramePreference attribute
0x2D1 u32 0 TextColumnCount (1,052/1,052)
0x2D1 f64 4 TextColumnGutter (93/93)
0x2D1 f64 14 TextColumnFixedWidth (1,045/1,045)
0x2CE u16 0 FirstBaselineOffset: 0 LeadingOffset, 1 AscentOffset, 2 CapHeight, 3 EmboxHeight, 4 XHeight (below)
0x2CE u16 2 VerticalJustification: 0 Top, 1 Center, 2 Bottom, 3 Justify (350/350)
0x2CE u16 20 VerticalBalanceColumns (18/18)
0x2CE u16 22 AutoSizingType: 0 Off, 1 HeightOnly, 2 WidthOnly, 3 HeightAndWidth (61/61)
0x2CE u16 24 AutoSizingReferencePoint: 0–8, top-left to bottom-right by rows (58/58)
0x2CE u16 26, f64 28 UseMinimumHeightForAutoSizing, MinimumHeightForAutoSizing
0x2CE u16 36, f64 38 UseMinimumWidthForAutoSizing, MinimumWidthForAutoSizing
0x2CE u16 46 UseNoLineBreaksForAutoSizing
0x2D1 u8 12 UseFixedColumnWidth
0x2D1 f64 32 TextColumnMaxWidth (in 40-byte chunks)
0x3730 u16 IgnoreWrap
0x22646 u32 0 ColumnRuleOverride: 1 true, 0 false (below)
0x22646 f64 28, u32 36 ColumnRuleStrokeWidth, ColumnRuleStrokeColor (a swatch; 0 = n)
0x22608 u16 2, f64 4, f64 12 FootnotesSpanAcrossColumns (1 = true), FootnotesMinimumSpacing, FootnotesSpaceBetween
0x2834 24 bytes BaselineFrameGridOption (below)

Span of footnotes. The u16 at 2 of chunk 0x22608 is FootnotesSpanAcrossColumns. Before 2026-10, 2,655 frames with 0 have false in IDML; the 22 frames with 1 (8 documents) all have an object style with span true and the footnote category on, and IDML leaves the attribute out, as for any value equal to the style's. Writing it from the chunk removes the 82 extra FootnotesSpanAcrossColumns values of the trustworthy pairs after 2026-10 and adds no wrong value.

Frames without chunk 0x2CE, and the 22-byte chunk. Frames of InDesign 14.0 and 15.0 can lack chunk 0x2CE (517 frames in 24 documents before 2026-10). Their IDML has FirstBaselineOffset="LeadingOffset" on all 517, although their styles have AscentOffset; where IDML writes the other values they are TopAlign, false, Off, CenterPoint, minimums off and 0, and no line breaks off. These are codes 0, reference point 4 and no minimums. InDesign 7.0 frames can have a 22-byte chunk 0x2CE (125 frames, 4 documents): offsets 0, 2 and 20 are as in the longer chunk (11 of 11, 11 of 11 and 13 of 13 values); it has no auto-sizing fields, and DOM 7 IDML has no auto-sizing attributes. The converter writes these frames' TextFramePreference with those values: over the trustworthy pairs after 2026-10, 670 more elements, with no wrong or extra value (FirstBaselineOffset 2,731 of 2,731, AutoSizingType 16,202 of 16,202).

The frame itself (class 0x6201) holds the inset spacing in chunk 0x3723 (44 bytes): f64, u32, then four f64 (left, top, right, bottom). IDML writes InsetSpacing as a list of top, left, bottom and right, or as the f64 at offset 0 (below). A frame without the chunk has 0 for all five.

Evidence over the text frames of the trustworthy pairs that the converter writes (TextFramePreference values reproduced): the auto-sizing minimums and their flags 4,069 to 4,071 of 4,069 to 4,071 each (5 frames with 108 pt minimums, 4 without line breaks), UseFixedColumnWidth 747 of 747 (9 true), TextColumnMaxWidth 23,043 of 23,043 (one frame with 210.24; the 30-byte chunks of DOM 7 files have no such field and their IDML no such attribute), IgnoreWrap 643 of the 817 frames that have it (74 true; frames without the chunk have false, which the converter writes: 1,871 of 1,871 values in the corpus after 2026-10), column rule width and colour 7,277 and 7,323 of 7,277 and 7,323, footnote spacings 4,351 of 4,351 each. Without chunk 0x22646 the IDML has width 1 and Color/Black (2,816 frames); without chunk 0x22608, 12 and 6 (1,430 frames). The column rule and footnote settings are written from the versions in which IDML has them (idml-values.md).

InsetSpacing: IDML writes it as a list where the frame is a plain rectangle and as one number (<InsetSpacing type="unit">15</InsetSpacing>) where it is not. A plain rectangle is a frame whose path (as written in PathGeometry) is one path of exactly four straight points (both direction points on the anchor), each sharing its x or y coordinate with the next (compared to 1e-4 pt), so that they are the corners of a rectangle along the axes of the frame's inner coordinates, and whose corner options in effect (its own TopLeftCornerOption to BottomRightCornerOption, else its object style's along BasedOn) are all None. Chunk 0x3723 holds no shape flag: its u32 at offset 8 is a UID (the frame's UID plus a few in most frames). Evidence over the text frames of the trustworthy pairs (except own/), in spreads, master spreads and stories (anchored frames):

Frame List One number None
Plain rectangle 40,603 0 6,551 (DOM 7 to 10)
Four-point rectangle with a corner option in effect 0 584 0
Curved path 0 771 0
Straight path of 2 or 3 points 0 29 0
Straight path of 4 points, not along the axes 0 131 0
Straight path of 5 to 7 points 4 77 0
Straight path of 9 to 32 points 0 124 0

The tolerance matters: 4 plain rectangles have corners whose coordinates differ in the last digit (-2395.597908385931 and -2395.597908385932), and IDML writes them as lists. A path with more than four points is not a plain rectangle even when its extra points add no corner: 32 of the 77 frames with 5 to 7 straight points reduce to a rectangle once repeated points and points on a side are removed (a closed path that repeats its first point at the end, open paths that repeat the first point, a 7-point path with 3 extra points on one side, a 6-point path with an extra point on the bottom side), and all 77 are one number (29 with 5 points, 34 with 6, 14 with 7). The 4 lists among them are exceptions, all with 5 points: 3 copies of one frame in one document, and one frame whose closing point differs from its first by 3.5e-15.

The one number is the f64 at offset 0 of chunk 0x3723, whatever the four insets are, equal or not. In one DOM 15 document, 101 anchored star-shaped frames (10 points) have 0 at offset 0 and four insets of 9, and two curved frames (44 and 28 points) have 0 at offset 0 and insets of 36, 0, 25.2 and 0; IDML writes 0 for all 103. In every other one-number frame of the trustworthy pairs the f64 at offset 0 equals the four insets.

From DOM 11 every frame has InsetSpacing. Before DOM 11 a frame that is not a plain rectangle always has it: all 200 such frames of the trustworthy pairs of DOM 7 to 10 (one number: 0, 4, 4.94, 5 or 15). For a plain rectangle it follows the rule of the general category below (857 frames with it, 6,551 without): IDML writes it where the frame's insets differ from its object style's (chunk 0x1B924 at 34, compared as a set of four values, since the order of the style's fields is not shown) or the style turns the category off. Over the trustworthy pairs of the corpus after 2026-10 the converter reproduces 42,337 of 42,341 InsetSpacing values; the 4 that differ are the list exceptions above.

MinimumFirstBaselineOffset is 0 on every frame and object style of the corpus IDML files, so its field cannot be found. IDML writes it on a frame exactly where the baseline category rule below writes the baseline attributes; the converter writes 0 under that rule: 1,753 of 1,753 values, none extra.

Values written on frames. IDML writes an attribute of a frame's TextFramePreference when its category is off in the frame's object style (the category ID is not in the style's list, chunk 0x1B92E, also for [None]), or when the frame's value differs from the style's value. The style's values are its own, or, if it has no text frame settings, those of the style it is based on, then [None]'s.

Category ID Attributes
General 0x1B93E TextColumnCount, TextColumnGutter, TextColumnFixedWidth, UseFixedColumnWidth, UseFlexibleColumnWidth, TextColumnMaxWidth, VerticalJustification, VerticalThreshold, IgnoreWrap, VerticalBalanceColumns, InsetSpacing
Baseline 0xADC8 FirstBaselineOffset, MinimumFirstBaselineOffset
Auto-sizing 0xADC9 the seven auto-sizing attributes
Footnotes 0xADCA the four Footnotes… attributes
Column rules 0xADCB the ten ColumnRule… attributes

Evidence over the 489 trustworthy pairs. Frames with style [None] write a whole category in a document if and only if [None]'s list lacks the ID (counting documents with such frames):

Category ID missing ID present
Auto-sizing (DOM 8 on) written in 28 of 28 documents written in 0 of 224 (one more has frames whose values differ)
Footnotes (13.1 on) 21 of 21 0 of 153
Column rules (DOM 15 on) 35 of 35 0 of 64
General, baseline (ID present in all 254) 0 of 254

Exceptions: TextColumnMaxWidth is on every frame from DOM 8 (22,775 of 22,775), TextColumnCount on every frame from DOM 10 (18,679 of 18,680; before, it follows the rule: absent in 4,006 frames where it equals the style), and InsetSpacing on every frame from DOM 11. The footnote values are on no frame before 13.1: none of the 3 documents of 13.0 has them, though one has frames whose style has the category off.

Applied to the converter's frame values and the reference styles' values, the rule leaves out 379,953 values that the IDML does not have, keeps the 200,434 it has, and leaves out one value that the IDML has (a TextColumnFixedWidth equal to its style's).

ColumnRuleOverride: the u32 at offset 0 of chunk 0x22646 (60 bytes). In the conversions of the 1,251 trustworthy pairs after 2026-10, 11,319 frames have the chunk: 2 frames (a 15.0 and an 18.4 document) have 1, and IDML has ColumnRuleOverride="true" on both; the other 11,317 have 0, and IDML has false wherever it writes the attribute. The converter writes true for 1 and false otherwise, also for frames without the chunk: 21,167 of 21,167 values, no extra value. The same 2 frames are the only ones whose chunk 0x2265A (32 bytes) is not all zero, so the corpus cannot tell the two chunks apart; offset 0 of 0x22646 is taken because the chunk holds the other column rule values of the frame.

Baseline frame grid of text frames. Chunk 0x2834 of the multi-column frame (24 bytes) holds the frame's baseline grid:

Offset Type BaselineFrameGridOption attribute
0 u16, 1 = true UseCustomBaselineFrameGrid
2 f64 StartingOffsetForBaselineFrameGrid
10 u16: 0 TopOfPage, 1 TopOfMargin, 2 TopOfFrame, 3 TopOfInset BaselineFrameGridRelativeOption
12 f64 BaselineFrameGridIncrement
20 u32 UID of an interface colour (class 0x1F11), 0 for the document's colour: BaselineFrameGridColor

Without the chunk the values are false, 0, TopOfInset, 12 and the document's colour (187 of 187 frames before 2026-10). The text frame settings of an object style (chunk 0x1B924) hold the same fields at offset 82 (u16 82, f64 84, u16 92, f64 94, u32 102).

IDML writes the element by the category rule above with category 0xADC8: when the category is off in the applied style, or the frame has no style object, it writes all four attributes and the colour; otherwise each attribute whose value differs from the style's, and the colour when the frame's colour UID differs from the style's. A frame with nothing to write has no element. The colour is the document's baseline frame grid colour (preferences.md) for UID 0, otherwise the interface colour named as for layers. The element has the colour as its only Properties child and follows TextFramePreference.

Evidence before 2026-10: all 23,940 text frames of the 606 trustworthy pairs (category off: 749 of 749 with every value; no style object: 4 of 4; category on with values that differ: 269 of 269 with exactly those values; only the colour UID differs: 32 of 32; nothing differs: no element in 22,886 of 22,886). One frame with offset 118 places the starting offset at 2. Object styles: 1,412 of 1,412 match their ObjectStyle/BaselineFrameGridOption.

Over the 1,251 trustworthy pairs after 2026-10, the converter's elements by this rule are 1,961 of the 1,961 reference elements on the frames it writes (the other 372 are on frames it does not write), with no extra element. All attributes are reproduced (1,692 to 1,915 each); 1,685 of 1,727 colours are, and the 42 others are on frames with UID 0 in documents whose document colour the converter gets wrong (preferences.md). The object styles' four values are reproduced in 5,556 of 5,556 styles; code 1 TopOfMargin occurs in 6 styles of 6 documents, with UseCustomBaselineFrameGrid="true".

Text orientation (chunk 0x2DE). The multi-column frame holds a matrix (six f64) in chunk 0x2DE. Its first four values are 1 0 0 1 for horizontal text and 0 1 −1 0 (a quarter turn) for vertical text. IDML has no frame attribute for this; it writes the orientation on the story (StoryPreference, StoryOrientation). Evidence:

  • All 18,207 multi-column frames in the 239 distinct little-endian public files that have text frames have 1 0 0 1. All 2,094 stories in the corpus IDML files have StoryOrientation="Horizontal".
  • A sample typeset vertically has 0 1 −1 0 in the frames of some stories and 1 0 0 1 in the others. In its print PDF, the text of every frame with the quarter turn is set in vertical columns ordered right to left (glyphs of a column share an x position and follow each other downwards), and the text of every frame with 1 0 0 1 is set in horizontal lines, such as the running heads. The frames of one story always agree.
  • In the rotated frames, TextColumnFixedWidth (chunk 0x2D1) equals the frame's height, not its width: the columns run down the page.

The last two values of the matrix are not identified. The converter writes Vertical for a story whose frames all have the quarter turn, and otherwise Horizontal, the value every IDML has. A story whose frames disagree or have another matrix gets a warning. Two frames in the InDesign 3.0 file have no chunk 0x2DE; they do not count.

First baseline offset. IDML writes FirstBaselineOffset on a frame's TextFramePreference only when it differs from the frame's object style. Over the frames of the corpus pairs, compared with the value written on the frame or, if absent, on its object style:

Code IDML value Frames
1 AscentOffset 1,121 of 1,121 (13 on the frame, 1,108 from the object style)
2 CapHeight 10 of 10 (copies of one document)

No pair has code 0. The evidence for it is a sample and its print PDF. In the PDF, the first baseline in each frame with code 0 lies below the frame's top edge by exactly the leading of that first line, for first lines with several different leadings. Of the values in the IDML schema (AscentOffset, CapHeight, LeadingOffset, EmboxHeight, XHeight, FixedHeight), only LeadingOffset depends on the leading.

Code 3 is EmboxHeight. No public file has it: the 18,207 multi-column frames of the 239 distinct little-endian public files have code 1 or 2 only. The evidence is a sample and its print PDF, and a sample typeset vertically with the same print PDF:

  • The frames measured have code 3, TopAlign and one line. No chunk of these frames or of their multi-column frame objects holds the measured distance as a number, so it is not a stored minimum offset.
  • A first line set in a CJK font lies below the frame's top edge by 0.880 of its point size. The font's ideographic em box (its BASE table) has its bottom at −0.120 em, so the em box top is at 0.880 em. The font's cap height (0.742 em), its x-height (0.503 em), the leading and a fixed offset of 0 give other distances. Its ascent is also 0.880 em.
  • A first line set in a Latin font lies below the frame's top edge by 0.825 of its point size. The font's ascent is 0.710 em, its cap height 0.650 em and its x-height 0.400 em; the leading and a fixed offset of 0 do not match either. So code 3 is not AscentOffset, which is code 1 in any case.
  • Of the values in the IDML schema, only EmboxHeight remains. The Latin font has no em box data; the measured 0.825 em equals an em box centred on half the cap height (0.325 + 0.5).

The converter leaves out codes other than 0 to 3.

Text frame defaults of the document. The preferences object (class 0x2202) has chunks 0x22646 and 0x22608 with the frame layouts, for the document's TextFramePreference: f64 at 28 ColumnRuleStrokeWidth and u32 at 36 ColumnRuleStrokeColor (a swatch UID; 195 of 195 documents before 2026-10), and u16 at 2, f64 at 4 and f64 at 12 the footnote span and spacings. Without chunk 0x22646 the values are 1 and Color/Black. Every chunk 0x22608 in the corpus holds 0, 0, 12 and 6, and every IDML has false, false, 12 and 6, so its offsets rest on the frame layout. IDML writes the column rule values from DOM 15 and the four Footnotes… values from 13.1 (save history, above). Over the trustworthy pairs after 2026-10: column rule width and colour 576 of 576 each; footnote values 860 of 876 each (the other 16 were exported by InDesign 13.1 from a document the INDD shows as saved by 13.0).

Kinsoku and mojikumi tables

Kinsoku tables are objects of classes 0x4209 (hard), 0x420A (soft), 0x42B4 (Korean), 0x42B5 (Simplified Chinese), 0x42B6 (Traditional Chinese) and 0x4204 (custom); mojikumi tables are classes 0x4206 and 0x4203 (custom, below). IDML writes one KinsokuTable or MojikumiTable per object in designmap.xml, kinsoku tables first, each in UID order (mojikumi tables of both classes together). Chunk 0x100B is a flag byte (1 = built-in key, $ID/) and the name; Self is KinsokuTable/<Name> or MojikumiTable/<Name>. Implemented in src/model/cjk.rs.

Evidence: 8 pairs have such objects, and their IDML lists exactly them, by name and in that order (6 with one table of each kind, 2 with 6 kinsoku and 16 mojikumi tables). The other 70 pairs have neither objects nor elements.

Custom kinsoku table (chunk 0x4214). Five u16 counts, then that many UTF-16 units for each of five lists: CantBeginLineChars, CantEndLineChars, a list not identified, HangingPunctuationChars and CantBeSeparatedChars. The evidence is one table in two copies of one document: the four non-empty lists have different lengths (66, 22, 4 and 3), and each matches the IDML attribute of that length. The layout parses in all 85 objects of class 0x4204 in the 250 distinct little-endian files, and the third count is 0 in all of them.

Built-in tables have only Self and Name in IDML. Mojikumi chunk 0x421E (a u16 from 1 to 16) is not used.

Custom mojikumi tables (class 0x4203). Chunk 0x100B holds a flag byte (0 in all of them) and the name, as for the other tables. Chunk 0x420A holds the settings:

Field Contents
u32 26 in all 835 objects of the 129 little-endian files that have the class
u32 0 in all
u32 n entry count
n × 34 bytes entries, below
u32, u32 not identified
u16 BasedOnMojikumiSet: 0 Nothing; n > 0 the built-in table kMojikumiDefaultName<n> (attributes.md): 1 LineEndAllOneHalfEmEnum, 10 LineEndAllOneEmEnum, 16 SimpChineseDefault

Each entry is one IDML OverrideMojikumiAkiType:

Offset Type IDML
0 u16 TargetMojikumiClass
2 u16 SideMojikumiClass
4, 12, 20 f64 Minimum, Desired, Maximum
28 u16 CompressionPriority
30 u16 AkiDoesNotFloat (0 false, 1 true)
32 u16 SideIsAfterTarget (0 false, 1 true)

IDML writes the table as <MojikumiTable Self="MojikumiTable/<name>" Name="<name>" BasedOnMojikumiSet="…"> with Properties, OverrideMojikumiAkiList and one OverrideMojikumiAkiType per entry, in file order, with the attributes in the order TargetMojikumiClass, SideMojikumiClass, SideIsAfterTarget, Minimum, Desired, Maximum, CompressionPriority, AkiDoesNotFloat.

Evidence, in the corpus of 2026-10: 185 tables in 66 pairs. The entry count matches in 185 of 185 tables, all eight fields of the entries in file order in 62,439 of 62,439 entries, and BasedOnMojikumiSet in 185 of 185 (code 1: 151 tables, 0: 33, 16: 1). Seven more trustworthy pairs (three of version 10.0, four of 10.0 and 10.1 whose IDML is from 10.2) have one table with code 10 each, and IDML LineEndAllOneEmEnum in 7 of 7. Self is MojikumiTable/ and the name in all 187 custom tables of the corpus IDML files. The layout parses in all 835 objects of the corpus; codes 3, 6, 9 and 11 also occur (232 objects, none with an IDML), and code 5 in a sample without an IDML. The built-in tables of these codes occur in no IDML, so the converter leaves BasedOnMojikumiSet out for them. The code is not the position of the value in the schema's MojikumiTableDefaults list by any rule the corpus proves: the proven codes 0, 1, 2, 10, 14, 15 and 16 are at their positions, but codes of other enumerations are not (12 of the 50 text attribute enumerations the converter maps differ from the schema order). A chunk whose length is not 22 + 34 n, or a flag other than 0 or 1, leaves the table out with a warning. In the 66 pairs, the tables of classes 0x4206 and 0x4203 are listed together in UID order, after all kinsoku tables.

Colours (0x1F05)

Chunk Contents
0x1F10 u8 1 if the name is a built-in key; name; u32 flags: bit 0 removable, bit 1 visible, bit 2 editable
0x1F01 u32 space (5 RGB, 6 CMYK, 7 LAB, 14 HSB, below), u16 count, f64 components: fractions for RGB, CMYK and HSB; for LAB the L, a and b values as IDML writes them
0x1F09 u32 model: 0 Process, 1 Spot, 2 Registration (below)
0x1F24 f64 tint value (−1 for a colour, see tints below), then u32 ColorOverride: 0 Normal, 1 Specialpaper, 2 Specialblack, 3 Specialregistration, 4 Hiddenreserved
0x1F0A Alternate colour, as 0x1F01: space 3 none, 6 CMYK, 7 LAB

After the flags, chunk 0x1F10 has two u32 and the SwatchCreatorID (7937 for colours made in the document, other numbers for colours from a swatch library, such as 31527). AlternateSpace is NoAlternateColor with AlternateColorValue="" without chunk 0x1F0A or with space 3; otherwise the space and the values, CMYK as percentages. Evidence over the 12,197 colours of the trustworthy pairs whose IDML colour has the same name: SwatchCreatorID 12,197 of 12,197; alternate space and values 12,197 of 12,197 (7,527 without the chunk, 4,624 with space 3, 33 LAB and 13 CMYK alternates, all library colours).

Space 7 is Space="LAB", with the three stored values as ColorValue (for example 79.2156862745098 38 53). The corpus IDML files have 92 LAB colours in 40 distinct files: 61 spot colours from swatch libraries (41 with a LAB alternate) and 31 process colours made in the document. Over all 803 pairs, Space is reproduced for 18,935 of 18,936 colours and ColorValue for 18,926.

Space 14 holds hue, saturation and brightness as fractions. IDML writes such a colour as RGB with ConvertToHsb="true"; the 9 such colours in the pairs (all hue 0, saturation 1, brightness 1) are 255 0 0. The converter converts with the usual hexagon formula. Every other colour has ConvertToHsb="false" (4,695 of 4,695 colours of the IDML files from DOM 16 on, where the attribute exists).

Colour groups. From DOM 12 on, every swatch (colour, tint, gradient, None) has SwatchColorGroupReference: the ColorGroupSwatch of the colour group that lists it, or n. Over the trustworthy pairs from DOM 12 on: colours 9,135 of 9,135, gradients 450 of 450, None 353 of 353, tints 24 of 24. DOM 11 files have the attribute on some swatches only (639 of 1,584 colours), and the converter writes it from DOM 12 on.

Unnamed colours are referenced by UID (Color/u93). All 1,296 colours in the pairs match on Model, Space, ColorValue, ColorOverride, Name and the three flags.

Which unnamed colours IDML writes. A colour without a name is in the IDML only if a value written in the package refers to it (an attribute or element text Color/u…; a tint counts), if a stop of any gradient refers to it, even of an unnamed gradient that IDML leaves out (below), or if an entry of class 0x1F05 in one of the two tables of the page item defaults (preferences.md) names it with either UID. Over the 489 trustworthy pairs, of the unnamed colours the converter wrote:

In the IDML Not in the IDML
Referenced by the output 2,309 0
Not referenced, named in a page item defaults table 564 0
Neither 10 8,684

All colours, written or not, are in the swatch list of the preferences object (class 0x2202, chunk 0x1F02), and the colour objects of the two groups have the same chunks and flags, so neither decides it. Named colours are always written. Unnamed gradients follow the same rule with class 0x5503: 457 unnamed gradients are referenced nowhere and named in no table, and none is in the IDML; 526 of the 548 unnamed gradients IDML writes meet the rule. Their stops go with them.

The other 22 are named by chunk 0x6E06 of the page item defaults object (class 0x6E07). The chunk has 34 bytes in all 489 trustworthy documents before 2026-10: u32 5, u32 0, u32 0, u32 14, then three entries of u16 0 and a u32 UID. Entry 0 names an object of class 0x5533, entry 1 a gradient and entry 2 a colour (489 of 489 each). IDML writes the gradient of entry 1 in every document: 480 are unnamed, and all 480 are in the IDML; none of the 162 unnamed gradients IDML leaves out (in the documents checked) is in the chunk. The colour of entry 2 is in the IDML wherever the converter writes it (82 of 82). The converter treats the swatches of chunk 0x6E06 as named by the page item defaults. With it, every unnamed gradient of the trustworthy pairs of 2026-10 that IDML writes is written (783 of 783 Gradient elements).

Model codes. The 250 distinct little-endian files hold 13,067 colours with chunk 0x1F09: 12,814 with code 0, 250 with code 2 (one Registration colour per file) and 3 with code 1. Two of the three are copies of one colour in two pairs, and their IDML has Model="Spot"; the third is in a file without an IDML. The converter leaves Model out, with a warning, for any other code.

Code 3: mixed inks. The corpus after 2026-10 has 47 colours with code 3 in 27 files, 16 of them pairs (InDesign 12.1 to 17.0, typeset in Korean). Their IDML has no Color element for them; it lists MixedInk and MixedInkGroup elements in Resources/Graphic.xml. A colour object with model code 3 is a mixed ink:

Chunk Layout IDML
0x1F09 u32 3, u32 n, n ink UIDs (class 0x1F07) InkList (Ink/ and each ink's Self name), InkNameList (the ink names, $ID/ for built-in ones)
0x1F01 u32 9 (colour space), u16 n, n f64 fractions InkPercentages: each fraction × 100 in the shortest form that reads back (30.000000000000004 where 0.3 × 100 gives it)
0x102D u32 m, m colour UIDs (the spot colours) MixedInkSpotColorList (Color/ and the name), MixedInkSpotColorNameList (the names)
0x1F10 as for colours Name, ColorEditable, ColorRemovable, Visible, SwatchCreatorID

In these lists a space of a name is written %20. A mixed ink group is a code 3 colour that also has chunk 0x1F24 (f64 −1, u32 5); its percentages are 0. IDML writes it as MixedInkGroup with Self, Model="Mixedinkmodel", the four lists, Name, the three flags, SwatchCreatorID and SwatchColorGroupReference. The members of a group are colour objects with colour space 9 in chunk 0x1F01, their own percentages and name, chunk 0x117 the group's UID, and no chunk 0x1F09 or 0x102D: they take the ink and spot lists from the group and have BaseColor="MixedInkGroup/<group name>". Other mixed inks have BaseColor="n".

MixedInk writes Self, Model="Mixedinkmodel", Space="MixedInk", InkList, InkPercentages, BaseColor, InkNameList, MixedInkSpotColorNameList, MixedInkSpotColorList, Name, ColorEditable, ColorRemovable, Visible, SwatchCreatorID and SwatchColorGroupReference, in this order. Self is MixedInk/ or MixedInkGroup/ and the name, escaped as colour names. In Graphic.xml the groups follow the inks, then the mixed inks sorted by Name in code point order (… 1, … 10, … 11, … 2; 16 of 16 files, UID order fails in 3). Fill colours and colour group swatches refer to them by Self.

Evidence: the 16 trustworthy pairs (DOM 12.1 to 17.0): 30 mixed inks without a group, 48 group members and 3 groups; every attribute above matches 81 of 81. No tint has a mixed ink as its base colour.

Tints are objects of the same class without chunks 0x1F10 and 0x1F01. Chunk 0x117 is the UID of the base colour, and chunk 0x1F24 holds the tint value in percent (IDML TintValue) where a colour has −1, followed by the colour override as for colours. IDML names a tint after its base colour and value: Name="Gold 80%" and Self="Tint/Gold 80%25" for 80 % of a colour named Gold. The black swatch (override Specialblack) is written in brackets: [Black] 40%.

Evidence: all 2,107 colours with a name in the distinct little-endian files have −1 at the start of chunk 0x1F24. The same files have 26 tints in 24 files, all with this layout and a named base colour. The pairs have 3 IDML Tint elements (2 files, one of them on black), and all 3 match on TintValue, BaseColor, Name and ColorOverride. Their 19 references (FillColor of 15 page items, StrokeColor of 3, one gradient stop) match too.

A tint's AlternateSpace and AlternateColorValue are those of its base colour (NoAlternateColor and an empty list where the colour has none): 260 of 260 IDML tints of the corpus of 2026-10 (204 in trustworthy pairs; 9 with LAB).

Tints have no flags chunk, so ColorEditable, ColorRemovable and Visible (true in all 3 IDML tints) are not written. Brackets are known only for black; other reserved colours as a tint base do not occur in the pairs.

The None swatch is class 0x6E0B (name in chunk 0x1F30).

Gradients (0x5503). Chunk 0x5503: u16 stop count n, n u32 stop colour UIDs, n f64 locations (0–1), n f64 midpoints, u32 type (1 linear). Chunk 0x5505: flag byte, name, u32 flags as for colours. All 99 gradients and 198 stops in the pairs match.

The midpoint stored with stop i is the position of the midpoint between stops i and i+1, measured from the start of the gradient (0–1), as for opacity gradient stops (transparency.md). IDML writes it on stop i+1 as a percentage of the distance between the two stops: Midpoint = (midpoint i − location i) / (location i+1 − location i) × 100. Evidence:

  • Most pairs have two stops at locations 0 and 1, where both readings give the same value. Two gradients in one pair have their first stop at 0.0037; stored midpoints 0.50184 and 0.60147 give IDML Midpoint 50 and 60 with this formula (2 of 2), not 50.18 and 60.15.
  • Gradients with more than two stops, or with stops not at 0 and 1, occur in 26 files, 392 gradients. Only the two above are in a reference IDML. In all 426 stop gaps of non-zero width, the stored midpoint lies between the two stops' locations, as a position from the start of the gradient must (for example stops at 0, 0.5 and 1 with stored midpoints 0.25 and 0.75). Written to IDML unconverted, 13 of them were outside the 13–87 that the IDML schema allows for Midpoint; converted, all 426 are inside it.
  • 8 gaps, all in one file, have width 0 (two stops at the same location), so the formula gives no value.

When the computed value is outside 13–87 or there is none, the converter leaves the Midpoint out and warns.

Inks (0x1F07)

Each ink object with chunk 0x1F0D is one IDML Ink in Resources/Graphic.xml, in UID order (314 of 314 inks, 78 of 78 pairs; the four process inks are UIDs 7 to 10). Self is Ink/<Name> (973 of 973 inks in the corpus IDML files). Chunk 0x1F0D is a flag byte (1 = built-in key, $ID/) and the name, then 86 bytes. Offsets from the end of the name:

Offset Contents IDML Evidence
14 f64 NeutralDensity 314 of 314 (2,786 of 2,786 over the 654 pairs of the later corpus)
26 u32, one less than the IDML value TrapOrder 314 of 314
32 f64 Frequency 314 of 314
40 f64 Angle 314 of 314 (0, 15, 27, 45, 63 and 75)
56 u8 ConvertToProcess (1 true) 2,065 of 2,065 inks of the trustworthy pairs (3 true)

Byte 2 is 1 for the four process inks and 0 for spot inks; its meaning is not known. The u8 at 56 is ConvertToProcess (1 true, 0 false): it is 1 for the 3 inks of the trustworthy pairs whose IDML has true (one spot ink, in three copies of one document) and 0 for the other 2,062; no other byte separates them. InkType="Normal" and PrintInk="true" are in every IDML ink and are written from that observation (idml-values.md). The schema puts inks after the colours and before the tints.

In 41 files without an IDML (InDesign 6.0, 13.x and 14.x, from two font projects), the neutral density of all four process inks, their only inks, is −1. The IDML schema allows 0.001 to 10 and no corpus IDML shows what InDesign writes for such an ink, so the converter leaves NeutralDensity out (with a warning) when the value is outside that range.

Colour groups (0x1F39)

Chunk 0x13C is a flag byte and the group name, chunk 0x1F60 a UID list of the group's swatches. The preferences object (class 0x2202) lists the groups in chunk 0x1F61 (u32 count, UIDs). IDML writes a ColorGroup in designmap.xml for each listed group, in that order, with Self="ColorGroup/<Name>"; the first has IsRootColorGroup="true", the others false (77 of 77 pairs; the DOM 7 pair has no chunk 0x1F61 and no groups). The root group is named [Root Color Group] with no $ID/, though its flag byte is 0.

Before DOM 11.3, Self is the group's UID (u<hex>) instead: in 58 of the 59 trustworthy pairs of versions 10.0 to 11.2 that have groups (one 11.0 file uses names), and names in 358 of 358 pairs from 11.3 on. The DOM version decides, not the header: header 11.4 files whose last session was 11.0 (DOM 11.0) use the UID. With the DOM version the converter writes (idml-values.md, DOM version), the extra ColorGroup elements of the trustworthy pairs fall from 15 values in 5 documents to 6 in 2 (not examined), and 3 more groups are reproduced.

Each swatch of the list is a ColorGroupSwatch with Self="u<group UID>ColorGroupSwatch<index in hex>" and SwatchItemRef the swatch's reference (Swatch/None, Color/…, Tint/… or Gradient/…). In 99 of 101 groups the list gives exactly the IDML swatches, in order; the other two are in the pairs whose IDML was exported from another save. The converter writes 907 of the 942 IDML swatches, all with the IDML reference. A swatch without a reference is left out, and the indices of the others are kept.

Bullet characters

The preferences object (class 0x2202) lists the bullet characters offered for lists in chunk 0x1A488: u16 1, u32 count, then for each bullet u32 character type (0 UnicodeOnly, 1 UnicodeWithFont, 2 GlyphWithFont, as in attributes.md), u32 character value, u32 font family UID (0 = none), a flag byte (1 = built-in key, $ID/) and the font style as an in-object string, then a byte: 0, or 1 followed by four more bytes. IDML writes one ABullet per entry in designmap.xml, with Self="dABullet<index>" (the index in hexadecimal: dABullet9, dABulleta, dABulletb in the 2 documents with more than ten bullets), CharacterType, CharacterValue and the BulletsFont (the family name, $ID/ for none) and BulletsFontStyle properties.

Evidence: all 78 pairs have the chunk; the count equals the number of IDML ABullet elements in 78 of 78 and the records end the chunk. All 396 bullets match on type, value and font style, and 395 on the font; the other is in the pair whose IDML names the family Minion Pro (OTF) (fonts.md).

The byte after the font style is 0 in 7,443 of the 7,447 bullets in the 1,428 distinct little-endian files that have the chunk. In one InDesign 20.0 file (with IDML) it is 1 in four bullets, each with flag byte 2, and four bytes follow: 00 00 90 01 after Regular and 00 00 BC 02 after Bold (read as two u16: 0 and 400, 0 and 700). Their meaning is not known, and IDML writes nothing for them. With this layout the records end the chunk in all 1,428 files. In the same file, the same five bytes also follow Regular in FontStyle attribute values (0x1B02, attributes.md), whose length prefix includes them. Flag byte 2 occurs in 46 bullets; in that file's IDML its style names have no $ID/ prefix, as with flag 0.

XML tags (0xBF19)

Chunk 0xBF2F is a u32 length and the tag name as text segments (in files from InDesign 2.0 to 5.0, a flag byte and an in-object string; big-endian.md); chunk 0x117 is the UID of the tag's colour, an object of class 0x1F11 whose chunk 0x1F01 holds u32 colour space 5 (RGB), u16 3 and three f64 fractions, as for swatches. IDML writes each tag as an XMLTag in XML/Tags.xml, with Self="XMLTag/<Name>" and the colour as the TagColor property. In all 78 pairs the number of tag objects equals the number of XMLTag elements and the names match (87 tags). IDML lists them by name, ignoring case (the one pair with more than one tag, 10 tags).

Red, green, blue TagColor Evidence
0.31, 0.6, 1 LightBlue 78 tags (Root)
1, 0, 0 Red 1
0.31, 1, 0.31 Green 1
0, 0, 1 Blue 1
1, 1, 0.31 Yellow 1
1, 0.31, 1 Magenta 1
0, 1, 1 Cyan 1
0.5, 0.5, 0.5 Gray 1
0, 0, 0 Black 1
0.6, 0, 0 BrickRed 1

Each colour other than light blue occurs once, all in one file. The converter leaves out TagColor for other colours.

The XML structure (the backing story and the elements) is described in xml.md.