test_image.c (10698B)
1 /* Copyright (C) 2013-2023, 2025 Vincent Forest (vaplv@free.fr) 2 * 3 * The RSys library is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published 5 * by the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * The RSys library is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with the RSys library. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #include "image.h" 17 #include "mem_allocator.h" 18 #include "test_utils.h" 19 20 #define WIDTH 64 21 #define HEIGHT 32 22 23 static void 24 check_image_eq 25 (const struct image* img, 26 const char* ref_pixels, 27 const size_t ref_width, 28 const size_t ref_height, 29 const enum image_format ref_fmt) 30 { 31 size_t x, y; 32 size_t i; 33 34 CHK(img->format == ref_fmt); 35 CHK(img->height == ref_height); 36 CHK(img->width == ref_width); 37 CHK(img->pitch >= img->width); 38 39 i = 0; 40 FOR_EACH(y, 0, img->height) { 41 const char* row = img->pixels + img->pitch * (size_t)y; 42 FOR_EACH(x, 0, img->width) { 43 const char* pixel = row + (size_t)x*sizeof_image_format(img->format); 44 switch(img->format) { 45 case IMAGE_RGB8: 46 CHK(((uint8_t*)pixel)[0] == ((uint8_t*)ref_pixels)[i]), ++i; 47 CHK(((uint8_t*)pixel)[1] == ((uint8_t*)ref_pixels)[i]), ++i; 48 CHK(((uint8_t*)pixel)[2] == ((uint8_t*)ref_pixels)[i]), ++i; 49 break; 50 case IMAGE_RGB16: 51 CHK(((uint16_t*)pixel)[0] == ((uint16_t*)ref_pixels)[i]), ++i; 52 CHK(((uint16_t*)pixel)[1] == ((uint16_t*)ref_pixels)[i]), ++i; 53 CHK(((uint16_t*)pixel)[2] == ((uint16_t*)ref_pixels)[i]), ++i; 54 break; 55 default: FATAL("Unreachable code.\n"); break; 56 } 57 } 58 } 59 } 60 61 static void 62 check_image_read 63 (FILE* fp, 64 const size_t width, 65 const size_t height, 66 const enum image_format fmt, 67 struct mem_allocator* allocator) 68 { 69 struct image img; 70 size_t max_val; 71 int is_bin; 72 char id[2]; 73 74 CHK(image_init(allocator, &img) == RES_OK); 75 76 CHK(fseek(fp, 0, SEEK_SET) == 0); 77 CHK(image_read_ppm_stream(&img, fp) == RES_OK); 78 79 CHK(fseek(fp, 0, SEEK_SET) == 0); 80 CHK(fread(id, 1, 2, fp) == 2); 81 CHK(id[0] == 'P'); 82 CHK(id[1] == '3' || id[1] == '6'); 83 is_bin = id[1] == '6'; 84 85 switch(fmt) { 86 case IMAGE_RGB8: max_val = 255; break; 87 case IMAGE_RGB16: max_val = 65535; break; 88 default: FATAL("Unreachable code.\n"); break; 89 } 90 91 CHK(fseek(fp, 3, SEEK_SET) == 0); 92 fprintf(fp, "%lu %lu\n", (unsigned long)width+1, (unsigned long)height); 93 CHK(fseek(fp, 0, SEEK_SET) == 0); 94 CHK(image_read_ppm_stream(&img, fp) == RES_BAD_ARG); 95 CHK(fseek(fp, 3, SEEK_SET) == 0); 96 fprintf(fp, "%lu %lu\n", (unsigned long)width, (unsigned long)height+1); 97 CHK(fseek(fp, 0, SEEK_SET) == 0); 98 CHK(image_read_ppm_stream(&img, fp) == RES_BAD_ARG); 99 CHK(fseek(fp, 3, SEEK_SET) == 0); 100 fprintf(fp, "%lu %lu\n", (unsigned long)width, (unsigned long)height); 101 fprintf(fp, "%lu\n", (unsigned long)max_val+1); 102 CHK(fseek(fp, 0, SEEK_SET) == 0); 103 104 if(is_bin) { 105 CHK(image_read_ppm_stream(&img, fp) == RES_BAD_ARG); 106 } else { 107 switch(fmt) { 108 case IMAGE_RGB8: 109 CHK(image_read_ppm_stream(&img, fp) == RES_OK); 110 break; 111 case IMAGE_RGB16: 112 CHK(image_read_ppm_stream(&img, fp) == RES_BAD_ARG); 113 break; 114 default: FATAL("Unreachable code.\n"); break; 115 } 116 } 117 118 CHK(fseek(fp, 3, SEEK_SET) == 0); 119 fprintf(fp, "%lu %lu\n", (unsigned long)width, (unsigned long)height); 120 fprintf(fp, "%lu\n", (unsigned long)max_val); 121 CHK(fseek(fp, 0, SEEK_SET) == 0); 122 CHK(image_read_ppm_stream(&img, fp) == RES_OK); 123 124 CHK(image_release(&img) == RES_OK); 125 } 126 127 static void 128 check_image 129 (const char* pixels, 130 const size_t width, 131 const size_t height, 132 const enum image_format fmt, 133 struct mem_allocator* allocator) 134 { 135 struct image img; 136 size_t pitch; 137 FILE* fp; 138 139 CHK(image_init(NULL, NULL) == RES_BAD_ARG); 140 CHK(image_init(allocator, NULL) == RES_BAD_ARG); 141 CHK(image_init(NULL, &img) == RES_OK); 142 CHK(image_release(NULL) == RES_BAD_ARG); 143 CHK(image_release(&img) == RES_OK); 144 CHK(image_init(allocator, &img) == RES_OK); 145 146 pitch = width * sizeof_image_format(fmt); 147 148 CHK(image_setup(NULL, 0, 0, 0, fmt, NULL) == RES_BAD_ARG); 149 CHK(image_setup(&img, 0, 0, 0, fmt, NULL) == RES_BAD_ARG); 150 CHK(image_setup(NULL, width, 0, 0, fmt, NULL) == RES_BAD_ARG); 151 CHK(image_setup(&img, width, 0, 0, fmt, NULL) == RES_BAD_ARG); 152 CHK(image_setup(NULL, 0, height, 0, fmt, NULL) == RES_BAD_ARG); 153 CHK(image_setup(&img, 0, height, 0, fmt, NULL) == RES_BAD_ARG); 154 CHK(image_setup(NULL, width, height, 0, fmt, NULL) == RES_BAD_ARG); 155 CHK(image_setup(&img, width, height, 0, fmt, NULL) == RES_BAD_ARG); 156 CHK(image_setup(NULL, 0, 0, pitch, fmt, NULL) == RES_BAD_ARG); 157 CHK(image_setup(&img, 0, 0, pitch, fmt, NULL) == RES_BAD_ARG); 158 CHK(image_setup(NULL, width, 0, pitch, fmt, NULL) == RES_BAD_ARG); 159 CHK(image_setup(&img, width, 0, pitch, fmt, NULL) == RES_BAD_ARG); 160 CHK(image_setup(NULL, 0, height, pitch, fmt, NULL) == RES_BAD_ARG); 161 CHK(image_setup(&img, 0, height, pitch, fmt, NULL) == RES_BAD_ARG); 162 CHK(image_setup(NULL, width, height, pitch, fmt, NULL) == RES_BAD_ARG); 163 CHK(image_setup(&img, width, height, pitch, fmt, NULL) == RES_OK); 164 CHK(image_setup(NULL, 0, 0, 0, fmt, pixels) == RES_BAD_ARG); 165 CHK(image_setup(&img, 0, 0, 0, fmt, pixels) == RES_BAD_ARG); 166 CHK(image_setup(NULL, width, 0, 0, fmt, pixels) == RES_BAD_ARG); 167 CHK(image_setup(&img, width, 0, 0, fmt, pixels) == RES_BAD_ARG); 168 CHK(image_setup(NULL, 0, height, 0, fmt, pixels) == RES_BAD_ARG); 169 CHK(image_setup(&img, 0, height, 0, fmt, pixels) == RES_BAD_ARG); 170 CHK(image_setup(NULL, width, height, 0, fmt, pixels) == RES_BAD_ARG); 171 CHK(image_setup(&img, width, height, 0, fmt, pixels) == RES_BAD_ARG); 172 CHK(image_setup(NULL, 0, 0, pitch, fmt, pixels) == RES_BAD_ARG); 173 CHK(image_setup(&img, 0, 0, pitch, fmt, pixels) == RES_BAD_ARG); 174 CHK(image_setup(NULL, width, 0, pitch, fmt, pixels) == RES_BAD_ARG); 175 CHK(image_setup(&img, width, 0, pitch, fmt, pixels) == RES_BAD_ARG); 176 CHK(image_setup(NULL, 0, height, pitch, fmt, pixels) == RES_BAD_ARG); 177 CHK(image_setup(&img, 0, height, pitch, fmt, pixels) == RES_BAD_ARG); 178 CHK(image_setup(NULL, width, height, pitch, fmt, pixels) == RES_BAD_ARG); 179 CHK(image_setup(&img, width, height, pitch, fmt, pixels) == RES_OK); 180 181 fp = tmpfile(); 182 CHK(fp != NULL); 183 184 CHK(image_write_ppm_stream(NULL, 0, NULL) == RES_BAD_ARG); 185 CHK(image_write_ppm_stream(&img, 0, NULL) == RES_BAD_ARG); 186 CHK(image_write_ppm_stream(NULL, 0, fp) == RES_BAD_ARG); 187 CHK(image_write_ppm_stream(&img, 0, fp) == RES_OK); 188 189 CHK(image_read_ppm_stream(NULL, NULL) == RES_BAD_ARG); 190 CHK(image_read_ppm_stream(&img, NULL) == RES_BAD_ARG); 191 CHK(image_read_ppm_stream(NULL, fp) == RES_BAD_ARG); 192 CHK(image_read_ppm_stream(&img, fp) == RES_BAD_ARG); 193 rewind(fp); 194 CHK(image_read_ppm_stream(&img, fp) == RES_OK); 195 check_image_eq(&img, pixels, width, height, fmt); 196 197 rewind(fp); 198 CHK(image_write_ppm_stream(&img, 1, fp) == RES_OK); 199 rewind(fp); 200 CHK(image_read_ppm_stream(&img, fp) == RES_OK); 201 check_image_eq(&img, pixels, width, height, fmt); 202 203 CHK(image_write_ppm(NULL, 0, NULL) == RES_BAD_ARG); 204 CHK(image_write_ppm(&img, 0, NULL) == RES_BAD_ARG); 205 CHK(image_write_ppm(NULL, 0, "test.ppm") == RES_BAD_ARG); 206 CHK(image_write_ppm(&img, 0, "test.ppm") == RES_OK); 207 208 CHK(image_read_ppm(NULL, NULL) == RES_BAD_ARG); 209 CHK(image_read_ppm(&img, NULL) == RES_BAD_ARG); 210 CHK(image_read_ppm(NULL, "test_bad.ppm") == RES_BAD_ARG); 211 CHK(image_read_ppm(&img, "test_bad.ppm") == RES_IO_ERR); 212 CHK(image_read_ppm(&img, "test.ppm") == RES_OK); 213 214 check_image_eq(&img, pixels, width, height, fmt); 215 216 CHK(image_write_ppm(&img, 1, "test.ppm") == RES_OK); 217 CHK(image_read_ppm(&img, "test.ppm") == RES_OK); 218 check_image_eq(&img, pixels, width, height, fmt); 219 220 CHK(image_write_ppm_stream(&img, 1, stdout) == RES_OK); 221 222 fclose(fp); 223 224 fp = tmpfile(); 225 CHK(fp != NULL); 226 CHK(image_write_ppm_stream(&img, 0, fp) == RES_OK); 227 check_image_read(fp, width, height, fmt, allocator); 228 fclose(fp); 229 230 fp = tmpfile(); 231 CHK(fp != NULL); 232 CHK(image_write_ppm_stream(&img, 1, fp) == RES_OK); 233 check_image_read(fp, width, height, fmt, allocator); 234 fclose(fp); 235 236 CHK(image_release(&img) == RES_OK); 237 } 238 239 int 240 main(int argc, char** argv) 241 { 242 uint8_t lut8[4][4][3] = { 243 {{0xFF,0xFF,0x00}, {0xFF,0x00,0x00}, {0xFF,0x00,0x00}, {0xFF,0xFF,0x00}}, 244 {{0xFF,0xFF,0xFF}, {0x00,0x00,0x00}, {0x00,0x00,0x00}, {0xFF,0xFF,0xFF}}, 245 {{0x00,0xFF,0x00}, {0x00,0xFF,0xFF}, {0x00,0xFF,0xFF}, {0x00,0xFF,0x00}}, 246 {{0x00,0x00,0xFF}, {0xFF,0x00,0xFF}, {0xFF,0x00,0xFF}, {0x00,0x00,0xFF}} 247 }; 248 uint16_t lut16[4][4][3] = { 249 { {0x0000,0x0000,0xFFFF}, {0xFFFF,0x0000,0xFFFF}, 250 {0xFFFF,0x0000,0xFFFF}, {0x0000,0x0000,0xFFFF} }, 251 { {0x0000,0xFFFF,0x0000}, {0x0000,0xFFFF,0xFFFF}, 252 {0x0000,0xFFFF,0xFFFF}, {0x0000,0xFFFF,0x0000} }, 253 { {0xFFFF,0xFFFF,0xFFFF}, {0x0000,0x0000,0x0000}, 254 {0x0000,0x0000,0x0000}, {0xFFFF,0xFFFF,0xFFFF} }, 255 { {0xFFFF,0xFFFF,0x0000}, {0xFFFF,0x0000,0x0000}, 256 {0xFFFF,0x0000,0x0000}, {0xFFFF,0xFFFF,0x0000} } 257 }; 258 struct mem_allocator allocator; 259 char* pixels; 260 int x, y, i = 0; 261 (void)argc, (void)argv; 262 263 CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); 264 265 pixels = MEM_ALLOC(&allocator, WIDTH*sizeof_image_format(IMAGE_RGB8)*HEIGHT); 266 CHK(pixels != NULL); 267 268 i = 0; 269 FOR_EACH(y, 0, HEIGHT) { 270 FOR_EACH(x, 0, WIDTH) { 271 int j = ((x/32) & 1) + ((y/16)&1) * 2; 272 int k = ((x/8) & 1) + ((y/8)&1) * 2; 273 274 ((uint8_t*)pixels)[i++] = lut8[j][k][0]; 275 ((uint8_t*)pixels)[i++] = lut8[j][k][1]; 276 ((uint8_t*)pixels)[i++] = lut8[j][k][2]; 277 }} 278 check_image(pixels, WIDTH, HEIGHT, IMAGE_RGB8, &allocator); 279 MEM_RM(&allocator, pixels); 280 281 pixels = MEM_ALLOC(&allocator, WIDTH*sizeof_image_format(IMAGE_RGB16)*HEIGHT); 282 CHK(pixels != NULL); 283 284 i = 0; 285 FOR_EACH(y, 0, HEIGHT) { 286 FOR_EACH(x, 0, WIDTH) { 287 int j = ((x/32) & 1) + ((y/16)&1) * 2; 288 int k = ((x/8) & 1) + ((y/8)&1) * 2; 289 ((uint16_t*)pixels)[i++] = lut16[j][k][0]; 290 ((uint16_t*)pixels)[i++] = lut16[j][k][1]; 291 ((uint16_t*)pixels)[i++] = lut16[j][k][2]; 292 }} 293 check_image(pixels, WIDTH, HEIGHT, IMAGE_RGB16, &allocator); 294 MEM_RM(&allocator, pixels); 295 296 check_memory_allocator(&allocator); 297 mem_shutdown_proxy_allocator(&allocator); 298 CHK(mem_allocated_size() == 0); 299 return 0; 300 }