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:
| M | src/image.c | | | 154 | +++++++++++++++++++++++++++++++++++++++++-------------------------------------- |
| M | src/image.h | | | 33 | +++++++++++++++++++++++++++++++++ |
| M | src/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;
}