From 430be3ec2f86aec28fa21558b3141a2e28efd848 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Wed, 22 Jan 2014 21:13:45 -0500 Subject: [PATCH] liblbx: Implement new image reading API. Add a new API which allows the application to essentially loop over the drawing commands in an LBX frame. This requires no runtime memory allocations in the library, pushing all that out to the caller. Conceptually this simplifies many applications because they can use this to handle image data row-at-a-time. For now, keep the old getframe function but change it to use the new API under the hood. --- src/image.c | 237 ++++++++++++++++++++++++++++++++++++---------------- src/image.h | 4 + 2 files changed, 168 insertions(+), 73 deletions(-) diff --git a/src/image.c b/src/image.c index b30f165..0caca96 100644 --- a/src/image.c +++ b/src/image.c @@ -39,6 +39,14 @@ #define HDR_LEN 12 +/* States for image readout */ +enum { + READ_STATE_INIT, + READ_STATE_HEADER, + READ_STATE_DATA, + READ_STATE_DONE, +}; + struct lbx_image_priv { struct lbx_image pub; @@ -52,8 +60,11 @@ struct lbx_image_priv { long paloff; + /* State of frame readout */ + unsigned currentx, currenty, currentn; + int read_state; + int currentframe; - int currentx, currenty; unsigned char **framedata; unsigned char **mask; @@ -204,66 +215,26 @@ struct lbx_image *lbx_img_fopen(const char *file) static int _lbx_drawrow(struct lbx_image_priv *img) { - unsigned short length, offset; - unsigned char buf[4]; unsigned char *pos; - size_t rc; + unsigned x, y; + long rc; assert(img->framedata); assert(img->mask); - if (img->fops->read(buf, sizeof buf, img->f) != sizeof buf) - goto readerr; - - length = unpack_16_le(buf+0); - offset = unpack_16_le(buf+2); - if (length == 0 && offset == 1000) + rc = lbx_img_read_row_header(&img->pub, &x, &y); + if (rc == 0) return 1; - - /* Length of 0 increments Y position */ - if (!length) { - if (offset > img->pub.height - img->currenty) { - lbx_error_raise(LBX_EFORMAT); - return -1; - } - - img->currenty += offset; - img->currentx = 0; - return 0; - } - - /* Otherwise we read pixel data */ - if (offset > img->pub.width - img->currentx) { - lbx_error_raise(LBX_EFORMAT); + else if (rc < 0) return -1; - } - img->currentx += offset; - if (length > img->pub.width - img->currentx) { - lbx_error_raise(LBX_EFORMAT); + pos = &img->framedata[y][x]; + rc = lbx_img_read_row_data(&img->pub, pos); + if (rc < 0) return -1; - } - - memset(&img->mask[img->currenty][img->currentx], 1, length); - - pos = &img->framedata[img->currenty][img->currentx]; - rc = img->fops->read(pos, length, img->f); - img->currentx += rc; - - if (rc < length) - goto readerr; - - /* Skip padding byte, if any */ - if (length % 2) { - if (img->fops->read(buf, 1, img->f) != 1) - goto readerr; - } + memset(&img->mask[y][x], 1, rc); return 0; -readerr: - if (img->fops->eof(img->f)) - lbx_error_raise(LBX_EEOF); - return -1; } static unsigned char **allocframebuffer(size_t width, size_t height) @@ -300,15 +271,154 @@ static unsigned char **allocframebuffer(size_t width, size_t height) return new; } +int lbx_img_seek(struct lbx_image *pub, unsigned frame) +{ + struct lbx_image_priv *img = (struct lbx_image_priv *)pub; + + if (frame >= pub->frames) { + lbx_error_raise(LBX_EINVAL); + return -1; + } + + if (img->fops->seek(img->f, img->offsets[frame], SEEK_SET)) { + return -1; + } + + if (!(img->flags & FLAG_RAW)) { + unsigned char buf[4]; + + /* Read frame header */ + if (img->fops->read(buf, 4, img->f) != 4) { + if (img->fops->eof(img->f)) + lbx_error_raise(LBX_EEOF); + return -1; + } + + if (unpack_16_le(buf) != 1) { + lbx_error_raise(LBX_EFORMAT); + return -1; + } + + img->currentx = 0; + img->currenty = unpack_16_le(buf+2); + if (img->currenty > img->pub.height) { + lbx_error_raise(LBX_EFORMAT); + return -1; + } + } + + img->read_state = READ_STATE_HEADER; + return 0; +} + +long lbx_img_read_row_header(struct lbx_image *pub, unsigned *x, unsigned *y) +{ + struct lbx_image_priv *img = (struct lbx_image_priv *)pub; + unsigned short length, offset; + unsigned char buf[4]; + + if (img->read_state != READ_STATE_HEADER) { + lbx_error_raise(LBX_EINVAL); + return -1; + } + + /* Raw images have no row headers */ + if (img->flags & FLAG_RAW) { + img->currentn = img->pub.width; + *y = img->currenty++; + *x = 0; + + if (*y < img->pub.height) { + img->read_state = READ_STATE_DATA; + return img->currentn; + } else { + img->read_state = READ_STATE_DONE; + return 0; + } + } + + do { + if (img->fops->read(buf, sizeof buf, img->f) != sizeof buf) { + if (img->fops->eof(img->f)) + lbx_error_raise(LBX_EEOF); + return -1; + } + + length = unpack_16_le(buf+0); + offset = unpack_16_le(buf+2); + + if (length == 0) { + if (offset == 1000) { + img->read_state = READ_STATE_DONE; + return 0; + } else if (offset > img->pub.height - img->currenty) { + lbx_error_raise(LBX_EFORMAT); + return -1; + } + + img->currenty += offset; + img->currentx = 0; + } + } while (length == 0); + + if (offset > img->pub.width - img->currentx) { + lbx_error_raise(LBX_EFORMAT); + return -1; + } + img->currentx += offset; + + if (length > img->pub.width - img->currentx) { + lbx_error_raise(LBX_EFORMAT); + return -1; + } + img->currentn = length; + + img->read_state = READ_STATE_DATA; + *x = img->currentx; + *y = img->currenty; + + return img->currentn; +} + +long lbx_img_read_row_data(struct lbx_image *pub, void *buf) +{ + struct lbx_image_priv *img = (struct lbx_image_priv *)pub; + + if (img->read_state != READ_STATE_DATA) { + lbx_error_raise(LBX_EINVAL); + return -1; + } + + if (img->fops->read(buf, img->currentn, img->f) != img->currentn) { + if (img->fops->eof(img->f)) + lbx_error_raise(LBX_EEOF); + return -1; + } + + if (!(img->flags & FLAG_RAW)) { + /* Skip padding byte, if any */ + if (img->currentn % 2) { + if (img->fops->seek(img->f, 1, SEEK_CUR)) + return -1; + } + } + + img->read_state = READ_STATE_HEADER; + img->currentx += img->currentn; + + return img->currentn; +} + static unsigned char **read_raw_frame(struct lbx_image_priv *img, int frame) { unsigned long size = img->pub.width * img->pub.height; + int rc; assert(img->flags & FLAG_RAW); - if (img->fops->seek(img->f, img->offsets[frame], SEEK_SET)) { + rc = lbx_img_seek(&img->pub, frame); + if (rc < 0) return NULL; - } if (img->fops->read(img->framedata[0], size, img->f) != size) { if (img->fops->eof(img->f)) @@ -373,28 +483,9 @@ unsigned char **lbx_img_getframe(struct lbx_image *pub, int frame) if (img->currentframe != frame) { int rc; - if (img->fops->seek(img->f, img->offsets[frame], SEEK_SET)) { - return NULL; - } - - /* Read frame header */ - if (img->fops->read(buf, 4, img->f) != 4) { - if (img->fops->eof(img->f)) - lbx_error_raise(LBX_EEOF); - return NULL; - } - - if (unpack_16_le(buf) != 1) { - lbx_error_raise(LBX_EFORMAT); - return NULL; - } - - img->currentx = 0; - img->currenty = unpack_16_le(buf+2); - if (img->currenty > img->pub.height) { - lbx_error_raise(LBX_EFORMAT); + rc = lbx_img_seek(pub, frame); + if (rc < 0) return NULL; - } do { rc = _lbx_drawrow(img); diff --git a/src/image.h b/src/image.h index 0a8dc99..880f7de 100644 --- a/src/image.h +++ b/src/image.h @@ -24,6 +24,10 @@ struct lbx_image *lbx_img_open(void *f, const struct lbx_file_ops *fops, struct lbx_image *lbx_img_fopen(const char *file); int lbx_img_close(struct lbx_image *img); +int lbx_img_seek(struct lbx_image *img, unsigned frame); +long lbx_img_read_row_header(struct lbx_image *img, unsigned *x, unsigned *y); +long lbx_img_read_row_data(struct lbx_image *img, void *buf); + unsigned char **lbx_img_getframe(struct lbx_image *img, int frame); unsigned char **lbx_img_getmask(struct lbx_image *img); -- 2.43.2