2#include <winpr/string.h>
3#include <winpr/assert.h>
6#include <winpr/image.h>
9static const char test_src_filename[] = TEST_SOURCE_PATH
"/rgb";
10static const char test_bin_filename[] = TEST_BINARY_PATH
"/rgb";
12static BOOL test_image_equal(
const wImage* imageA,
const wImage* imageB)
14 return winpr_image_equal(imageA, imageB,
15 WINPR_IMAGE_CMP_IGNORE_DEPTH | WINPR_IMAGE_CMP_IGNORE_ALPHA |
16 WINPR_IMAGE_CMP_FUZZY);
19static BOOL test_equal_to(
const wImage* bmp,
const char* name, UINT32 format)
22 wImage* cmp = winpr_image_new();
26 char path[MAX_PATH] = WINPR_C_ARRAY_INIT;
27 (void)_snprintf(path,
sizeof(path),
"%s.%s", name, winpr_image_format_extension(format));
28 const int cmpSize = winpr_image_read(cmp, path);
31 (void)fprintf(stderr,
"[%s] winpr_image_read failed for %s", __func__, path);
35 rc = test_image_equal(bmp, cmp);
37 (void)fprintf(stderr,
"[%s] winpr_image_eqal failed", __func__);
40 winpr_image_free(cmp, TRUE);
44static BOOL test_equal(
void)
47 wImage* bmp = winpr_image_new();
52 char path[MAX_PATH] = WINPR_C_ARRAY_INIT;
53 (void)_snprintf(path,
sizeof(path),
"%s.bmp", test_src_filename);
54 PathCchConvertStyleA(path,
sizeof(path), PATH_STYLE_NATIVE);
56 const int bmpSize = winpr_image_read(bmp, path);
59 (void)fprintf(stderr,
"[%s] winpr_image_read failed for %s", __func__, path);
63 for (UINT32 x = 0; x < UINT8_MAX; x++)
65 if (!winpr_image_format_is_supported(x))
67 if (!test_equal_to(bmp, test_src_filename, x))
73 winpr_image_free(bmp, TRUE);
78static BOOL test_read_write_compare(
const char* tname,
const char* tdst, UINT32 format)
81 wImage* bmp1 = winpr_image_new();
82 wImage* bmp2 = winpr_image_new();
83 wImage* bmp3 = winpr_image_new();
84 if (!bmp1 || !bmp2 || !bmp3)
87 char spath[MAX_PATH] = WINPR_C_ARRAY_INIT;
88 char dpath[MAX_PATH] = WINPR_C_ARRAY_INIT;
89 char bpath1[MAX_PATH] = WINPR_C_ARRAY_INIT;
90 char bpath2[MAX_PATH] = WINPR_C_ARRAY_INIT;
91 (void)_snprintf(spath,
sizeof(spath),
"%s.%s", tname, winpr_image_format_extension(format));
92 (void)_snprintf(dpath,
sizeof(dpath),
"%s.%s", tdst, winpr_image_format_extension(format));
93 (void)_snprintf(bpath1,
sizeof(bpath1),
"%s.src.%s", dpath,
94 winpr_image_format_extension(WINPR_IMAGE_BITMAP));
95 (void)_snprintf(bpath2,
sizeof(bpath2),
"%s.bin.%s", dpath,
96 winpr_image_format_extension(WINPR_IMAGE_BITMAP));
97 PathCchConvertStyleA(spath,
sizeof(spath), PATH_STYLE_NATIVE);
98 PathCchConvertStyleA(dpath,
sizeof(dpath), PATH_STYLE_NATIVE);
99 PathCchConvertStyleA(bpath1,
sizeof(bpath1), PATH_STYLE_NATIVE);
100 PathCchConvertStyleA(bpath2,
sizeof(bpath2), PATH_STYLE_NATIVE);
102 const int bmpRSize = winpr_image_read(bmp1, spath);
105 (void)fprintf(stderr,
"[%s] winpr_image_read failed for %s", __func__, spath);
109 const int bmpWSize = winpr_image_write(bmp1, dpath);
112 (void)fprintf(stderr,
"[%s] winpr_image_write failed for %s", __func__, dpath);
116 const int bmp2RSize = winpr_image_read(bmp2, dpath);
119 (void)fprintf(stderr,
"[%s] winpr_image_read failed for %s", __func__, dpath);
123 const int bmpSrcWSize = winpr_image_write_ex(bmp1, WINPR_IMAGE_BITMAP, bpath1);
124 if (bmpSrcWSize <= 0)
126 (void)fprintf(stderr,
"[%s] winpr_image_write_ex failed for %s", __func__, bpath1);
132 const int bmpBinWSize = winpr_image_write_ex(bmp2, WINPR_IMAGE_BITMAP, bpath2);
133 if (bmpBinWSize <= 0)
135 (void)fprintf(stderr,
"[%s] winpr_image_write_ex failed for %s", __func__, bpath2);
139 const int bmp3RSize = winpr_image_read(bmp3, bpath2);
142 (void)fprintf(stderr,
"[%s] winpr_image_read failed for %s", __func__, bpath2);
146 if (!winpr_image_equal(bmp1, bmp2,
147 WINPR_IMAGE_CMP_IGNORE_DEPTH | WINPR_IMAGE_CMP_IGNORE_ALPHA |
148 WINPR_IMAGE_CMP_FUZZY))
150 (void)fprintf(stderr,
"[%s] winpr_image_eqal failed bmp1 bmp2", __func__);
154 rc = winpr_image_equal(bmp3, bmp2,
155 WINPR_IMAGE_CMP_IGNORE_DEPTH | WINPR_IMAGE_CMP_IGNORE_ALPHA |
156 WINPR_IMAGE_CMP_FUZZY);
158 (void)fprintf(stderr,
"[%s] winpr_image_eqal failed bmp3 bmp2", __func__);
160 winpr_image_free(bmp1, TRUE);
161 winpr_image_free(bmp2, TRUE);
162 winpr_image_free(bmp3, TRUE);
166static BOOL test_read_write(
void)
169 for (UINT32 x = 0; x < UINT8_MAX; x++)
171 if (!winpr_image_format_is_supported(x))
173 if (!test_read_write_compare(test_src_filename, test_bin_filename, x))
179static BOOL test_load_file(
const char* name)
182 wImage* image = winpr_image_new();
186 const int res = winpr_image_read(image, name);
190 winpr_image_free(image, TRUE);
194static void put_u16(BYTE* p, UINT16 v)
196 p[0] = (BYTE)(v & 0xff);
197 p[1] = (BYTE)((v >> 8) & 0xff);
200static void put_u32(BYTE* p, UINT32 v)
202 p[0] = (BYTE)(v & 0xff);
203 p[1] = (BYTE)((v >> 8) & 0xff);
204 p[2] = (BYTE)((v >> 16) & 0xff);
205 p[3] = (BYTE)((v >> 24) & 0xff);
212static BOOL test_unaligned_no_overread(
void)
215 const UINT32 width = 1;
216 const UINT32 height = 10;
217 const UINT32 bpp = 3;
218 const UINT32 uscanline = width * bpp;
219 const UINT32 biSizeImage = uscanline * height;
220 const size_t offBits = 54;
221 const size_t size = offBits + biSizeImage;
223 wImage* image = winpr_image_new();
224 BYTE* bmp = (BYTE*)calloc(1, size);
230 put_u32(&bmp[2], (UINT32)size);
231 put_u32(&bmp[10], (UINT32)offBits);
232 put_u32(&bmp[14], 40);
233 put_u32(&bmp[18], width);
234 put_u32(&bmp[22], (UINT32)(-(INT32)height));
235 put_u16(&bmp[26], 1);
236 put_u16(&bmp[28], 24);
237 put_u32(&bmp[30], 0);
238 put_u32(&bmp[34], biSizeImage);
239 for (UINT32 i = 0; i < biSizeImage; i++)
240 bmp[offBits + i] = (BYTE)i;
242 if (winpr_image_read_buffer(image, bmp, size) <= 0)
245 if ((image->width != width) || (image->height != height))
248 for (UINT32 row = 0; row < height; row++)
250 for (UINT32 b = 0; b < uscanline; b++)
252 if (image->data[1ULL * row * image->scanline + b] != (BYTE)(row * uscanline + b))
260 winpr_image_free(image, TRUE);
264static BOOL test_load(
void)
266 const char* names[] = {
267 "rgb.16a.bmp",
"rgb.16a.nocolor.bmp",
"rgb.16.bmp",
"rgb.16.nocolor.bmp",
268 "rgb.16x.bmp",
"rgb.16x.nocolor.bmp",
"rgb.24.bmp",
"rgb.24.nocolor.bmp",
269 "rgb.32.bmp",
"rgb.32.nocolor.bmp",
"rgb.32x.bmp",
"rgb.32x.nocolor.bmp",
273 for (
size_t x = 0; x < ARRAYSIZE(names); x++)
275 const char* name = names[x];
276 char* fname = GetCombinedPath(TEST_SOURCE_PATH, name);
277 const BOOL res = test_load_file(fname);
287static BOOL test_bmp_offbits(UINT32 compression, UINT32 padding, BOOL topDown)
290 const UINT32 width = 2;
291 const UINT32 height = 2;
292 const UINT32 bpp = 32;
293 const UINT32 stride = width * bpp / 8;
294 const UINT32 biSizeImage = stride * height;
295 const size_t headerSize = 54;
296 const size_t maskSize = (compression == BI_BITFIELDS) ? 3 *
sizeof(DWORD) : 0;
297 const size_t minOffset = headerSize + maskSize;
298 const size_t offBits = minOffset + padding;
299 const size_t size = offBits + biSizeImage;
301 wImage* image = winpr_image_new();
302 BYTE* bmp = (BYTE*)calloc(1, size);
308 put_u32(&bmp[2], (UINT32)size);
309 put_u32(&bmp[10], (UINT32)offBits);
310 put_u32(&bmp[14], 40);
311 put_u32(&bmp[18], width);
312 put_u32(&bmp[22], topDown ? (UINT32)(-(INT32)height) : height);
313 put_u16(&bmp[26], 1);
314 put_u16(&bmp[28], bpp);
315 put_u32(&bmp[30], compression);
316 put_u32(&bmp[34], biSizeImage);
317 if (compression == BI_BITFIELDS)
319 put_u32(&bmp[54], 0x00FF0000);
320 put_u32(&bmp[58], 0x0000FF00);
321 put_u32(&bmp[62], 0x000000FF);
325 const BYTE pixels[16] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
326 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 };
327 memcpy(&bmp[offBits], pixels,
sizeof(pixels));
329 if (winpr_image_read_buffer(image, bmp, size) <= 0)
331 (void)fprintf(stderr,
"[%s] failed to read BMP at offset %" PRIuz
"\n", __func__,
336 if ((image->width != width) || (image->height != height) || (image->bitsPerPixel != bpp) ||
337 (image->bytesPerPixel != bpp / 8) || (image->scanline != stride) || !image->data)
339 (void)fprintf(stderr,
"[%s] unexpected image layout\n", __func__);
343 for (
size_t row = 0; row < height; row++)
345 const size_t srcRow = topDown ? row : height - 1 - row;
346 if (memcmp(&image->data[row * image->scanline], &pixels[srcRow * stride], stride) != 0)
348 (void)fprintf(stderr,
"[%s] unexpected pixels in row %" PRIuz
"\n", __func__, row);
357 const UINT32 offsets[] = { 0,
358 (UINT32)(headerSize - 1),
359 (UINT32)(minOffset - 1),
364 for (
size_t x = 0; x < ARRAYSIZE(offsets); x++)
366 winpr_image_free(image, TRUE);
367 image = winpr_image_new();
370 put_u32(&bmp[10], offsets[x]);
371 if (winpr_image_read_buffer(image, bmp, size) > 0)
373 (void)fprintf(stderr,
"[%s] accepted invalid offset %" PRIu32
"\n", __func__,
383 winpr_image_free(image, TRUE);
387int TestImage(
int argc,
char* argv[])
397 if (!test_read_write())
403 if (!test_unaligned_no_overread())
406 if (!test_bmp_offbits(BI_BITFIELDS, 0, FALSE) || !test_bmp_offbits(BI_BITFIELDS, 4, TRUE) ||
407 !test_bmp_offbits(BI_RGB, 0, FALSE) || !test_bmp_offbits(BI_RGB, 12, TRUE))