+ return 0;
+}
+
+int
+lbximg_getpalette(struct lbx_image *img, struct lbx_colour palette[static 256])
+{
+ unsigned char entry[4];
+ unsigned int i;
+ size_t rc;
+
+ /* Do nothing if the image doesn't have embedded palette data. */
+ if (!(img->flags & FLAG_PALETTE))
+ return 0;
+
+ if (img->fops->seek(img->f, img->paloff, SEEK_SET)) {
+ lbx_errno = -errno;
+ return -1;
+ }
+
+ for (i = 0; i < img->palcount; i++) {
+ rc = img->fops->read(entry, sizeof entry, img->f);
+ if (rc < sizeof entry) {
+ goto readerr;
+ }
+
+ if (entry[0] != 0) {
+ lbx_errno = LBX_EFORMAT;
+ return -1;
+ }
+
+ palette[img->palstart + i] = (struct lbx_colour){
+ .red = entry[1] << 2,
+ .green = entry[2] << 2,
+ .blue = entry[3] << 2,
+ .active = 1,
+ };
+ }
+
+ return 0;
+readerr:
+ lbx_errno = img->fops->eof(img->f) ? LBX_EEOF : -errno;
+ return -1;
+}
+
+void lbximg_getinfo(struct lbx_image *img, struct lbx_imginfo *info)
+{
+ *info = (struct lbx_imginfo) {
+ .width = img->width,
+ .height = img->height,
+ .nframes = img->frames,
+ .palettesz = (img->flags & FLAG_PALETTE) ? img->palcount : 0,
+ };
+
+ /* There seems to be two ways of specifying that an image loops. */
+ if (img->flags & FLAG_LOOPING) {
+ info->loopstart = 0;
+ info->looping = 1;
+ } else if (img->leadin != img->frames - 1) {
+ info->loopstart = img->leadin;
+ info->looping = 1;
+ }
+}
+
+unsigned char **lbximg_getmask(struct lbx_image *img)
+{
+ return img->mask;
+}
+
+int lbximg_close(struct lbx_image *img)
+{
+ int rc = 0;
+
+ if (img) {
+ if (img->framedata) {
+ free(img->framedata[0]);
+ free(img->framedata);
+ }
+
+ if (img->mask) {
+ free(img->mask[0]);
+ free(img->mask);
+ }
+
+ if (img && img->dtor) {
+ rc = img->dtor(img->f);
+ }
+
+ free(img);