rsys

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

commit 1b44014de972e34812f635959c85e24d16755eed
parent 77fecf49100c5f98c513a07b90ae8ee6ae65045a
Author: vaplv <vincent.forest@meso-star.com>
Date:   Thu, 30 Mar 2017 11:42:54 +0200

Update the image API

Keep the legacy image_ppm_write functions but add a new image data
structure on which the loading of a PPM relies.

Diffstat:
Msrc/image.c | 154+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/image.h | 33+++++++++++++++++++++++++++++++++
Msrc/test_image.c | 84+++++++++++++++++++++++++++++++++----------------------------------------------
3 files changed, 147 insertions(+), 124 deletions(-)

diff --git a/src/image.c b/src/image.c @@ -35,16 +35,6 @@ struct parser { /******************************************************************************* * Helper functions ******************************************************************************/ -static INLINE size_t -sizeof_format(const enum image_format fmt) -{ - switch(fmt) { - case IMAGE_RGB8: return sizeof(uint8_t[3]); - case IMAGE_RGB16: return sizeof(uint16_t[3]); - default: FATAL("Unreachable code.\n"); break; - } -} - static void parser_init(struct parser* parser, FILE* stream) { @@ -142,6 +132,85 @@ parse_bin_pixels * Exported functions ******************************************************************************/ res_T +image_init(struct mem_allocator* mem_allocator, struct image* img) +{ + struct mem_allocator* allocator; + if(!img) return RES_BAD_ARG; + allocator = mem_allocator ? mem_allocator : &mem_default_allocator; + memset(img, 0, sizeof(struct image)); + img->allocator = allocator; + return RES_OK; +} + +res_T +image_release(struct image* img) +{ + if(!img) return RES_BAD_ARG; + if(img->pixels) MEM_RM(img->allocator, img->pixels); + return RES_OK; +} + +res_T +image_read_ppm_stream(struct image* img, FILE* stream) +{ + struct parser parser; + char* buffer = NULL; + size_t pitch; + unsigned long width=0, height=0, max_val=0; + enum ppm_id id; + enum image_format fmt; + res_T res = RES_OK; + + if(!img || !stream) return RES_BAD_ARG; + + parser_init(&parser, stream); + + /* Read header */ + #define CALL(Func) { res = Func; if(res != RES_OK) goto error; } (void)0 + CALL(parse_ppm_id(parser_next_token(&parser), &id)); + CALL(cstr_to_ulong(parser_next_token(&parser), &width)); + CALL(cstr_to_ulong(parser_next_token(&parser), &height)); + CALL(cstr_to_ulong(parser_next_token(&parser), &max_val)); + #undef CALL + + /* Check header */ + if(!width || !height || !max_val || max_val >= 65536) { + res = RES_BAD_ARG; + goto error; + } + + /* Allocate the image buffer */ + fmt = max_val <= 255 ? IMAGE_RGB8 : IMAGE_RGB16; + pitch = width * sizeof_image_format(fmt); + buffer = MEM_ALLOC(img->allocator, pitch*height); + if(!buffer) { + res = RES_MEM_ERR; + goto error; + } + + /* Read pixel data */ + switch(id) { + case P3: res = parse_raw_pixels(&parser, width, height, fmt, buffer); break; + case P6: res = parse_bin_pixels(&parser, width, height, fmt, buffer); break; + default: FATAL("Unreachable code.\n"); break; + } + + /* Setup the image layout */ + if(img->pixels) MEM_RM(img->allocator, img->pixels); + img->pixels = buffer; + img->width = width; + img->height = height; + img->format = fmt; + img->pitch = pitch; + +exit: + return res; +error: + if(buffer) MEM_RM(img->allocator, buffer); + goto exit; +} + +res_T image_ppm_write (const char* path, const int width, @@ -223,68 +292,3 @@ error: goto exit; } -res_T -image_ppm_read_stream - (FILE* fp, - struct mem_allocator* mem_allocator, - size_t* out_width, - size_t* out_height, - enum image_format* out_fmt, - char** out_buffer) -{ - struct parser parser; - struct mem_allocator* allocator; - char* buffer = NULL; - unsigned long width=0, height=0, max_val; - enum ppm_id id; - enum image_format fmt = IMAGE_RGB8; - res_T res = RES_OK; - - allocator = mem_allocator ? mem_allocator : &mem_default_allocator; - if(!fp || !out_width || !out_height || !out_fmt || !out_buffer) { - res = RES_BAD_ARG; - goto error; - } - - parser_init(&parser, fp); - - /* Read header */ - #define CALL(Func) { res = Func; if(res != RES_OK) goto error; } (void)0 - CALL(parse_ppm_id(parser_next_token(&parser), &id)); - CALL(cstr_to_ulong(parser_next_token(&parser), &width)); - CALL(cstr_to_ulong(parser_next_token(&parser), &height)); - CALL(cstr_to_ulong(parser_next_token(&parser), &max_val)); - #undef CALL - - /* Check header */ - if(!width || !height || !max_val || max_val >= 65536) { - res = RES_BAD_ARG; - goto error; - } - - /* Allocate the image buffer */ - fmt = max_val <= 255 ? IMAGE_RGB8 : IMAGE_RGB16; - buffer = MEM_ALLOC(allocator, width * height * sizeof_format(fmt)); - if(!buffer) { - res = RES_MEM_ERR; - goto error; - } - - /* Read pixel data */ - switch(id) { - case P3: res = parse_raw_pixels(&parser, width, height, fmt, buffer); break; - case P6: res = parse_bin_pixels(&parser, width, height, fmt, buffer); break; - default: FATAL("Unreachable code.\n"); break; - } - -exit: - if(out_width) *out_width = width; - if(out_height) *out_height = height; - if(out_fmt) *out_fmt = fmt; - if(out_buffer) *out_buffer = buffer; - return res; -error: - if(buffer) MEM_RM(allocator, buffer), buffer = NULL; - goto exit; -} - diff --git a/src/image.h b/src/image.h @@ -25,9 +25,42 @@ enum image_format { IMAGE_RGB16 }; +struct image { + size_t width; + size_t height; + size_t pitch; + enum image_format format; + char* pixels; + struct mem_allocator* allocator; +}; + +static FINLINE size_t +sizeof_image_format(const enum image_format fmt) +{ + switch(fmt) { + case IMAGE_RGB8: return sizeof(uint8_t[3]); + case IMAGE_RGB16: return sizeof(uint16_t[3]); + default: FATAL("Unreachable code.\n"); break; + } +} + BEGIN_DECLS RSYS_API res_T +image_init + (struct mem_allocator* allocator, /* May be NULL */ + struct image* img); + +RSYS_API res_T +image_release + (struct image* img); + +RSYS_API res_T +image_read_ppm_stream + (struct image* image, + FILE* stream); + +RSYS_API res_T image_ppm_write (const char* path, const int width, diff --git a/src/test_image.c b/src/test_image.c @@ -15,6 +15,7 @@ #include "image.h" #include "mem_allocator.h" +#include "test_utils.h" #define WIDTH 64 #define HEIGHT 32 @@ -28,18 +29,19 @@ main(int argc, char** argv) {{0x00,0xFF,0x00}, {0x00,0xFF,0xFF }, {0x00,0xFF,0xFF}, { 0x00,0xFF,0x00}}, {{0x00,0x00,0xFF}, {0xFF,0x00,0xFF }, {0xFF,0x00,0xFF}, { 0x00,0x00,0xFF}} }; + struct mem_allocator allocator; + struct image img; unsigned char* pixels; - char* buf; FILE* fp; - size_t w, h; - enum image_format fmt; int x, y, i = 0; (void)argc, (void)argv; + CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); + fp = tmpfile(); NCHECK(fp, NULL); - pixels = mem_alloc(WIDTH*HEIGHT*3); + pixels = MEM_ALLOC(&allocator, WIDTH*HEIGHT*3); NCHECK(pixels, NULL); i = 0; @@ -87,57 +89,41 @@ main(int argc, char** argv) CHECK(image_ppm_write_stream(fp, WIDTH, HEIGHT, 3, pixels), RES_OK); rewind(fp); - CHECK(image_ppm_read_stream(NULL, NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, NULL, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, &w, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, &w, NULL, NULL, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, NULL, &h, NULL, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, NULL, &h, NULL, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, &w, &h, NULL, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, &w, &h, NULL, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, NULL, NULL, &fmt, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, NULL, NULL, &fmt, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, &w, NULL, &fmt, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, &w, NULL, &fmt, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, NULL, &h, &fmt, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, NULL, &h, &fmt, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, &w, &h, &fmt, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, &w, &h, &fmt, NULL), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, NULL, NULL, NULL, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, NULL, NULL, NULL, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, &w, NULL, NULL, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, &w, NULL, NULL, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, NULL, &h, NULL, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, NULL, &h, NULL, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, &w, &h, NULL, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, &w, &h, NULL, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, NULL, NULL, &fmt, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, NULL, NULL, &fmt, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, &w, NULL, &fmt, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, &w, NULL, &fmt, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, NULL, &h, &fmt, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, NULL, &h, &fmt, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(NULL, NULL, &w, &h, &fmt, &buf), RES_BAD_ARG); - CHECK(image_ppm_read_stream(fp, NULL, &w, &h, &fmt, &buf), RES_OK); - NCHECK(buf, NULL); - CHECK(w, WIDTH); - CHECK(h, HEIGHT); - CHECK(fmt, IMAGE_RGB8); + CHECK(image_init(NULL, NULL), RES_BAD_ARG); + CHECK(image_init(&allocator, NULL), RES_BAD_ARG); + CHECK(image_init(NULL, &img), RES_OK); + CHECK(image_release(NULL), RES_BAD_ARG); + CHECK(image_release(&img), RES_OK); + CHECK(image_init(&allocator, &img), RES_OK); + + CHECK(image_read_ppm_stream(NULL, NULL), RES_BAD_ARG); + CHECK(image_read_ppm_stream(&img, NULL), RES_BAD_ARG); + CHECK(image_read_ppm_stream(NULL, fp), RES_BAD_ARG); + CHECK(image_read_ppm_stream(&img, fp), RES_OK); + + CHECK(img.format, IMAGE_RGB8); + CHECK(img.height, HEIGHT); + CHECK(img.width, WIDTH); + CHECK(img.pitch >= img.width, 1); i = 0; FOR_EACH(y, 0, HEIGHT) { - FOR_EACH(x, 0, WIDTH) { - CHECK(((unsigned char*)buf)[i], pixels[i]), ++i; - CHECK(((unsigned char*)buf)[i], pixels[i]), ++i; - CHECK(((unsigned char*)buf)[i], pixels[i]), ++i; - }} + const char* row = img.pixels + img.pitch * (size_t)y; + FOR_EACH(x, 0, WIDTH) { + const char* pixel = row + (size_t)x*sizeof_image_format(img.format); + CHECK(((uint8_t*)pixel)[0], pixels[i]), ++i; + CHECK(((uint8_t*)pixel)[1], pixels[i]), ++i; + CHECK(((uint8_t*)pixel)[2], pixels[i]), ++i; + } + } - CHECK(image_ppm_write_stream - (stdout, WIDTH, HEIGHT, 3, (unsigned char*)buf), RES_OK); + CHECK(image_release(&img), RES_OK); - mem_rm(buf); fclose(fp); - mem_rm(pixels); + MEM_RM(&allocator, pixels); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); CHECK(mem_allocated_size(), 0); return 0; }