This document describes the binary format of Altium Designer .SchLib (Schematic symbol library)
files as implemented by this crate. Every field below is verified against the byte-level
reverse-engineering campaign, the regenerated golden fixtures (scripts/samples/symbols.SchLib,
authored by real Altium 24) and the current reader/writer in src/altium/schlib/.
Note: Cross-referenced against AltiumSharp, pyAltiumLib and Altium-authored sample libraries. See References for links.
SchLib files are OLE Compound Documents (CFB format, OLE v3) containing:
/
├── FileHeader # Library metadata (C-string param block)
├── Storage # Embedded image bytes (compressed-storage stream)
└── {ComponentName}/ # One storage per symbol
├── Data # Symbol records stream
├── PinFrac # OPTIONAL: fractional pin coordinates (compressed storage)
├── PinSymbolLineWidth # OPTIONAL: per-pin symbol line widths (compressed storage)
├── PinWideText # OPTIONAL: wide form of non-ASCII pin names
└── PinFunctionData # OPTIONAL: written by newer Altium; carried verbatim, not read
The pin auxiliary streams are emitted only when at least one pin needs them (see
Pin auxiliary streams); a symbol with on-grid, default-width,
ASCII-named pins has only its Data stream, byte-identical to Altium's own output. Any other
stream a symbol's storage holds — a PinFunctionData from a newer Altium — is carried as read
(Symbol::extra_streams, base64 in JSON) and written back beside the ones this crate does
read, so nothing Altium stored is dropped for being unknown.
These rules apply to every text record and are referenced throughout the per-record tables instead of being repeated:
- Omit-when-default: zero-valued numeric keys and false booleans are OMITTED from the record
(Altium's
AddNonZero/AddBoolhelpers). A missing key means its default — numeric0, boolean false. Boolean keys are written as=Tonly;=Fis never written. IsNotAccesible: Altium's own single-'s' misspelling of "IsNotAccessible". Emitted asIsNotAccesible=Twhen set, omitted when false.- Colours are BGR: 32-bit
0x00BBGGRR(e.g.128= dark red,8388608= dark blue,11599871= light yellow,16711680= blue). An absent colour key reads back as 0 (black). - DXP units: coordinates are integer DXP units where 10 units = 1 grid square (1 DXP unit
= 10 mil = 100,000 raw internal units). Sub-unit precision uses the
_Fraccompanion keys (see Fractional coordinates). - Signed
_Frac: the fractional companion is signed, truncation is toward zero, and a zero integer part is omitted when the fraction is non-zero — golden-verified 2026-07-11 (details below). IndexInSheet: one shared sequential 0-based counter over all content records (see IndexInSheet).%UTF8%keys: any non-ASCII text value is written twice: the plain<Key>carrying the value's raw UTF-8 bytes, plus a%UTF8%<Key>companion. The gate is ASCII, not Windows-1252-representability — the golden storesRésistancethis way even thoughéhas a single-byte form. The companion's on-disk content in an Altium-authored file is the UTF-8 bytes re-decoded through the authoring machine's ANSI code page (a locale artefact; Windows-1250 for the golden); this crate writes the same bytes under both keys, which every reader resolves to the same value. Applies to every text field:LibReference,ComponentDescription,Texton Label/Parameter/Designator/TextFrame, and the FileHeader'sLibRef{N}/CompDescr{N}.UniqueID: 8-character alphanumeric per-record id, emitted as the LAST key.- Encoding: records are Windows-1252, with a leading
|, no trailing|, and a trailing0x00(the record length includes the null).
A root stream, present only when at least one component's name does not fit the CFB 31-UTF-16-unit
storage cap. Storage names for such components are the name's wire bytes plain-truncated at the
cap (the golden's Sinhala symbol is cut mid-codepoint, so the cut is bytewise); this stream maps
each real LibRef to its truncated SectionKey (storage name):
[u32 len]["|KeyCount=N|%UTF8%LibRef0=…|||LibRef0=…|%UTF8%SectionKey0=…|||SectionKey0=…" + 0x00]
Values follow the %UTF8% twin convention above; the ||| after each twin value is Altium's own
separator, reproduced verbatim. The FileHeader's LibRef{N} entries hold the full untruncated
name — the golden stores a 33-byte Khmer name there against a 31-unit storage — so lookup for a
long name goes FileHeader → SectionKeys → storage.
A non-ASCII pin name is stored in the binary pin record as its UTF-8 bytes (every one
of the golden's 52 such pins, Résistance included although Windows-1252 could hold it), with
this stream carrying the wide form beside it; the pin's other strings are Windows-1252.
Per-component, alongside PinFrac / PinSymbolLineWidth, in the shared compressed-storage
framing (see the /Storage section): one zlib entry per pin whose name leaves ASCII, keyed by pin
ordinal, payload a Unicode parameter block [u32 LE byte_len][UTF-16LE "|NAME=<text>"].
This is the pin name's authoritative wide form — the binary pin record narrows the name through the writing machine's ANSI code page, so a name typed as real Unicode survives only here. In an Altium-authored file the value can itself be the ANSI-widened form of the name's UTF-8 bytes (the golden's 52 streams all are, courtesy of script authoring); a reader folds such a value back through the plausible code pages and applies it only when the binary record yielded a lossy husk.
A single C-string parameter block:
[block_len:4 LE]["|HEADER=...|Weight=47|..." + 0x00] # length INCLUDES the null terminator
Keys as written by this crate (matching the golden library; note the mixed-case key spellings — the reader is case-insensitive):
| Key | Value | Notes |
|---|---|---|
HEADER |
Protel for Windows - Schematic Library Editor Binary File Version 5.0 |
File type identifier |
Weight |
47 | File weight |
MinorVersion |
9 | Minor version number |
UniqueID |
8-char alphanumeric | Library unique ID |
FontIdCount |
1 | Number of fonts in the font table |
Size1 |
10 | Font 1 size |
FontName1 |
Times New Roman | Font 1 name |
UseMBCS |
T | Multibyte character set |
IsBOC |
T | Binary OLE container flag |
SheetStyle |
9 | Sheet style number |
BorderOn |
T | Border enabled |
SheetNumberSpaceSize |
12 | |
AreaColor |
16317695 | Background colour (BGR) |
SnapGridOn / SnapGridSize |
T / 10 | |
VisibleGridOn / VisibleGridSize |
T / 10 | |
CustomX, CustomY |
18000 | Custom sheet dimensions |
UseCustomSheet |
T | |
ReferenceZonesOn |
T | |
Display_Unit |
0 | |
CompCount |
N | Number of components |
LibRef{i} |
name | Component name (0-indexed; OLE-safe storage name) |
CompDescr{i} |
text | Component description |
PartCount{i} |
N+1 | Stored as count + 1 |
Note: every
PartCountin the format (here and in RECORD=1) is stored asactual_count + 1. Read asmax(0, stored - 1)— do NOT floor at 1: a single-part symbol storesPartCount=1, which must decode to internal 0 and re-emit as 1 (flooring corrupted the round-trip toPartCount=2).
Each component's Data stream contains the symbol records:
[length:3 LE][flags:1][data:length]
[length:3 LE][flags:1][data:length]
...
The 4-byte header is a single 32-bit little-endian size word: the low 24 bits are the payload
length and the high byte is a flag (0x00 = text record, 0x01 = binary pin). For payloads under
16 MiB (always, in practice) this is byte-identical to a [u16 length LE][u16 BE type] reading,
which is why earlier notes described it that way. For text records the length INCLUDES the
trailing 0x00.
There is no end-of-stream marker — records simply run until the stream is exhausted. A trailing
0x0000 would be mis-read as a zero-length record (this was part of issue #68; the writer must not
emit one).
| Flag | Format | Description |
|---|---|---|
0x00 |
Text | Pipe-delimited key=value pairs (most records) |
0x01 |
Binary | Binary pin record (more compact than text) |
Text records contain pipe-delimited key=value pairs:
|RECORD=14|Location.X=-10|Location.Y=-4|Corner.X=10|Corner.Y=4|...
Every record type this crate models:
| ID | Type | Description |
|---|---|---|
| 1 | Component | Symbol header (name, description, part count) |
| 2 | Pin | Pin in text form (rare — skipped on read; binary pins are used instead) |
| 3 | IeeeSymbol | IEEE symbol glyph (a dot, a clock, an active-low input, …) |
| 4 | Label | Text string — the only free text on a symbol |
| 5 | Bezier | Cubic Bezier curve (4 control points) |
| 6 | Polyline | Multiple connected line segments |
| 7 | Polygon | Filled polygon |
| 8 | Ellipse | Ellipse or circle |
| 9 | Pie | Filled circular sector |
| 10 | RoundRectangle | Rounded rectangle |
| 11 | EllipticalArc | Elliptical arc |
| 12 | Arc | Circular arc |
| 13 | Line | Single line segment |
| 14 | Rectangle | Rectangle shape |
| 28 | TextFrame | Bordered multi-line text box |
| 30 | Image | Embedded/linked picture (bytes in /Storage) |
| 34 | Designator | Component designator (R?, U?, etc.) — a parameter record variant |
| 41 | Parameter | Component parameter (Value, Part Number, etc.) |
| 44 | ImplementationList | Container for a component's implementations |
| 45 | Implementation | One implementation (footprint model link) |
| 46 | MapDefinerList | Container for the implementation's map definers |
| 47 | MapDefiner | Pin-to-pad mapping (structure known; skipped on read) |
| 48 | ImplementationParameters | Per-implementation parameters |
Records 44/46/47/48 carry structural links only; this crate writes 44, 46 and 48 (46/48 as empty
OwnerIndex-bearing children of each RECORD=45) and skips all four on read. Record IDs that only
occur in schematic documents (Wire, Port, PowerObject, Note, ...) never occur in a .SchLib and
are out of scope.
Binary pin records have a variable-length structure: a fixed header, then Pascal short strings
([u8 len][bytes], Windows-1252) interleaved with fixed fields. Field order is strict. With N =
description length, the layout is:
| Offset | Size | Field | Notes |
|---|---|---|---|
| 0-3 | 4 | Record type | Always 2 for pin (i32, LE) |
| 4 | 1 | Reserved | Always 0x00 |
| 5-6 | 2 | OwnerPartId | Signed i16, LE (-1 = all parts) |
| 7 | 1 | OwnerPartDisplayMode | Alternate-view index (0 in practice) |
| 8 | 1 | Symbol: InnerEdge | See Pin Symbols |
| 9 | 1 | Symbol: OuterEdge | |
| 10 | 1 | Symbol: Inside | |
| 11 | 1 | Symbol: Outside | |
| 12 | 1+N | Description | Pascal short string — NO interior reserved byte |
| 13+N | 1 | FormalType | 0x01 for a normal pin; AFTER Description, BEFORE Electrical |
| 14+N | 1 | Electrical type | See Electrical Types |
| 15+N | 1 | Flags | See Pin Flags |
| 16+N | 2 | Length | DXP units, signed i16 LE (integer part; fraction in PinFrac) |
| 18+N | 2 | Location.X | Signed i16, LE (integer part) |
| 20+N | 2 | Location.Y | Signed i16, LE (integer part) |
| 22+N | 4 | Colour | BGR, u32 LE |
| 26+N | 1+M | Name | Pascal short string |
| after | 1+K | Designator | Pascal short string |
| after | 1+P | SwapIdGroup | Pascal short string (empty by default) |
| after | 1+Q | PartAndSequence | Pascal short string; default |&| (= {SwapIdPart}|&|{SwapIdSequence} with both empty) |
| after | 1+R | DefaultValue | Pascal short string (e.g. 3.3V); LAST field |
A truncated legacy record is read tolerantly: any absent trailing Pascal string reads as "" and
is reproduced exactly on write (an empty PartAndSequence is NOT coerced back to |&|).
Flags byte at 15+N:
| Bit | Flag | Description |
|---|---|---|
| 0x01 | Rotated | Pin rotated 90° |
| 0x02 | Flipped | Pin flipped |
| 0x04 | Hidden | Pin hidden from view |
| 0x08 | DisplayNameVisible | Show pin name |
| 0x10 | DesignatorVisible | Show pin designator |
| 0x20 | IsNotAccessible | Not selectable |
| 0x40 | GraphicallyLocked | Pin is graphically locked |
| 0x80 | Reserved | — |
Pin symbol decorations appear at four positions on the pin (bytes 8-11) to indicate electrical characteristics:
| ID | Symbol | Description |
|---|---|---|
| 0 | None | No decoration |
| 1 | Dot | Inversion dot (bubble) |
| 2 | RightLeftSignalFlow | Right-to-left signal flow arrow |
| 3 | Clock | Clock input indicator |
| 4 | ActiveLowInput | Active low input bar |
| 5 | AnalogSignalIn | Analog signal input |
| 6 | NotLogicConnection | Not a logic connection |
| 7 | PostponedOutput | Postponed output |
| 8 | OpenCollector | Open collector output |
| 9 | HiZ | High impedance |
| 10 | HighCurrent | High current |
| 11 | Pulse | Pulse |
| 12 | Schmitt | Schmitt trigger input |
| 13 | ActiveLowOutput | Active low output bar |
| 14 | OpenCollectorPullUp | Open collector with pull-up |
| 15 | OpenEmitter | Open emitter output |
| 16 | OpenEmitterPullUp | Open emitter with pull-up |
| 17 | DigitalSignalIn | Digital signal input |
| 18 | ShiftLeft | Shift left |
| 19 | OpenOutput | Open output |
| 20 | LeftRightSignalFlow | Left-to-right signal flow arrow |
| 21 | BidirectionalSignalFlow | Bidirectional signal flow |
| Field | Limit |
|---|---|
| Name / Designator / Description / SwapIdGroup / PartAndSequence / DefaultValue | 255 encoded (Windows-1252) bytes max |
| Location.X, Location.Y | i16 range (±32767) |
| Length | i16 range (±32767) |
| Field | Default |
|---|---|
electrical_type |
Passive (ID 4) |
formal_type |
1 |
show_name / show_designator |
true |
colour |
Black (0x000000) |
part_and_sequence |
|&| |
swap_id_group / default_value |
empty |
Derived from the Rotated and Flipped flags:
| Rotated | Flipped | Orientation |
|---|---|---|
| false | false | Right (connection on left) |
| false | true | Left (connection on right) |
| true | false | Up (connection on bottom) |
| true | true | Down (connection on top) |
| ID | Type |
|---|---|
| 0 | Input |
| 1 | Bidirectional (InputOutput) |
| 2 | Output |
| 3 | OpenCollector |
| 4 | Passive |
| 5 | HiZ (Tri-state) |
| 6 | OpenEmitter |
| 7 | Power |
Three optional per-component OLE streams carry data the binary pin record cannot hold
(PinWideText, the third, is described above). All use the
compressed-storage framing with each entry keyed by the pin
ordinal as an ASCII-decimal Pascal string:
PinFrac— the fractional part of each off-grid pin's X / Y / length. Payload: 12 bytes = three little-endiani32(frac_x,frac_y,frac_length), each scaled by 100,000 like the text-record_Frackeys.PinSymbolLineWidth— a per-pin symbol line width. Payload: a Unicode parameter block[u32 LE byte_len][UTF-16LE "|SYMBOL_LINEWIDTH=N"].
A symbol whose pins are all on-grid, default-width and ASCII-named emits none of them.
Three stream families share one byte layout: PinFrac, PinSymbolLineWidth and the root
/Storage stream:
[u32 LE header_len][header_len header bytes] # C-string param block
then, per entry:
[u32 LE size] # low 24 bits = block size, high byte = 0x01 flag
0xD0 # storage-entry tag
[u8 name_len][name] # Pascal-string entry key (Windows-1252)
[u32 LE comp_len][comp_len bytes] # zlib-compressed payload
The header param block is |HEADER=<name> plus |Weight=<count> (Altium's mixed-case key) when
at least one entry follows.
The root /Storage stream carries the raw bytes of every embedded image (RECORD=30 with
EmbedImage=T), one compressed entry per image:
- Header:
|HEADER=Icon storage|Weight=<count>. An empty library carries the bare|HEADER=Icon storageblock with NOWeightkey. - Entry names: real AD24 names each entry with the image's full file path (the record's
FileNamevalue); AltiumSharp's own writer uses the zero-based index instead. This crate follows real AD24 on write. - Matching: entry names are ignored on read — payloads are matched to
EmbedImage=Timages in order across all symbols (global stream order), exactly like AltiumSharp'sParseStorageImageData. - Payload: the raw image file bytes (BMP/PNG/JPG), zlib-compressed (RFC 1950).
- Schematic units: 10 units = 1 grid square
- Standard grid is 10 units
- Pins are typically 10-30 units long
Graphic-primitive coordinates may sit off the integer grid. Altium stores each
coordinate as an integer key plus an optional <key>_Frac companion holding the
fractional part scaled by 100,000, reconstructed as:
value = <key> + <key>_Frac / 100000
This applies to every coordinate key — Location.X/Y, Corner.X/Y,
Radius, SecondaryRadius, CornerXRadius/CornerYRadius, TextMargin and
the polyline / polygon vertices X{n}/Y{n}. The _Frac field is signed:
AD24 truncates the integer part toward zero and lets the fraction carry the
coordinate's sign (range -99999..=99999, never opposite in sign to the integer
part). The FRACSHAPES golden fixture stores -5.45 as Location.X=-5 with
Location.X_Frac=-45000 (-5 + -45000/100000 = -5.45). AD24 omits every
zero coordinate key, integer and _Frac alike: the golden arc centred at
0.05 carries only Location.X_Frac=5000 (no Location.X), the LINES golden
line (0,0)→(10,0) carries only Corner.X=10, and the POLYLINES golden
vertices omit their zero X{n}/Y{n} halves. The reader defaults every
absent coordinate key to 0; integer-grid coordinates carry no _Frac. When the
fractional part rounds up to a whole unit it carries into the integer part
(e.g. 4.999995 → Radius=5, no _Frac) rather than being clamped.
Historical note: versions of this crate before the signed-frac fix wrote the floor form instead — a non-negative
_Fracwith a floored integer part (-5.45→Location.X=-6,Location.X_Frac=55000). Both forms decode identically undervalue = int + frac / 100000, and the reader parses the fraction as a signed integer, so files written in either convention read back correctly. (The pre-fix reader parsed_Fracas unsigned, silently dropping the fractional part of every AD24-written negative off-grid coordinate.)
Binary pin records (Type 1) store integer coordinates only; their fractional
parts live in the separate PinFrac stream.
Colours are stored as 32-bit BGR values:
0x00BBGGRR
Common colours:
| Value | Colour | Usage |
|---|---|---|
0x000080 (128) |
Dark Red | Component outline |
0x800000 (8388608) |
Dark Blue | Text, parameters |
0xB0FFFF (11599871) |
Light Yellow | Fill colour |
0xFF0000 (16711680) |
Blue | Component body |
0x000000 (0) |
Black | Pins; the read-back default for any absent colour key |
All content records — every graphic shape, user Label/Parameter record and every binary pin —
share ONE sequential 0-based IndexInSheet counter in stream order (golden-confirmed against both
the regenerated fixture and real Altium-authored libraries):
- The token is omitted at slot 0 and sits immediately after
IsNotAccesible(beforeOwnerPartId), matching the golden token order|RECORD=12|IsNotAccesible=T|IndexInSheet=1|…. - Binary pins store no token (the binary record has no such field) but still consume a
counter slot: a real Altium symbol with parameters 0-2, two pins, then a rectangle stores
IndexInSheet=5on the rectangle (slots 3 and 4 are the pins). - The component header (RECORD=1) and the trailing system Designator (RECORD=34) / Comment
(RECORD=41,
OwnerPartId=-1) records carry theIndexInSheet=-1sentinel and do not consume a counter slot (the golden DISPMODE system Comment storesIndexInSheet=-1while the rectangles keep slots 0 and 1); RECORD=44/46/48 carry no token and RECORD=45 carries-1. - The value is purely positional, so this crate derives it on write rather than storing it. That
makes the counter only as good as the record order: Altium stores the content records in
authoring order, interleaving the kinds (the golden's
LOCKFLAGS2runs line, arc, ellipse, round-rect, polyline, polygon, pie, bezier, label), so a symbol read from a file is written back in the order it came in. See Symbol Writing Order.
Most text records include these standard fields (see Cross-Cutting Conventions for the omission rules):
| Property | Type | Description |
|---|---|---|
RECORD |
int | Record type ID (first key) |
IsNotAccesible |
bool | Not selectable; single-'s' spelling; emit only when T |
IndexInSheet |
int | Shared content counter (0 omitted; -1 on header/system records) |
OwnerPartId |
int | Part ownership (-1 = all parts, 1+ = specific part) |
OwnerPartDisplayMode |
int | Alternate display mode; omitted when 0 |
GraphicallyLocked / Disabled / Dimmed |
bool | Universal display/lock flags; emit only when T |
UniqueID |
string | 8-char alphanumeric identifier, last key |
The four universal display/lock flags (GraphicallyLocked, Disabled, Dimmed,
OwnerPartDisplayMode) are modelled on all shape records and sit immediately after
OwnerPartId (golden: …|OwnerPartId=1|OwnerPartDisplayMode=1|Location.X=… on the DISPMODE
rectangle, …|OwnerPartId=1|GraphicallyLocked=T|… on LOCKFLAGS), in the order
OwnerPartDisplayMode, GraphicallyLocked, Disabled, Dimmed.
The first record of each component's Data stream. Keys as written (in order):
| Property | Type | Description |
|---|---|---|
LibReference |
string | Component name |
ComponentDescription |
string | Description |
PartCount |
int | Stored as count + 1 (see FileHeader note) |
DisplayModeCount |
int | Number of display modes (typically 1) |
IndexInSheet |
int | -1 for the component root |
OwnerPartId |
int | -1 for the component root |
CurrentPartId |
int | Currently displayed part (default 1) |
LibraryPath |
string | * sentinel — scripted headers carry it, UI-authored ones omit it |
SourceLibraryName |
string | * sentinel |
SheetPartFileName |
string | * sentinel — scripted headers carry it, UI-authored ones omit it |
TargetFileName |
string | * sentinel |
AllPinCount |
int | A stale count Altium does not maintain (a UI-drawn 32-pin MCU stores 1, a one-pin header 2); carried verbatim on a read-modify-write, the pin count for a symbol built from scratch |
AreaColor |
int | Fill colour (BGR, 11599871 = light yellow) |
Color |
int | Border colour (BGR, 128 = dark red) |
PartIDLocked |
bool | T/F |
Note: Altium-authored headers also carry a component
UniqueIDand may carryDesignItemId/ComponentKind; none of these is a typed field, but every key the model does not name — those, or a UI-authoredCOMPONENTKINDVERSION2=5— rides along verbatim: the whole header is carried as read (Symbol::header_params, every segment in order) and replayed byte for byte unless the field behind a segment was edited, so the two%UTF8%layouts Altium uses both survive. A UI-typed Latin-1 description is stored as%UTF8%ComponentDescription=<UTF-8 bytes>|||ComponentDescription=<Windows-1252 bytes>(twin first, two empty segments, code-page plain key); a scripted one puts UTF-8 bytes in both keys.
A record the file stores without a UniqueID (Altium writes a pie and an IEEE symbol that way) is not given one:
a save is deterministic, so a version-controlled library shows no phantom diff. The library's
own UniqueID in the FileHeader is kept for its lifetime as well.
Every content record is carried the same way — raw_params on each record struct holds its
segments as read — and replayed verbatim where the field behind a segment is unchanged: the
UI omits LineWidth=1 on a rectangle where a script writes it, stores a Latin-1 label as
%UTF8%Text=<UTF-8>|||Text=<Windows-1252>, and may carry keys this crate does not model,
all of which come back as stored; an edited field takes its canonical form, a cleared flag's
key is dropped, and the positional IndexInSheet is always recomputed.
The system parameter is Altium's own Comment record alone (with the Designator
record): stored after the designator with IndexInSheet=-1 and no counter slot. A user
parameter is a content record with a counter slot in authoring order — the UI stores it
with OwnerPartId=-1 too (a script sets 1), and before the graphics, so OwnerPartId
does not mark a parameter as system.
All shape records carry the common fields in addition to the tables
below; every coordinate accepts a _Frac companion.
Altium's text string: the only free text a symbol carries (the RECORD=3 this crate once
read as a "text annotation" is the IEEE symbol below).
| Property | Type | Description |
|---|---|---|
Location.X / Location.Y |
coord | Anchor position |
Orientation |
int | 0-3 = 0°/90°/180°/270°; omit at 0 |
Justification |
int | Text alignment (see below); omit at 0 |
Color |
int | Text colour (BGR; omit at 0) |
FontId |
int | Font-table reference (default 1; always written) |
Text / %UTF8%Text |
string | Content |
IsHidden |
bool | Emit only when T |
IsMirrored |
bool | Emit only when T |
Keys in golden order: Orientation and Justification sit between the coordinates and
Color/FontID (the JUSTIFY golden stores …|Location.X=-10|Justification=8|FontID=1|Text=TR|…).
Orientation values: orientation = (rotation_degrees / 90) % 4.
Justification values:
| ID | Position | ID | Position | ID | Position |
|---|---|---|---|---|---|
| 0 | Bottom Left | 3 | Middle Left | 6 | Top Left |
| 1 | Bottom Centre | 4 | Middle Centre | 7 | Top Centre |
| 2 | Bottom Right | 5 | Middle Right | 8 | Top Right |
One of Altium's standard logic and signal glyphs placed at a point with a scale, a
quarter-turn rotation and an optional mirror. Settled by the IEEESYM golden:
the record carries exactly these keys, in this order, and no UniqueID — Altium never
gives this record one, so none is written.
| Property | Type | Description |
|---|---|---|
Symbol |
int | The glyph (TIeeeSymbol, table below); always written |
Location.X / Location.Y |
coord | Anchor position; omit at 0 |
ScaleFactor |
coord | Glyph size in schematic units (10 for a 100 mil placement); always written |
Orientation |
int | 0-3 = 0°/90°/180°/270°; omit at 0 |
LineWidth |
int | Always written (1 at the default) |
Mirror |
bool | Emit only when T (note: Mirror, not a label's IsMirrored) |
Color |
int | Line colour (BGR; omit at 0) |
Golden records: |RECORD=3|IsNotAccesible=T|OwnerPartId=1|Symbol=1|Location.X=-10|ScaleFactor=10|LineWidth=1
(a dot), …|Symbol=3|ScaleFactor=10|Orientation=1|LineWidth=1|Mirror=T (a mirrored, rotated
clock) and …|OwnerPartId=1|GraphicallyLocked=T|Symbol=4|Location.X=10|ScaleFactor=20|LineWidth=1|Color=16711680
(a locked, larger, coloured active-low input) — the display flags sit after OwnerPartId as
on every graphic.
TIeeeSymbol values (AD24): 0 none, 1 Dot, 2 Right-Left Signal Flow, 3 Clock,
4 Active Low Input, 5 Analog Signal In, 6 Not Logic Connection, 7 Shift Right, 8 Postponed
Output, 9 Open Collector, 10 Hi-Z, 11 High Current, 12 Pulse, 13 Schmitt, 14 Delay, 15 Group
Line, 16 Group Binary, 17 Active Low Output, 18 Pi, 19 Greater Equal, 20 Less Equal, 21 Sigma,
22 Open Collector Pull Up, 23 Open Emitter, 24 Open Emitter Pull Up, 25 Digital Signal In,
26 And, 27 Invertor, 28 Or, 29 Xor, 30 Shift Left, 31 Input Output, 32 Open Circuit Output,
33 Left-Right Signal Flow, 34 Bidirectional Signal Flow. The JSON symbol field carries the
id as stored, so a value this table does not name round-trips unchanged.
| Property | Type | Description |
|---|---|---|
LocationCount |
int | Control point count (always 4; not validated on read) |
X{n} / Y{n} |
coord | Control points, 1-indexed (X1..Y4) |
LineWidth |
int | Line width index |
Color |
int | Line colour (BGR; omit at 0) |
IsNotAccesible |
bool | Emit only when T |
| Property | Type | Description |
|---|---|---|
IsNotAccesible |
bool | Emit only when T (the golden tags every polyline) |
LineWidth |
int | Line width index (always written) |
LineStyle |
int | 0=Solid, 1=Dashed, 2=Dotted; omit at 0 |
StartLineShape / EndLineShape |
int | Endpoint shapes (see below); omit at 0 |
LineShapeSize |
int | Size of endpoint shapes; omit at 0 |
Color |
int | Line colour (BGR; omit at 0) |
Transparent |
bool | Emit only when T, before LocationCount |
LocationCount |
int | Vertex count (minimum 2) |
X{n} / Y{n} |
coord | Vertices, 1-indexed (zero halves omitted) |
LineStyleExt |
int | Style companion after the vertices, same value as LineStyle; omit at 0 |
Line shapes:
| ID | Shape |
|---|---|
| 0 | None |
| 1 | Arrow |
| 2 | SolidArrow |
| 3 | Tail |
| 4 | SolidTail |
| 5 | Circle |
| 6 | Square |
| Property | Type | Description |
|---|---|---|
IsNotAccesible |
bool | Emit only when T |
LineWidth |
int | Border width index |
Color |
int | Border colour (BGR; omit at 0) |
AreaColor |
int | Fill colour (BGR; omit at 0) |
LineStyle |
int | 0=Solid, 1=Dashed, 2=Dotted; omit at 0 |
IsSolid |
bool | Whether filled; emit only when T (absent = unfilled) |
Transparent |
bool | Emit only when T, before LocationCount (SHAPESTYLE golden) |
LocationCount |
int | Vertex count (minimum 3) |
X{n} / Y{n} |
coord | Vertices, 1-indexed (zero halves omitted) |
Note:
IsSolidis the fill flag, not a border style.
| Property | Type | Description |
|---|---|---|
IsNotAccesible |
bool | Emit only when T (the golden tags every ellipse) |
Location.X / Location.Y |
coord | Centre |
Radius |
coord | X radius |
SecondaryRadius |
coord | Y radius; defaults to Radius when absent (circle) |
LineWidth |
int | Border width index |
Color / AreaColor |
int | Border / fill colour (BGR; omit at 0) |
IsSolid |
bool | Filled; emit only when T |
Transparent |
bool | Emit only when T |
A filled circular sector.
| Property | Type | Description |
|---|---|---|
IsNotAccesible |
bool | Emit only when T |
Location.X / Location.Y |
coord | Centre |
Radius |
coord | Radius |
LineWidth |
int | Border width index (before the angles) |
StartAngle / EndAngle |
float | Degrees, 3-decimal form (30.000); StartAngle omitted at 0, EndAngle always written (defaults 0.0 / 360.0 on read) |
Color / AreaColor |
int | Border / fill colour (BGR; omit at 0) |
IsSolid |
bool | Filled; emit only when T |
Transparent |
bool | Emit only when T |
| Property | Type | Description |
|---|---|---|
Location.X / Location.Y |
coord | First corner |
Corner.X / Corner.Y |
coord | Second corner |
CornerXRadius / CornerYRadius |
coord | Corner radii |
LineWidth |
int | Border width index |
Color / AreaColor |
int | Border / fill colour (BGR; omit at 0) |
LineStyle |
int | 0=Solid, 1=Dashed, 2=Dotted; omit at 0 |
IsSolid |
bool | Filled; emit only when T |
Transparent |
bool | Emit only when T |
| Property | Type | Description |
|---|---|---|
Location.X / Location.Y |
coord | Centre |
Radius (+ Radius_Frac) |
coord | Primary radius |
SecondaryRadius (+ _Frac) |
coord | Secondary radius; defaults to Radius when absent |
LineWidth |
int | Line width (before the angles) |
StartAngle / EndAngle |
float | Degrees, 3-decimal form; StartAngle omitted at 0, EndAngle always written (defaults 0.0 / 360.0 = full ellipse on read) |
Color / AreaColor |
int | Line / fill colour (BGR; omit at 0) |
Note: a fractional radius rounding up to a whole unit carries into the integer part rather than being clamped (see Fractional coordinates).
| Property | Type | Description |
|---|---|---|
IsNotAccesible |
bool | Emit only when T |
Location.X / Location.Y |
coord | Centre |
Radius |
coord | Arc radius |
LineWidth |
int | Line width (before the angles, per the ARCS golden) |
StartAngle / EndAngle |
float | Degrees, 3-decimal form (EndAngle=360.000); StartAngle omitted at 0, EndAngle always written (defaults 0.0 / 360.0 = full circle on read) |
Color / AreaColor |
int | Line / fill colour (BGR; omit at 0) |
| Property | Type | Description |
|---|---|---|
IsNotAccesible |
bool | Emit only when T |
Location.X / Location.Y |
coord | Start point |
Corner.X / Corner.Y |
coord | End point |
LineWidth |
int | Line width index |
LineStyle |
int | 0=Solid, 1=Dashed, 2=Dotted; omit at 0 |
Color |
int | Line colour (BGR; omit at 0) |
LineStyleExt |
int | Style companion, same value as LineStyle; omit at 0 (a golden dashed line carries BOTH LineStyle=1 and LineStyleExt=1; the reader accepts either) |
| Property | Type | Description |
|---|---|---|
IsNotAccesible |
bool | Always T on write |
Location.X / Location.Y |
coord | First corner |
Corner.X / Corner.Y |
coord | Second corner |
LineWidth |
int | Border line width index |
Color / AreaColor |
int | Border / fill colour (BGR; omit at 0) |
LineStyleExt |
int | Border style — rectangles store the line style in LineStyleExt, NOT LineStyle; omit at 0 |
IsSolid |
bool | Filled; emit only when T |
Transparent |
bool | Emit only when T (the golden's unfilled rectangle carries neither IsSolid nor Transparent) |
A bordered multi-line text box. All keys below are omit-when-default (note the defaults of 0 for
LineWidth and FontID, unlike other shapes).
| Property | Type | Description |
|---|---|---|
IsNotAccesible |
bool | Emit only when T |
Location.X / Location.Y |
coord | First corner |
Corner.X / Corner.Y |
coord | Second corner |
LineWidth |
int | Border width; omit at 0 |
Color |
int | Border colour (BGR; omit at 0) |
LineStyle |
int | Border style; omit at 0 |
AreaColor |
int | Fill colour (BGR; always written, even 0) |
TextColor |
int | Text colour (BGR; omit at 0) |
FontID |
int | Font reference (always written) |
IsSolid / ShowBorder |
bool | Emit only when T |
Orientation |
int | 0-3; omit at 0 |
Alignment |
int | Text alignment; omit at 0 |
WordWrap / ClipToRect |
bool | Emit only when T |
Text / %UTF8%Text |
string | Multi-line content (always written) |
TextMargin (+ _Frac) |
coord | Margin, following the omit-every-zero-key coordinate rule (a default frame carries only TextMargin_Frac=5) |
Transparent |
bool | Emit only when T, after TextMargin |
The picture metadata; embedded bytes live in /Storage.
| Property | Type | Description |
|---|---|---|
IsNotAccesible |
bool | Emit only when T |
Location.X / Location.Y |
coord | Bounding-box corner 1 |
Corner.X / Corner.Y |
coord | Bounding-box corner 2 |
LineWidth |
int | Border width index |
Color |
int | Border colour (BGR; omit at 0) |
LineStyle |
int | Border style; omit at 0 |
AreaColor |
int | Fill colour (BGR; omit at 0) |
IsSolid / Transparent / ShowBorder |
bool | Emit only when T |
KeepAspect |
bool | Preserve aspect ratio; emit only when T |
EmbedImage |
bool | T = bytes embedded in /Storage (matched in global stream order) |
FileName |
string | Image file path (also used as the /Storage entry name); omit when empty |
A parameter-record variant selected by Name=Designator. As written by this crate:
| Property | Value |
|---|---|
IndexInSheet / OwnerPartId |
-1 / -1 (system record; no counter slot) |
Location.X / Location.Y |
Designator position, modelled on the symbol (golden default -5 / 5; zero keys omitted) |
Color |
8388608 (dark blue) |
FontID |
1 |
Text / %UTF8%Text |
Designator text (e.g. R?) |
Name |
Designator |
ReadOnlyState |
1 |
UniqueID |
8-char id, preserved from read (generated only when absent) |
| Property | Type | Description |
|---|---|---|
IndexInSheet |
int | Shared content counter for user parameters (OwnerPartId >= 1, 0 omitted); the -1 sentinel for system parameters (OwnerPartId=-1, no counter slot). Directly after RECORD (parameters carry no IsNotAccesible token) |
OwnerPartId |
int | Part ownership (-1 = system Comment-class record) |
Location.X / Location.Y |
coord | Position; every zero key omitted, _Frac companions adjacent to their integer keys |
Orientation |
int | 0-3; omit at 0 |
Justification |
int | Text anchor 0-8 (same table as Label); omit at 0 (golden JUSTIFY carries Justification=8/=4) |
Color |
int | Text colour (BGR; omit at 0 — the golden's user parameters carry no key) |
FontID |
int | Font reference (always written) |
IsHidden |
bool | Emit only when T |
Text / %UTF8%Text |
string | Parameter value; omit when empty |
Name |
string | Parameter name (always written) |
ReadOnlyState |
int | Omit at 0 (after Name, per real Altium output) |
ParamType |
int | 0=String, 1=Boolean, 2=Integer, 3=Float; omit at 0 |
ShowName / HideName / IsConfigurable |
bool | Emit only when T |
Description |
string | Omit when empty |
-
RECORD=44 (ImplementationList) — always written, exactly
|RECORD=44, even when the symbol has no footprint models. -
RECORD=45 (Implementation) — one per footprint model, owned by the RECORD=44 via
OwnerIndex= the 44's 0-based stream-index:Property Type Description OwnerIndexint Stream-index of the owning RECORD=44 IndexInSheetint -1 Descriptionstring Model description ModelNamestring Footprint name ModelTypestring PCBLIB(alsoSIM/SIin the wild)DatafileCountint Number of datafile links (this crate writes 1) ModelDatafile0string Optional .PcbLibpath — what lets Altium resolve the footprint directlyModelDatafileEntity0string Footprint entity (resolution key) ModelDatafileKind0string PCBLibIsCurrentbool Ton the default footprint; omitted on every other (neverF)The record is carried and replayed like every content record (
raw_params, see Component Header Record): a UI-authored link also carriesIntegratedModel=T|DatabaseModel=T, which this crate does not model, and omitsDescriptionwhile it is empty, all of which come back as stored. A link without a datafile omits the whole datafile group —DatafileCount,ModelDatafile0,ModelDatafileEntity0,ModelDatafileKind0(theIMPLCHAINgolden's name-only links); this crate writes the group for a from-scratch link, which is what lets Altium resolve the footprint, and keeps a read link as it was unless a path is given. -
RECORD=46 (MapDefinerList) and RECORD=48 (ImplementationParameters) — written as empty children of each RECORD=45 (
|RECORD=46|OwnerIndex={45's index}/|RECORD=48|OwnerIndex=...). -
RECORD=47 (MapDefiner) — pin-to-pad mapping (
DESINTF,DESIMPCOUNT,DESIMP{i},ISTRIVIAL); structure known from AltiumSharp but currently skipped on read and never written.
Note:
DatafileCount=1plus theModelDatafileEntity0link is what lets Altium resolve the model to an actual footprint in aPcbLib; a name-only record withDatafileCount=0shows in the list but reports "model not found". AltiumSharp indexes the datafile keys 1-based (MODELDATAFILEKIND1); this crate writes 0-based — theIMPLCHAINgolden, authored by AD24, storesModelDatafile0/ModelDatafileEntity0/ModelDatafileKind0.
Read-side defaults when properties are absent:
| Property | Default | Notes |
|---|---|---|
FontId |
1 | Except TextFrame (0) |
StartAngle / EndAngle |
0.0 / 360.0 | Arc, EllipticalArc, Pie |
OwnerPartId |
1 | Shapes default to 1; -1 = all parts |
OwnerPartDisplayMode |
0 | |
IndexInSheet |
positional | Shared 0-based content counter; slot 0 omitted; -1 on header/system records |
LineWidth |
1 | Except TextFrame (0) |
Color / AreaColor |
0 (black) | Absent colour keys read as 0 on every record (Altium omits zero colours) |
SecondaryRadius |
= Radius |
Ellipse, EllipticalArc |
PartCount |
stored − 1 | No floor at 1 |
| Booleans | false | Only =T is ever written |
A symbol read from a file is written back in its own record order, because that is the order
the shared IndexInSheet counter numbers and Altium interleaves the kinds freely.
A symbol with no record order of its own — one built in memory — is written kind by kind, in the
order below (the shared IndexInSheet counter runs across steps 2-17; the designator and system
parameters keep the -1 sentinel and consume no slot):
- Component header (RECORD=1)
- Rectangles (RECORD=14) — before the pins so a solid body does not paint over pin names
- Pins (binary records; each consumes an
IndexInSheetslot) - Lines (RECORD=13)
- Polylines (RECORD=6)
- Polygons (RECORD=7)
- Arcs (RECORD=12)
- Pies (RECORD=9)
- Images (RECORD=30)
- Text frames (RECORD=28)
- Bezier curves (RECORD=5)
- Ellipses (RECORD=8)
- Rounded rectangles (RECORD=10)
- Elliptical arcs (RECORD=11)
- Labels (RECORD=4)
- IEEE symbols (RECORD=3)
- User parameters (RECORD=41,
OwnerPartId >= 1) — after the graphic content, matching the golden stream order (JUSTIFY stores labels at slots 0-3, user parameters at 4-5) - Designator (RECORD=34, when non-empty)
- System parameters (RECORD=41,
OwnerPartId = -1) — after the designator, as the golden orders them - Implementation list (RECORD=44), then per footprint model: RECORD=45 + RECORD=46 + RECORD=48
Steps 18-20 keep their positions either way: the designator, the system parameters and the implementation list follow the content records regardless of how those were ordered.
The stream ends with the last record's payload — there is no trailing end marker (see the Data Stream Format section and issue #68).
Some symbols have multiple parts (e.g. quad op-amp):
PartCountin the component header indicates total parts (stored as count + 1)- Each primitive has an
OwnerPartIdfield:-1= belongs to all parts1+= belongs to a specific part
- Pin text format (RECORD=2): rare; skipped on read (binary pins are authoritative)
- Pin symbol decorations: supported (22 symbol types at 4 positions)
- Display modes: count in
DisplayModeCount; primitives carryOwnerPartDisplayMode - Font storage: fonts defined in FileHeader (
FontName{N},Size{N}) - Unique IDs: text records carry an 8-char alphanumeric
UniqueIDas their last key — except a pie and an IEEE symbol, which Altium writes without one (and are given none) - Embedded images:
RECORD=30metadata + zlib payloads in/Storage, order-matched
- AltiumSharp - C# library for Altium files (MIT)
- pyAltiumLib - Python library for reading Altium files
- python-altium - Altium format documentation