Serenity Operating System
1/*
2 * Copyright (c) 2021, the SerenityOS developers.
3 * Copyright (c) 2021, Brian Gianforcaro <bgianf@serenityos.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#include <AK/DeprecatedString.h>
9#include <LibCore/MappedFile.h>
10#include <LibGfx/BMPLoader.h>
11#include <LibGfx/GIFLoader.h>
12#include <LibGfx/ICOLoader.h>
13#include <LibGfx/ImageDecoder.h>
14#include <LibGfx/JPEGLoader.h>
15#include <LibGfx/PBMLoader.h>
16#include <LibGfx/PGMLoader.h>
17#include <LibGfx/PNGLoader.h>
18#include <LibGfx/PPMLoader.h>
19#include <LibGfx/TGALoader.h>
20#include <LibGfx/WebPLoader.h>
21#include <LibTest/TestCase.h>
22#include <stdio.h>
23#include <string.h>
24
25#ifdef AK_OS_SERENITY
26# define TEST_INPUT(x) ("/usr/Tests/LibGfx/test-inputs/" x)
27#else
28# define TEST_INPUT(x) ("test-inputs/" x)
29#endif
30
31TEST_CASE(test_bmp)
32{
33 auto file = MUST(Core::MappedFile::map(TEST_INPUT("rgba32-1.bmp"sv)));
34 EXPECT(Gfx::BMPImageDecoderPlugin::sniff(file->bytes()));
35 auto plugin_decoder = MUST(Gfx::BMPImageDecoderPlugin::create(file->bytes()));
36 EXPECT(plugin_decoder->initialize());
37
38 EXPECT(plugin_decoder->frame_count());
39 EXPECT(!plugin_decoder->is_animated());
40 EXPECT(!plugin_decoder->loop_count());
41
42 auto frame = MUST(plugin_decoder->frame(0));
43 EXPECT(frame.duration == 0);
44}
45
46TEST_CASE(test_gif)
47{
48 auto file = MUST(Core::MappedFile::map(TEST_INPUT("download-animation.gif"sv)));
49 EXPECT(Gfx::GIFImageDecoderPlugin::sniff(file->bytes()));
50 auto plugin_decoder = MUST(Gfx::GIFImageDecoderPlugin::create(file->bytes()));
51 EXPECT(plugin_decoder->initialize());
52
53 EXPECT(plugin_decoder->frame_count());
54 EXPECT(plugin_decoder->is_animated());
55 EXPECT(!plugin_decoder->loop_count());
56
57 auto frame = MUST(plugin_decoder->frame(1));
58 EXPECT(frame.duration == 400);
59}
60
61TEST_CASE(test_not_ico)
62{
63 auto file = MUST(Core::MappedFile::map(TEST_INPUT("buggie.png"sv)));
64 EXPECT(!Gfx::ICOImageDecoderPlugin::sniff(file->bytes()));
65 auto plugin_decoder = MUST(Gfx::ICOImageDecoderPlugin::create(file->bytes()));
66 EXPECT(!plugin_decoder->initialize());
67
68 EXPECT(plugin_decoder->frame_count());
69 EXPECT(!plugin_decoder->is_animated());
70 EXPECT(!plugin_decoder->loop_count());
71
72 EXPECT(plugin_decoder->frame(0).is_error());
73}
74
75TEST_CASE(test_bmp_embedded_in_ico)
76{
77 auto file = MUST(Core::MappedFile::map(TEST_INPUT("serenity.ico"sv)));
78 EXPECT(Gfx::ICOImageDecoderPlugin::sniff(file->bytes()));
79 auto plugin_decoder = MUST(Gfx::ICOImageDecoderPlugin::create(file->bytes()));
80 EXPECT(plugin_decoder->initialize());
81
82 EXPECT(plugin_decoder->frame_count());
83 EXPECT(!plugin_decoder->is_animated());
84 EXPECT(!plugin_decoder->loop_count());
85
86 EXPECT(!plugin_decoder->frame(0).is_error());
87}
88
89TEST_CASE(test_jpeg_sof0_one_scan)
90{
91 auto file = MUST(Core::MappedFile::map(TEST_INPUT("rgb24.jpg"sv)));
92 EXPECT(Gfx::JPEGImageDecoderPlugin::sniff(file->bytes()));
93 auto plugin_decoder = MUST(Gfx::JPEGImageDecoderPlugin::create(file->bytes()));
94 EXPECT(plugin_decoder->initialize());
95
96 EXPECT(plugin_decoder->frame_count());
97 EXPECT(!plugin_decoder->is_animated());
98 EXPECT(!plugin_decoder->loop_count());
99
100 auto frame = MUST(plugin_decoder->frame(0));
101 EXPECT(frame.duration == 0);
102}
103
104TEST_CASE(test_jpeg_sof0_several_scans)
105{
106 auto file = MUST(Core::MappedFile::map(TEST_INPUT("several_scans.jpg"sv)));
107 EXPECT(Gfx::JPEGImageDecoderPlugin::sniff(file->bytes()));
108 auto plugin_decoder = MUST(Gfx::JPEGImageDecoderPlugin::create(file->bytes()));
109 EXPECT(plugin_decoder->initialize());
110
111 auto frame = MUST(plugin_decoder->frame(0));
112 EXPECT_EQ(frame.image->size(), Gfx::IntSize(592, 800));
113}
114
115TEST_CASE(test_jpeg_rgb_components)
116{
117 auto file = MUST(Core::MappedFile::map(TEST_INPUT("rgb_components.jpg"sv)));
118 EXPECT(Gfx::JPEGImageDecoderPlugin::sniff(file->bytes()));
119 auto plugin_decoder = MUST(Gfx::JPEGImageDecoderPlugin::create(file->bytes()));
120 EXPECT(plugin_decoder->initialize());
121
122 auto frame = MUST(plugin_decoder->frame(0));
123 EXPECT_EQ(frame.image->size(), Gfx::IntSize(592, 800));
124}
125
126TEST_CASE(test_jpeg_sof2_spectral_selection)
127{
128 auto file = MUST(Core::MappedFile::map(TEST_INPUT("spectral_selection.jpg"sv)));
129 EXPECT(Gfx::JPEGImageDecoderPlugin::sniff(file->bytes()));
130 auto plugin_decoder = MUST(Gfx::JPEGImageDecoderPlugin::create(file->bytes()));
131 EXPECT(plugin_decoder->initialize());
132
133 auto frame = MUST(plugin_decoder->frame(0));
134 EXPECT_EQ(frame.image->size(), Gfx::IntSize(592, 800));
135}
136
137TEST_CASE(test_pbm)
138{
139 auto file = MUST(Core::MappedFile::map(TEST_INPUT("buggie-raw.pbm"sv)));
140 EXPECT(Gfx::PBMImageDecoderPlugin::sniff(file->bytes()));
141 auto plugin_decoder = MUST(Gfx::PBMImageDecoderPlugin::create(file->bytes()));
142 EXPECT(plugin_decoder->initialize());
143
144 EXPECT(plugin_decoder->frame_count());
145 EXPECT(!plugin_decoder->is_animated());
146 EXPECT(!plugin_decoder->loop_count());
147
148 auto frame = MUST(plugin_decoder->frame(0));
149 EXPECT(frame.duration == 0);
150}
151
152TEST_CASE(test_pgm)
153{
154 auto file = MUST(Core::MappedFile::map(TEST_INPUT("buggie-raw.pgm"sv)));
155 EXPECT(Gfx::PGMImageDecoderPlugin::sniff(file->bytes()));
156 auto plugin_decoder = MUST(Gfx::PGMImageDecoderPlugin::create(file->bytes()));
157 EXPECT(plugin_decoder->initialize());
158
159 EXPECT(plugin_decoder->frame_count());
160 EXPECT(!plugin_decoder->is_animated());
161 EXPECT(!plugin_decoder->loop_count());
162
163 auto frame = MUST(plugin_decoder->frame(0));
164 EXPECT(frame.duration == 0);
165}
166
167TEST_CASE(test_png)
168{
169 auto file = MUST(Core::MappedFile::map(TEST_INPUT("buggie.png"sv)));
170 EXPECT(Gfx::PNGImageDecoderPlugin::sniff(file->bytes()));
171 auto plugin_decoder = MUST(Gfx::PNGImageDecoderPlugin::create(file->bytes()));
172 EXPECT(plugin_decoder->initialize());
173
174 EXPECT(plugin_decoder->frame_count());
175 EXPECT(!plugin_decoder->is_animated());
176 EXPECT(!plugin_decoder->loop_count());
177
178 auto frame = MUST(plugin_decoder->frame(0));
179 EXPECT(frame.duration == 0);
180}
181
182TEST_CASE(test_ppm)
183{
184 auto file = MUST(Core::MappedFile::map(TEST_INPUT("buggie-raw.ppm"sv)));
185 EXPECT(Gfx::PPMImageDecoderPlugin::sniff(file->bytes()));
186 auto plugin_decoder = MUST(Gfx::PPMImageDecoderPlugin::create(file->bytes()));
187 EXPECT(plugin_decoder->initialize());
188
189 EXPECT(plugin_decoder->frame_count());
190 EXPECT(!plugin_decoder->is_animated());
191 EXPECT(!plugin_decoder->loop_count());
192
193 auto frame = MUST(plugin_decoder->frame(0));
194 EXPECT(frame.duration == 0);
195}
196
197TEST_CASE(test_targa_bottom_left)
198{
199 auto file = MUST(Core::MappedFile::map(TEST_INPUT("buggie-bottom-left-uncompressed.tga"sv)));
200 EXPECT(MUST(Gfx::TGAImageDecoderPlugin::validate_before_create(file->bytes())));
201 auto plugin_decoder = MUST(Gfx::TGAImageDecoderPlugin::create(file->bytes()));
202 EXPECT(plugin_decoder->initialize());
203
204 EXPECT_EQ(plugin_decoder->frame_count(), 1u);
205 EXPECT(!plugin_decoder->is_animated());
206 EXPECT(!plugin_decoder->loop_count());
207
208 auto frame = MUST(plugin_decoder->frame(0));
209 EXPECT(frame.duration == 0);
210}
211
212TEST_CASE(test_targa_top_left)
213{
214 auto file = MUST(Core::MappedFile::map(TEST_INPUT("buggie-top-left-uncompressed.tga"sv)));
215 EXPECT(MUST(Gfx::TGAImageDecoderPlugin::validate_before_create(file->bytes())));
216 auto plugin_decoder = MUST(Gfx::TGAImageDecoderPlugin::create(file->bytes()));
217 EXPECT(plugin_decoder->initialize());
218
219 EXPECT_EQ(plugin_decoder->frame_count(), 1u);
220 EXPECT(!plugin_decoder->is_animated());
221 EXPECT(!plugin_decoder->loop_count());
222
223 auto frame = MUST(plugin_decoder->frame(0));
224 EXPECT(frame.duration == 0);
225}
226
227TEST_CASE(test_targa_bottom_left_compressed)
228{
229 auto file = MUST(Core::MappedFile::map(TEST_INPUT("buggie-bottom-left-compressed.tga"sv)));
230 EXPECT(MUST(Gfx::TGAImageDecoderPlugin::validate_before_create(file->bytes())));
231 auto plugin_decoder = MUST(Gfx::TGAImageDecoderPlugin::create(file->bytes()));
232 EXPECT(plugin_decoder->initialize());
233
234 EXPECT_EQ(plugin_decoder->frame_count(), 1u);
235 EXPECT(!plugin_decoder->is_animated());
236 EXPECT(!plugin_decoder->loop_count());
237
238 auto frame = MUST(plugin_decoder->frame(0));
239 EXPECT(frame.duration == 0);
240}
241
242TEST_CASE(test_targa_top_left_compressed)
243{
244 auto file = MUST(Core::MappedFile::map(TEST_INPUT("buggie-top-left-compressed.tga"sv)));
245 EXPECT(MUST(Gfx::TGAImageDecoderPlugin::validate_before_create(file->bytes())));
246 auto plugin_decoder = MUST(Gfx::TGAImageDecoderPlugin::create(file->bytes()));
247 EXPECT(plugin_decoder->initialize());
248
249 EXPECT_EQ(plugin_decoder->frame_count(), 1u);
250 EXPECT(!plugin_decoder->is_animated());
251 EXPECT(!plugin_decoder->loop_count());
252
253 auto frame = MUST(plugin_decoder->frame(0));
254 EXPECT(frame.duration == 0);
255}
256
257TEST_CASE(test_webp_simple_lossy)
258{
259 auto file = MUST(Core::MappedFile::map(TEST_INPUT("simple-vp8.webp"sv)));
260 EXPECT(Gfx::WebPImageDecoderPlugin::sniff(file->bytes()));
261 auto plugin_decoder = MUST(Gfx::WebPImageDecoderPlugin::create(file->bytes()));
262 EXPECT(plugin_decoder->initialize());
263
264 EXPECT_EQ(plugin_decoder->frame_count(), 1u);
265 EXPECT(!plugin_decoder->is_animated());
266 EXPECT(!plugin_decoder->loop_count());
267
268 EXPECT_EQ(plugin_decoder->size(), Gfx::IntSize(240, 240));
269}
270
271TEST_CASE(test_webp_simple_lossless)
272{
273 auto file = MUST(Core::MappedFile::map(TEST_INPUT("simple-vp8l.webp"sv)));
274 EXPECT(Gfx::WebPImageDecoderPlugin::sniff(file->bytes()));
275 auto plugin_decoder = MUST(Gfx::WebPImageDecoderPlugin::create(file->bytes()));
276 EXPECT(plugin_decoder->initialize());
277
278 EXPECT_EQ(plugin_decoder->frame_count(), 1u);
279 EXPECT(!plugin_decoder->is_animated());
280 EXPECT(!plugin_decoder->loop_count());
281
282 EXPECT_EQ(plugin_decoder->size(), Gfx::IntSize(386, 395));
283}
284
285TEST_CASE(test_webp_extended_lossy)
286{
287 auto file = MUST(Core::MappedFile::map(TEST_INPUT("extended-lossy.webp"sv)));
288 EXPECT(Gfx::WebPImageDecoderPlugin::sniff(file->bytes()));
289 auto plugin_decoder = MUST(Gfx::WebPImageDecoderPlugin::create(file->bytes()));
290 EXPECT(plugin_decoder->initialize());
291
292 EXPECT_EQ(plugin_decoder->frame_count(), 1u);
293 EXPECT(!plugin_decoder->is_animated());
294 EXPECT(!plugin_decoder->loop_count());
295
296 EXPECT_EQ(plugin_decoder->size(), Gfx::IntSize(417, 223));
297}
298
299TEST_CASE(test_webp_extended_lossless)
300{
301 auto file = MUST(Core::MappedFile::map(TEST_INPUT("extended-lossless.webp"sv)));
302 EXPECT(Gfx::WebPImageDecoderPlugin::sniff(file->bytes()));
303 auto plugin_decoder = MUST(Gfx::WebPImageDecoderPlugin::create(file->bytes()));
304 EXPECT(plugin_decoder->initialize());
305
306 EXPECT_EQ(plugin_decoder->frame_count(), 1u);
307 EXPECT(!plugin_decoder->is_animated());
308 EXPECT(!plugin_decoder->loop_count());
309
310 EXPECT_EQ(plugin_decoder->size(), Gfx::IntSize(417, 223));
311}
312
313TEST_CASE(test_webp_extended_lossless_animated)
314{
315 auto file = MUST(Core::MappedFile::map(TEST_INPUT("extended-lossless-animated.webp"sv)));
316 EXPECT(Gfx::WebPImageDecoderPlugin::sniff(file->bytes()));
317 auto plugin_decoder = MUST(Gfx::WebPImageDecoderPlugin::create(file->bytes()));
318 EXPECT(plugin_decoder->initialize());
319
320 EXPECT_EQ(plugin_decoder->frame_count(), 8u);
321 EXPECT(plugin_decoder->is_animated());
322 EXPECT_EQ(plugin_decoder->loop_count(), 42u);
323
324 EXPECT_EQ(plugin_decoder->size(), Gfx::IntSize(990, 1050));
325}