+int lbximg_loadpalette(FILE *f, struct lbx_colour palette[static 256])
+{
+ uint8_t entry[4];
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ if (fread(entry, sizeof entry, 1, f) != 1) {
+ lbx_errno = (feof(f)) ? LBX_EEOF : -errno;
+ return -1;
+ }
+
+ if (entry[0] != 1) {
+ lbx_errno = LBX_EFORMAT;
+ return -1;
+ }
+
+ palette[i] = (struct lbx_colour){
+ .red = entry[1] << 2,
+ .green = entry[2] << 2,
+ .blue = entry[3] << 2,
+ };
+ }
+
+ return 0;
+}
+
+int
+lbximg_getpalette(struct lbx_image *img, struct lbx_colour palette[static 256])
+{
+ unsigned int i;
+ size_t rc;
+
+ uint8_t entry[4];
+
+ /* Do nothing if the image doesn't have embedded palette data. */
+ if (!(img->flags & FLAG_PALETTE))
+ return 0;
+
+ if (_lbx_fseek(img->f, &img->foff, img->paloff) == -1)
+ return -1;
+
+ for (i = 0; i < img->palcount; i++) {
+ rc = fread(entry, 1, sizeof entry, img->f);
+ img->foff += rc;
+
+ 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,
+ };
+ }
+
+ return 0;
+readerr:
+ lbx_errno = feof(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;
+}
+