-
-
Notifications
You must be signed in to change notification settings - Fork 181
/
gif.hexpat
185 lines (157 loc) · 5.06 KB
/
gif.hexpat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#pragma description GIF image
#pragma MIME image/gif
// Extension Labels
#define LABEL_GC 0xF9
#define LABEL_COMMENT 0xFE
#define LABEL_APPLICATION 0xFF
#define LABEL_PLAINTEXT 0x01
// Indentifier Magics
#define IMAGE_SEPERATOR_MAGIC 0x2C
#define EXTENSION_INTRODUCER_MAGIC 0x21
#define GIF_TRAILER_MAGIC 0x3B
import std.io;
import std.core;
import std.mem;
import std.string;
import std.math;
import type.magic;
bitfield GCT_Flags {
size : 3 [[comment("physical size = 2^(flags.size + 1)")]];
sort : 1 [[comment("Indicates if the table is sorted by importance")]];
colorRes : 3 [[comment("Indicates the richness of the original pallet")]];
enabled : 1;
};
bitfield ImageDescriptorFlags {
lctSize: 3;
reserved: 2;
lctSort: 1;
interlaceFlag: 1;
lctEnable: 1;
};
bitfield GCE_Flags {
transparent : 1;
userInput : 1;
disposalMode : 3 [[format("format::dispose_enum")]];
reserved : 3;
};
struct Color {
u8 red;
u8 green;
u8 blue;
} [[color(std::format("{:02X}{:02X}{:02X}", red, green, blue))]];
struct _SubBlocks {
u8 data_size;
u8 data[data_size];
};
struct DataSubBlocks {
_SubBlocks subBlocks[while(std::mem::read_unsigned($, 1) != 0)];
};
struct Header {
type::Magic<"GIF"> magic;
char version[3];
};
struct LogicalScreenDescriptor {
u16 width;
u16 height;
GCT_Flags gctFlags;
u8 bgColorIndex;
u8 pixelAscpet;
if (gctFlags.enabled) {
Color gct[std::math::pow(2, gctFlags.size + 1)];
}
};
struct ImageDescriptor {
u16 imageLeftPosition;
u16 imageTopPosition;
u16 imageWidth;
u16 imageHeight;
ImageDescriptorFlags flags;
if(flags.lctEnable) {
Color lct[std::math::pow(2, flags.lctSize + 1)];
}
u8 lzwMinCode [[comment("This byte determines the initial number of bits used for LZW codes in the image data")]];
DataSubBlocks lzwCompressedData [[comment("Data is pallet indecies either into current LDC or GCT and is compressed using LZW")]];
};
struct CommentExtension {
DataSubBlocks commentData;
};
struct ApplicationExtension {
u8 blockSize;
char identifier[8];
char authenticationCode[3];
DataSubBlocks applicationData;
};
struct PlainTextExtension {
u8 blockSize;
u16 textGridLeftPos;
u16 textGridTopPos;
u16 textGridWidth;
u16 textGridHeight;
u8 charCellWidth;
u8 charCellHeight;
u8 textForegroundColorIndex;
u8 textBackgroundColorIndex;
DataSubBlocks plainTextData;
};
struct GraphicControlExtension {
u8 blockSize;
std::assert_warn(blockSize == 4, "Unexpected GCE block size");
GCE_Flags flags;
u16 delay [[format("format::delay")]];
u8 transparentColorIndex;
};
struct Extension {
u8 label [[format("format::extension_name")]];
if(label == LABEL_GC) GraphicControlExtension gce [[inline]];
if(label == LABEL_COMMENT) CommentExtension c [[inline]];
if(label == LABEL_APPLICATION) ApplicationExtension a [[inline]];
if(label == LABEL_PLAINTEXT) PlainTextExtension p [[inline]];
};
struct Block {
u8 identifier [[format("format::identifier_name")]];
if(identifier == IMAGE_SEPERATOR_MAGIC) ImageDescriptor i [[inline]];
if(identifier == EXTENSION_INTRODUCER_MAGIC) Extension e [[inline]];
if(identifier == GIF_TRAILER_MAGIC) break;
u8 blockTerminator;
} [[format("format::block_name")]];
namespace format {
fn dispose_enum(u8 value) {
if(value == 0x00) return "Do nothing";
if(value == 0x01) return "Do not remove pixels";
if(value == 0x02) return "Restore background pixels";
if(value == 0x03) return "Restore previous pixels";
};
fn extension_name(u8 label) {
if(label == LABEL_GC) return "Graphical Control Extension";
if(label == LABEL_COMMENT) return "Comment Extension";
if(label == LABEL_APPLICATION) return "Application Extension";
if(label == LABEL_PLAINTEXT) return "Plaintext Extension";
return "Unknown Extension";
};
fn block_name(ref Block b) {
if(b.identifier == IMAGE_SEPERATOR_MAGIC) return "Image Descriptor";
if(b.identifier == EXTENSION_INTRODUCER_MAGIC) return "Extension";
if(b.identifier == GIF_TRAILER_MAGIC) return "Trailer";
return "Unknown Block Type";
};
fn identifier_name(u8 identifier) {
if(identifier == IMAGE_SEPERATOR_MAGIC) return "Image Separator";
if(identifier == EXTENSION_INTRODUCER_MAGIC) return "Extension Introducer";
if(identifier == GIF_TRAILER_MAGIC) return "GIF Trailer";
return "Unknown Identifier";
};
fn delay(u16 delay) {
if(delay == -1) return "forever";
else if(delay < 2) return "100ms";
else return std::string::to_string(delay * 10) + "ms";
return "notime";
};
}
struct Gif {
u8 data[std::mem::size()] [[no_unique_address, hidden]];
Header header;
std::assert_warn(header.version == "89a" || header.version == "87a", "Unsupported format version");
LogicalScreenDescriptor logicalScreenDescriptor;
Block blocks[while(!std::mem::eof())];
} [[hex::visualize("image", this.data)]];
Gif gif @ 0x00;