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
// 纯 MoonBit GIF 解码器
// 支持 GIF89a/GIF87a 单帧解码(RGB,channels=3)
// 规范: GIF89a Specification + src/format/gif_encode.mbt
// 单帧解码委托 decode_gif_animation_pure 取第一帧
///|
/// LZW 解码(LSB 优先变长码)
/// 返回颜色索引序列
fn lzw_decode(
data : Array[Byte],
min_code_size : Int,
) -> Array[Int] raise @types.LoadError {
let clear_code = 1 << min_code_size
let end_code = clear_code + 1
let mut code_width = min_code_size + 1
let mut dict : Array[Array[Int]] = []
for i in 0..<clear_code {
dict.push([i])
}
dict.push([])
dict.push([])
let output : Array[Int] = []
let mut bit_buffer = 0
let mut bit_count = 0
let mut data_pos = 0
let mut prev : Int = -1
let data_len = data.length()
let mut done = false
while !done {
while bit_count < code_width {
if data_pos >= data_len {
done = true
break
}
bit_buffer = bit_buffer | (data[data_pos].to_int() << bit_count)
bit_count += 8
data_pos += 1
}
if done {
break
}
let code = bit_buffer & ((1 << code_width) - 1)
bit_buffer = bit_buffer >> code_width
bit_count -= code_width
if code == clear_code {
dict = []
for i in 0..<clear_code {
dict.push([i])
}
dict.push([])
dict.push([])
code_width = min_code_size + 1
prev = -1
} else if code == end_code {
done = true
} else {
let entry : Array[Int] = if code < dict.length() {
dict[code]
} else if code == dict.length() && prev >= 0 {
let prev_entry = dict[prev]
let new_entry : Array[Int] = []
for v in prev_entry {
new_entry.push(v)
}
new_entry.push(prev_entry[0])
new_entry
} else {
raise @types.LoadError::DecodeFailed(
"GIF LZW 解码错误:code 超出字典范围",
)
}
for v in entry {
output.push(v)
}
if prev >= 0 {
let prev_entry = dict[prev]
let new_entry : Array[Int] = []
for v in prev_entry {
new_entry.push(v)
}
new_entry.push(entry[0])
dict.push(new_entry)
if dict.length() == 1 << code_width && code_width < 12 {
code_width += 1
}
}
prev = code
}
}
output
}
///|
/// 解码 GIF 字节流为 Image
/// 支持 GIF89a/GIF87a 单帧解码(RGB,channels=3)
/// 不支持 interlace(packed bit6=1 时 raise LoadError)
/// 委托 decode_gif_animation_pure 取第一帧
pub fn decode_gif_pure(data : Bytes) -> @types.Image raise @types.LoadError {
let anim = decode_gif_animation_pure(data)
if anim.frames.length() == 0 {
raise @types.LoadError::DecodeFailed("GIF 无有效帧")
}
anim.frames[0]
}