]> git.draconx.ca Git - liblbx.git/commitdiff
liblbx: Implement new image reading API.
authorNick Bowler <nbowler@draconx.ca>
Thu, 23 Jan 2014 02:13:45 +0000 (21:13 -0500)
committerNick Bowler <nbowler@draconx.ca>
Thu, 23 Jan 2014 03:14:50 +0000 (22:14 -0500)
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
src/image.h

index b30f165f159e4345449a4b6dc2ab50bef17d3d11..0caca9631aec54890711df84047de20dd93a6962 100644 (file)
 
 #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);
index 0a8dc99c6d1de95d631a9f5d6c22ae57863f363d..880f7dea3a577df6f8b2b2d7a6e2e409ecd15ace 100644 (file)
@@ -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);