rsys

Basic data structures and low-level features
git clone git://git.meso-star.fr/rsys.git
Log | Files | Refs | README | LICENSE

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 }