FreeRDP
Loading...
Searching...
No Matches
TestImage.c
1#include <stdio.h>
2#include <winpr/string.h>
3#include <winpr/assert.h>
4#include <winpr/file.h>
5#include <winpr/path.h>
6#include <winpr/image.h>
7
8static const char test_src_filename[] = TEST_SOURCE_PATH "/rgb";
9static const char test_bin_filename[] = TEST_BINARY_PATH "/rgb";
10
11static BOOL test_image_equal(const wImage* imageA, const wImage* imageB)
12{
13 return winpr_image_equal(imageA, imageB,
14 WINPR_IMAGE_CMP_IGNORE_DEPTH | WINPR_IMAGE_CMP_IGNORE_ALPHA |
15 WINPR_IMAGE_CMP_FUZZY);
16}
17
18static BOOL test_equal_to(const wImage* bmp, const char* name, UINT32 format)
19{
20 BOOL rc = FALSE;
21 wImage* cmp = winpr_image_new();
22 if (!cmp)
23 goto fail;
24
25 char path[MAX_PATH] = WINPR_C_ARRAY_INIT;
26 (void)_snprintf(path, sizeof(path), "%s.%s", name, winpr_image_format_extension(format));
27 const int cmpSize = winpr_image_read(cmp, path);
28 if (cmpSize <= 0)
29 {
30 (void)fprintf(stderr, "[%s] winpr_image_read failed for %s", __func__, path);
31 goto fail;
32 }
33
34 rc = test_image_equal(bmp, cmp);
35 if (!rc)
36 (void)fprintf(stderr, "[%s] winpr_image_eqal failed", __func__);
37
38fail:
39 winpr_image_free(cmp, TRUE);
40 return rc;
41}
42
43static BOOL test_equal(void)
44{
45 BOOL rc = FALSE;
46 wImage* bmp = winpr_image_new();
47
48 if (!bmp)
49 goto fail;
50
51 char path[MAX_PATH] = WINPR_C_ARRAY_INIT;
52 (void)_snprintf(path, sizeof(path), "%s.bmp", test_src_filename);
53 PathCchConvertStyleA(path, sizeof(path), PATH_STYLE_NATIVE);
54
55 const int bmpSize = winpr_image_read(bmp, path);
56 if (bmpSize <= 0)
57 {
58 (void)fprintf(stderr, "[%s] winpr_image_read failed for %s", __func__, path);
59 goto fail;
60 }
61
62 for (UINT32 x = 0; x < UINT8_MAX; x++)
63 {
64 if (!winpr_image_format_is_supported(x))
65 continue;
66 if (!test_equal_to(bmp, test_src_filename, x))
67 goto fail;
68 }
69
70 rc = TRUE;
71fail:
72 winpr_image_free(bmp, TRUE);
73
74 return rc;
75}
76
77static BOOL test_read_write_compare(const char* tname, const char* tdst, UINT32 format)
78{
79 BOOL rc = FALSE;
80 wImage* bmp1 = winpr_image_new();
81 wImage* bmp2 = winpr_image_new();
82 wImage* bmp3 = winpr_image_new();
83 if (!bmp1 || !bmp2 || !bmp3)
84 goto fail;
85
86 char spath[MAX_PATH] = WINPR_C_ARRAY_INIT;
87 char dpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
88 char bpath1[MAX_PATH] = WINPR_C_ARRAY_INIT;
89 char bpath2[MAX_PATH] = WINPR_C_ARRAY_INIT;
90 (void)_snprintf(spath, sizeof(spath), "%s.%s", tname, winpr_image_format_extension(format));
91 (void)_snprintf(dpath, sizeof(dpath), "%s.%s", tdst, winpr_image_format_extension(format));
92 (void)_snprintf(bpath1, sizeof(bpath1), "%s.src.%s", dpath,
93 winpr_image_format_extension(WINPR_IMAGE_BITMAP));
94 (void)_snprintf(bpath2, sizeof(bpath2), "%s.bin.%s", dpath,
95 winpr_image_format_extension(WINPR_IMAGE_BITMAP));
96 PathCchConvertStyleA(spath, sizeof(spath), PATH_STYLE_NATIVE);
97 PathCchConvertStyleA(dpath, sizeof(dpath), PATH_STYLE_NATIVE);
98 PathCchConvertStyleA(bpath1, sizeof(bpath1), PATH_STYLE_NATIVE);
99 PathCchConvertStyleA(bpath2, sizeof(bpath2), PATH_STYLE_NATIVE);
100
101 const int bmpRSize = winpr_image_read(bmp1, spath);
102 if (bmpRSize <= 0)
103 {
104 (void)fprintf(stderr, "[%s] winpr_image_read failed for %s", __func__, spath);
105 goto fail;
106 }
107
108 const int bmpWSize = winpr_image_write(bmp1, dpath);
109 if (bmpWSize <= 0)
110 {
111 (void)fprintf(stderr, "[%s] winpr_image_write failed for %s", __func__, dpath);
112 goto fail;
113 }
114
115 const int bmp2RSize = winpr_image_read(bmp2, dpath);
116 if (bmp2RSize <= 0)
117 {
118 (void)fprintf(stderr, "[%s] winpr_image_read failed for %s", __func__, dpath);
119 goto fail;
120 }
121
122 const int bmpSrcWSize = winpr_image_write_ex(bmp1, WINPR_IMAGE_BITMAP, bpath1);
123 if (bmpSrcWSize <= 0)
124 {
125 (void)fprintf(stderr, "[%s] winpr_image_write_ex failed for %s", __func__, bpath1);
126 goto fail;
127 }
128
129 /* write a bitmap and read it back.
130 * this tests if we have the proper internal format */
131 const int bmpBinWSize = winpr_image_write_ex(bmp2, WINPR_IMAGE_BITMAP, bpath2);
132 if (bmpBinWSize <= 0)
133 {
134 (void)fprintf(stderr, "[%s] winpr_image_write_ex failed for %s", __func__, bpath2);
135 goto fail;
136 }
137
138 const int bmp3RSize = winpr_image_read(bmp3, bpath2);
139 if (bmp3RSize <= 0)
140 {
141 (void)fprintf(stderr, "[%s] winpr_image_read failed for %s", __func__, bpath2);
142 goto fail;
143 }
144
145 if (!winpr_image_equal(bmp1, bmp2,
146 WINPR_IMAGE_CMP_IGNORE_DEPTH | WINPR_IMAGE_CMP_IGNORE_ALPHA |
147 WINPR_IMAGE_CMP_FUZZY))
148 {
149 (void)fprintf(stderr, "[%s] winpr_image_eqal failed bmp1 bmp2", __func__);
150 goto fail;
151 }
152
153 rc = winpr_image_equal(bmp3, bmp2,
154 WINPR_IMAGE_CMP_IGNORE_DEPTH | WINPR_IMAGE_CMP_IGNORE_ALPHA |
155 WINPR_IMAGE_CMP_FUZZY);
156 if (!rc)
157 (void)fprintf(stderr, "[%s] winpr_image_eqal failed bmp3 bmp2", __func__);
158fail:
159 winpr_image_free(bmp1, TRUE);
160 winpr_image_free(bmp2, TRUE);
161 winpr_image_free(bmp3, TRUE);
162 return rc;
163}
164
165static BOOL test_read_write(void)
166{
167 BOOL rc = TRUE;
168 for (UINT32 x = 0; x < UINT8_MAX; x++)
169 {
170 if (!winpr_image_format_is_supported(x))
171 continue;
172 if (!test_read_write_compare(test_src_filename, test_bin_filename, x))
173 rc = FALSE;
174 }
175 return rc;
176}
177
178static BOOL test_load_file(const char* name)
179{
180 BOOL rc = FALSE;
181 wImage* image = winpr_image_new();
182 if (!image || !name)
183 goto fail;
184
185 const int res = winpr_image_read(image, name);
186 rc = (res > 0);
187
188fail:
189 winpr_image_free(image, TRUE);
190 return rc;
191}
192
193static void put_u16(BYTE* p, UINT16 v)
194{
195 p[0] = (BYTE)(v & 0xff);
196 p[1] = (BYTE)((v >> 8) & 0xff);
197}
198
199static void put_u32(BYTE* p, UINT32 v)
200{
201 p[0] = (BYTE)(v & 0xff);
202 p[1] = (BYTE)((v >> 8) & 0xff);
203 p[2] = (BYTE)((v >> 16) & 0xff);
204 p[3] = (BYTE)((v >> 24) & 0xff);
205}
206
207/* A 24bpp BMP whose biSizeImage carries the unaligned image size
208 * (width * bytesPerPixel * height) selects the unaligned read path. The decoder
209 * must not consume more than biSizeImage bytes from the input buffer. The buffer
210 * here is allocated to the exact BMP size, so any over-read is detectable. */
211static BOOL test_unaligned_no_overread(void)
212{
213 BOOL rc = FALSE;
214 const UINT32 width = 1;
215 const UINT32 height = 10;
216 const UINT32 bpp = 3;
217 const UINT32 uscanline = width * bpp; /* 3, not a multiple of 4 */
218 const UINT32 biSizeImage = uscanline * height; /* 30 */
219 const size_t offBits = 54; /* 14 + 40 */
220 const size_t size = offBits + biSizeImage; /* 84 */
221
222 wImage* image = winpr_image_new();
223 BYTE* bmp = (BYTE*)calloc(1, size);
224 if (!image || !bmp)
225 goto fail;
226
227 bmp[0] = 'B';
228 bmp[1] = 'M';
229 put_u32(&bmp[2], (UINT32)size); /* bfSize */
230 put_u32(&bmp[10], (UINT32)offBits); /* bfOffBits */
231 put_u32(&bmp[14], 40); /* biSize */
232 put_u32(&bmp[18], width); /* biWidth */
233 put_u32(&bmp[22], (UINT32)(-(INT32)height)); /* biHeight, top-down */
234 put_u16(&bmp[26], 1); /* biPlanes */
235 put_u16(&bmp[28], 24); /* biBitCount */
236 put_u32(&bmp[30], 0); /* biCompression BI_RGB */
237 put_u32(&bmp[34], biSizeImage); /* biSizeImage */
238 for (UINT32 i = 0; i < biSizeImage; i++)
239 bmp[offBits + i] = (BYTE)i;
240
241 if (winpr_image_read_buffer(image, bmp, size) <= 0)
242 goto fail;
243
244 if ((image->width != width) || (image->height != height))
245 goto fail;
246
247 for (UINT32 row = 0; row < height; row++)
248 {
249 for (UINT32 b = 0; b < uscanline; b++)
250 {
251 if (image->data[1ULL * row * image->scanline + b] != (BYTE)(row * uscanline + b))
252 goto fail;
253 }
254 }
255
256 rc = TRUE;
257fail:
258 free(bmp);
259 winpr_image_free(image, TRUE);
260 return rc;
261}
262
263static BOOL test_load(void)
264{
265 const char* names[] = {
266 "rgb.16a.bmp", "rgb.16a.nocolor.bmp", "rgb.16.bmp", "rgb.16.nocolor.bmp",
267 "rgb.16x.bmp", "rgb.16x.nocolor.bmp", "rgb.24.bmp", "rgb.24.nocolor.bmp",
268 "rgb.32.bmp", "rgb.32.nocolor.bmp", "rgb.32x.bmp", "rgb.32x.nocolor.bmp",
269 "rgb.bmp"
270 };
271
272 for (size_t x = 0; x < ARRAYSIZE(names); x++)
273 {
274 const char* name = names[x];
275 char* fname = GetCombinedPath(TEST_SOURCE_PATH, name);
276 const BOOL res = test_load_file(fname);
277 free(fname);
278 if (!res)
279 return FALSE;
280 }
281
282 return TRUE;
283}
284
285int TestImage(int argc, char* argv[])
286{
287 int rc = 0;
288
289 WINPR_UNUSED(argc);
290 WINPR_UNUSED(argv);
291
292 if (!test_equal())
293 rc -= 1;
294
295 if (!test_read_write())
296 rc -= 2;
297
298 if (!test_load())
299 rc -= 4;
300
301 if (!test_unaligned_no_overread())
302 rc -= 8;
303
304 return rc;
305}