]> git.draconx.ca Git - liblbx.git/blob - doc/txt/image-format.txt
lbximg: Fix wart in frame scanline header format
[liblbx.git] / doc / txt / image-format.txt
1 LBX Images:
2
3 This document describes the LBX image format used in Moo2.  The goal is that
4 the code to decode images in liblbx can be written against this specification,
5 thus guiding the implementation.
6
7 All multi-byte integer types are stored in the image file from
8 least-significant to most-significant byte.  This document uses the names
9 "uint8", "uint16" and "uint32" to refer to 8-bit, 16-bit and 32-bit unsigned
10 integers, respectively.
11
12 LBX Images begin with a 12-byte header which has the following layout:
13
14   OFFSET   TYPE     DESCRIPTION
15   -----------------------------------------------------
16        0   uint16   Image width in pixels
17        2   uint16   Image height in pixels
18        4   uint16   Unknown (always 0?)
19        6   uint8    Number of frames
20        7   uint8    Unknown (always 0?)
21        8   uint8    Lead-in (less than the frame count)
22        9   uint8    Chunk size
23       10   uint16   Flags
24
25 Immediately following the header is an sequence of uint32 offsets (one for
26 each frame) indicating the start of each frame, followed by a final uint32
27 offset which marks the end of the file.
28
29 The frame count, lead-in and chunk size describe how the image is animated,
30 which is described later.  The flags value is the bitwise-OR of zero or more
31 of the following values:
32
33   VALUE   NAME        DESCRIPTION
34   ----------------------------------------------------------------------------
35   0x0100  raw         If set, this flag enables a simpler method of storing
36                       frame data in the image.
37   0x0400  overwrite   If set, behave as if the chunk size was 1 instead of its
38                       actual value.
39   0x0800  building    Unknown.  This flag is set on the building images
40                       (perhaps to enable a special blending mode for shadows).
41   0x1000  palette     If set, the image contains embedded palette data.
42   0x2000  loop        If set, behave as if the lead-in was 0 instead of its
43                       actual value.
44
45 If the palette flag is set, the palette data follows the frame offsets.  The
46 palette has a 4-byte header:
47
48   OFFSET   TYPE     DESCRIPTION
49   -----------------------------------------------------
50        0   uint16   Index of the first embedded palette entry
51        2   uint16   Number of embedded palette entries.
52
53 The sum of these two values must not exceed 256.  Immediately following the
54 palette header are the palette entries.  Each palette entry is 4 bytes with
55 the following layout:
56
57   OFFSET   TYPE     DESCRIPTION
58   -----------------------------------------------------
59        0   uint8    Always 1.
60        1   uint8    Red component   (0-63)
61        2   uint8    Green component (0-63)
62        3   uint8    Blue component  (0-63)
63
64 Note that component values are stored as an 8-bit integer but only range
65 from 0-63 (6 bits per channel), with (0, 0, 0) being the darkest black and
66 (63, 63, 63) the brightest white.  The values in the image's embedded palette
67 supersede the values in the "main" palette.
68
69 Image data:
70
71 Each LBX image consists of one or more frames.  The start of each frame
72 can be found by seeking to the appropriate offset in the file, as described
73 above.
74
75 There are two main methods of encoding frame data.  The simplest is the raw
76 encoding, which is used when the "raw" flag (0x0100) is set in the header.
77 In raw encoding, the pixel data for the entire frame is stored verbatim in
78 row-major order (one uint8 value per pixel).  There are no headers to parse
79 within the frame, and this format does not support transparency as each frame
80 specifies a palette index for every pixel in the image.
81
82 For example, a 3x2 raw image has exactly 6 bytes per frame, with the pixels
83 laid out as in the following format.  The numbers represent byte offsets
84 within the file:
85
86   +---+---+---+
87   | 0 | 1 | 2 |
88   +---+---+---+
89   | 3 | 4 | 5 |
90   +---+---+---+
91
92 The more common method is a line-based encoding, which is more flexible.
93 In this format, a cursor is maintained to track where pixel data is to be
94 written.  The X value of the cursor specifies the number of pixels right
95 from the left edge of the image, and the Y value of the cursor specifies
96 the number of pixels down from the top edge of the image.
97
98 Each frame in this encoding begins with a header.
99
100   OFFSET   TYPE     DESCRIPTION
101   -----------------------------------------------------
102        0   uint16   Always 1.
103        2   uint16   Initial Y position of cursor.
104
105 The cursor has an initial X value of 0.  Immediately following the header
106 is a sequence of one or more drawing commands.  Each command consists of a
107 2-byte header.
108
109   OFFSET   TYPE     DESCRIPTION
110   -----------------------------------------------------
111        0   uint16   Length: number of pixels to follow
112        2   uint16   Cursor offset
113
114 If length is non-zero, first the offset is added to the current X value of the
115 cursor, then the pixel data (1 byte per pixel) follows and is drawn starting
116 at the current cursor position, with successive pixels increasing in X value.
117 The cursor is updated as pixels are drawn.  In general, new pixel data
118 supersedes any previous value for a particular pixel.  Pixels that have no
119 data specified are transparent.  Animated images may re-use pixel values from
120 the previous frame, see below for details.
121
122 If length is odd, there is a padding byte after the last pixel which must be
123 skipped.
124
125 If length is 0, then the offset is added to the Y value of the cursor, the X
126 value of the cursor is reset to 0, and no pixel data follows.
127
128 Notwithstanding the above, if both length is 0 and offset is exactly 1000,
129 then there are no further drawing commands in this frame.
130
131 Animation:
132
133 There are 3 parameters relevant to animations found in the image header: the
134 frame count, the lead-in, and the chunk size.  Frame count specifies the total
135 number of frames in the image, chunk size affects how frames are decoded and
136 the lead-in affects how animations are displayed.
137
138 Normally, each decoded frame is drawn on top of the previous frame, with the
139 first frame drawn on a fully transparent slate.  So if the first frame has any
140 unspecified pixel values, those pixels are transparent, while if the second
141 frame has any unspecified pixel values, those pixels retain the value from the
142 first frame (transparent or otherwise).
143
144 However, if the chunk size is set to a non-zero value, then the slate is reset
145 to a fully transparent state when decoding a frame number which is divisible
146 by the chunk size.  So if this is set to 1, every frame must specify all
147 non-transparent pixels as they will each be drawn on top of a transparent
148 slate (just like the first frame).  This parameter is the only way for pixels
149 which are opaque in one frame to become transparent in the next.
150
151 The lead-in specifies the frame to be displayed after the last frame in an
152 animation.  If this is different from the last frame, then the result is a
153 looping animation.  If this is the same as the last frame, then the result is
154 an animation that stops at the end.