+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])
+{
+ size_t hdrlen = 6*(sizeof img->pal)+(img->offs)*(sizeof *img->offsets);
+ unsigned int i;
+ size_t rc;
+
+ uint16_t start, count;
+ uint8_t entry[4];
+
+ /* Do nothing if the image doesn't have embedded palette data. */
+ if (img->pal == 0)
+ return 0;
+
+ /* Palette data is located right after the header. */
+ if (_lbx_fseek(img->f, &img->foff, hdrlen) == -1)
+ return -1;
+
+ /* Palette header */
+ if (fread(&start, sizeof start, 1, img->f) != 1) goto readerr;
+ if (fread(&count, sizeof count, 1, img->f) != 1) goto readerr;
+ start = letohs(start); img->foff += sizeof start;
+ count = letohs(count); img->foff += sizeof count;
+
+ if (start + count > 256) {
+ lbx_errno = LBX_EFORMAT;
+ return -1;
+ }
+
+ if (hdrlen + 2*sizeof start + count*sizeof entry > img->offsets[0]) {
+ lbx_errno = LBX_EFORMAT;
+ return -1;
+ }
+
+ for (i = 0; i < count; 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[start + 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,
+ };
+}
+