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
///|
/// 解码结果值对象,承载图像几何元信息与像素数据(8-bit 无符号像素)
pub(all) struct Image {
width : Int
height : Int
channels : Int
data : Bytes
} derive(Eq, @debug.Debug)
///|
/// 16-bit 解码结果值对象,像素数据为 16-bit 无符号整数(little-endian,每像素 2 字节)
pub(all) struct Image16 {
width : Int
height : Int
channels : Int
data : Bytes
} derive(Eq, @debug.Debug)
///|
/// HDR float 解码结果值对象,像素数据为 32-bit IEEE float(little-endian,每像素 4 字节)
pub(all) struct ImageF {
width : Int
height : Int
channels : Int
data : Bytes
} derive(Eq, @debug.Debug)
///|
/// 图像信息查询结果,仅含几何元信息,不加载像素数据
pub(all) struct ImageInfo {
width : Int
height : Int
channels : Int
} derive(Eq, @debug.Debug)
///|
/// 动画 GIF 解码结果,包含多帧图像和每帧延迟(毫秒)
pub(all) struct GifAnimation {
frames : Array[Image]
delays : Array[Int]
} derive(Eq, @debug.Debug)
///|
/// 加载失败领域错误
pub(all) suberror LoadError {
FileIO(String)
UnsupportedFormat(String)
DecodeFailed(String)
EncodeFailed(String)
}
///|
/// 图像格式枚举
pub(all) enum ImageFormat {
Png
Jpeg
Bmp
Gif
Tga
Psd
Hdr
Pnm
Qoi
Webp
Tiff
Ico
Cur
Icns
Apng
Avif
Heif
JpegXl
Unknown
} derive(Eq, @debug.Debug)
///|
/// resize 滤波器类型
pub(all) enum ResizeFilter {
Default
Box
Triangle
CubicBSPline
CatmullROM
Mitchell
PointSample
} derive(Eq, @debug.Debug)
///|
/// resize 边缘处理模式
pub(all) enum ResizeEdge {
Clamp
Reflect
Wrap
Zero
} derive(Eq, @debug.Debug)
///|
/// APNG 动画解码结果
pub(all) struct PngAnimation {
frames : Array[Image]
delays : Array[Int] // 毫秒
} derive(Eq, @debug.Debug)
///|
/// 图像维度上限(单边最大像素数)。
/// 防止恶意图像声明超大尺寸导致 OOM 或整数溢出。
/// 65535 覆盖常见图像格式最大尺寸(PNG/TIFF 32-bit、JPEG 65500、BMP 32-bit)。
pub const MAX_IMAGE_DIMENSION : Int = 65535
///|
/// 校验图像维度是否在安全范围内。
/// 检查 width/height 为正数且不超过 MAX_IMAGE_DIMENSION,
/// 且 width * height * channels 不超过 Int 最大值(防溢出)。
/// 校验失败时 raise LoadError::DecodeFailed。
pub fn check_dims(
width : Int,
height : Int,
channels : Int,
) -> Unit raise LoadError {
if width <= 0 || height <= 0 || channels <= 0 {
raise LoadError::DecodeFailed(
"图像尺寸无效: width=\{width}, height=\{height}, channels=\{channels}",
)
}
if width > MAX_IMAGE_DIMENSION || height > MAX_IMAGE_DIMENSION {
raise LoadError::DecodeFailed(
"图像尺寸超过上限 \{MAX_IMAGE_DIMENSION}: width=\{width}, height=\{height}",
)
}
// 检查 width * height * channels 是否溢出
// Int 在 wasm/native 为 32 位有符号,最大值 2147483647
// 先算 width * height,再乘 channels
let max_int = 2147483647
if width > max_int / height {
raise LoadError::DecodeFailed(
"图像像素总数溢出: \{width} * \{height}",
)
}
let pixel_count = width * height
if pixel_count > max_int / channels {
raise LoadError::DecodeFailed(
"图像数据大小溢出: \{pixel_count} * \{channels}",
)
}
}
///|
/// 安全乘法:返回 a * b,溢出时返回 None。
/// 用于在分配大数组前检查是否会溢出。
pub fn safe_mul(a : Int, b : Int) -> Int? {
if a <= 0 || b <= 0 {
return Some(0)
}
let max_int = 2147483647
if a > max_int / b {
None
} else {
Some(a * b)
}
}
///|
/// 安全三参数乘法:返回 a * b * c,溢出时返回 None。
/// 常用于计算 w * h * channels 的数组大小。
pub fn safe_mul3(a : Int, b : Int, c : Int) -> Int? {
match safe_mul(a, b) {
Some(ab) =>
match safe_mul(ab, c) {
Some(result) => Some(result)
None => None
}
None => None
}
}