started adding indexed color support to imago2 master
authorJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 14 Dec 2021 09:45:19 +0000 (11:45 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 14 Dec 2021 09:45:19 +0000 (11:45 +0200)
imago/src/byteord.h
imago/src/filetga.c
imago/src/imago2.c
imago/src/imago2.h

index c3c3858..6ac5f30 100644 (file)
@@ -18,7 +18,9 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #ifndef IMAGO_BYTEORD_H_
 #define IMAGO_BYTEORD_H_
 
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199900) || (defined(_MSC_VER) && _MSC_VER >= 1600)
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199900) || \
+       (defined(_MSC_VER) && _MSC_VER >= 1600) || \
+       (defined(__WATCOMC__) && __WATCOMC__ >= 1200)
 #include <stdint.h>
 #else
 #include <sys/types.h>
@@ -31,6 +33,7 @@ typedef short int16_t;
 typedef unsigned short uint16_t;
 typedef long int32_t;
 typedef unsigned long uint32_t;
+typedef unsigned long uintptr_t;
 #endif
 
 #include "imago2.h"
index 49f8f66..c92e396 100644 (file)
@@ -71,7 +71,7 @@ struct tga_footer {
 static int check(struct img_io *io);
 static int read_tga(struct img_pixmap *img, struct img_io *io);
 static int write_tga(struct img_pixmap *img, struct img_io *io);
-static int read_pixel(struct img_io *io, int rdalpha, unsigned char *pix);
+static int read_pixel(struct img_io *io, int fmt, unsigned char *pix);
 
 int img_register_tga(void)
 {
@@ -109,10 +109,11 @@ static int read_tga(struct img_pixmap *img, struct img_io *io)
 {
        struct tga_header hdr;
        unsigned long x, y;
-       int i, c;
+       int i, idx, c, r, g, b;
        int rle_mode = 0, rle_pix_left = 0;
-       int rdalpha;
        int pixel_bytes;
+       int fmt;
+       struct img_colormap cmap;
 
        /* read header */
        hdr.idlen = iofgetc(io);
@@ -131,24 +132,61 @@ static int read_tga(struct img_pixmap *img, struct img_io *io)
        }
        hdr.img_desc = c;
 
-       if(!IS_RGBA(hdr.img_type)) {
-               fprintf(stderr, "libimago: only true color tga images are supported\n");
-               return -1;
-       }
-
        io->seek(hdr.idlen, SEEK_CUR, io->uptr);        /* skip the image ID */
 
-       /* skip the color map if it exists */
+       /* read the color map if it exists */
        if(hdr.cmap_type == 1) {
-               io->seek(hdr.cmap_len * hdr.cmap_entry_sz / 8, SEEK_CUR, io->uptr);
+               cmap.ncolors = hdr.cmap_len;
+
+               for(i=0; i<hdr.cmap_len; i++) {
+                       switch(hdr.cmap_entry_sz) {
+                       case 16:
+                               c = img_read_int16_le(io);
+                               r = (c & 0x7c00) >> 7;
+                               g = (c & 0x03e0) >> 2;
+                               b = (c & 0x001f) << 3;
+                               break;
+
+                       case 24:
+                               b = iofgetc(io);
+                               g = iofgetc(io);
+                               r = iofgetc(io);
+                               break;
+
+                       case 32:
+                               b = iofgetc(io);
+                               g = iofgetc(io);
+                               r = iofgetc(io);
+                               iofgetc(io);    /* ignore attribute byte */
+                       }
+
+                       idx = i + hdr.cmap_first;
+                       if(idx < 256) {
+                               cmap.color[idx].r = r;
+                               cmap.color[idx].g = g;
+                               cmap.color[idx].b = b;
+                               if(cmap.ncolors <= idx) cmap.ncolors = idx + 1;
+                       }
+               }
        }
 
        x = hdr.img_width;
        y = hdr.img_height;
-       rdalpha = hdr.img_desc & 0xf;
-       pixel_bytes = rdalpha ? 4 : 3;
 
-       if(img_set_pixels(img, x, y, rdalpha ? IMG_FMT_RGBA32 : IMG_FMT_RGB24, 0) == -1) {
+       if(hdr.img_type == IMG_CMAP || hdr.img_type == IMG_RLE_CMAP) {
+               if(hdr.img_bpp != 8) {
+                       fprintf(stderr, "read_tga: indexed images with more than 8bpp not supported\n");
+                       return -1;
+               }
+               pixel_bytes = 1;
+               fmt = IMG_FMT_IDX8;
+       } else {
+               int alpha = hdr.img_desc & 0xf;
+               pixel_bytes = alpha ? 4 : 3;
+               fmt = alpha ? IMG_FMT_RGBA32 : IMG_FMT_RGB24;
+       }
+
+       if(img_set_pixels(img, x, y, fmt, 0) == -1) {
                return -1;
        }
 
@@ -161,7 +199,7 @@ static int read_tga(struct img_pixmap *img, struct img_io *io)
                for(j=0; j<x; j++) {
                        /* if the image is raw, then just read the next pixel */
                        if(!IS_RLE(hdr.img_type)) {
-                               if(read_pixel(io, rdalpha, ptr) == -1) {
+                               if(read_pixel(io, fmt, ptr) == -1) {
                                        return -1;
                                }
                        } else {
@@ -171,7 +209,7 @@ static int read_tga(struct img_pixmap *img, struct img_io *io)
                                if(rle_pix_left) {
                                        /* if it's a raw packet, read the next pixel, otherwise keep the same */
                                        if(!rle_mode) {
-                                               if(read_pixel(io, rdalpha, ptr) == -1) {
+                                               if(read_pixel(io, fmt, ptr) == -1) {
                                                        return -1;
                                                }
                                        } else {
@@ -186,7 +224,7 @@ static int read_tga(struct img_pixmap *img, struct img_io *io)
                                        rle_mode = (phdr & 128);                /* last bit shows the mode for this packet (1: rle, 0: raw) */
                                        rle_pix_left = (phdr & ~128);   /* the rest gives the count of pixels minus one (we also read one here, so no +1) */
                                        /* and read the first pixel of the packet */
-                                       if(read_pixel(io, rdalpha, ptr) == -1) {
+                                       if(read_pixel(io, fmt, ptr) == -1) {
                                                return -1;
                                        }
                                }
@@ -196,6 +234,11 @@ static int read_tga(struct img_pixmap *img, struct img_io *io)
                }
        }
 
+       if(fmt == IMG_FMT_IDX8) {
+               struct img_colormap *dest = img_colormap(img);
+               *dest = cmap;
+       }
+
        return 0;
 }
 
@@ -204,9 +247,18 @@ static int write_tga(struct img_pixmap *img, struct img_io *io)
        return -1;      /* TODO */
 }
 
-static int read_pixel(struct img_io *io, int rdalpha, unsigned char *pix)
+static int read_pixel(struct img_io *io, int fmt, unsigned char *pix)
 {
        int r, g, b, a;
+
+       if(fmt == IMG_FMT_IDX8) {
+               if((b = iofgetc(io)) == -1) {
+                       return -1;
+               }
+               *pix = b;
+               return 0;
+       }
+
        if((b = iofgetc(io)) == -1 || (g = iofgetc(io)) == -1 || (r = iofgetc(io)) == -1) {
                return -1;
        }
@@ -215,7 +267,7 @@ static int read_pixel(struct img_io *io, int rdalpha, unsigned char *pix)
        pix[1] = g;
        pix[2] = b;
 
-       if(rdalpha) {
+       if(fmt == IMG_FMT_RGBA32) {
                if((a = iofgetc(io)) == -1) {
                        return -1;
                }
index b4ec465..2480f82 100644 (file)
@@ -21,8 +21,13 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include <string.h>
 #include "imago2.h"
 #include "ftmodule.h"
+#include "byteord.h"
 #include "chkalloc.h"
 
+/* calculate int-aligned offset to colormap, right after the end of the pixel data */
+#define CMAPPTR(fb, fbsz)      \
+       (struct img_colormap*)((((uintptr_t)fb) + (fbsz) + sizeof(int) - 1) & ~(sizeof(int) - 1))
+
 static int pixel_size(enum img_fmt fmt);
 static size_t def_read(void *buf, size_t bytes, void *uptr);
 static size_t def_write(void *buf, size_t bytes, void *uptr);
@@ -94,15 +99,21 @@ int img_set_pixels(struct img_pixmap *img, int w, int h, enum img_fmt fmt, void
 {
        void *newpix;
        int pixsz = pixel_size(fmt);
+       int bsz = w * h * pixsz;
+
+       if(fmt == IMG_FMT_IDX8) {
+               /* add space for the colormap, and space to align it to sizeof(int) */
+               bsz += sizeof(struct img_colormap) + sizeof(int) - 1;
+       }
 
-       if(!(newpix = chk_malloc(w * h * pixsz))) {
+       if(!(newpix = chk_malloc(bsz))) {
                return -1;
        }
 
        if(pix) {
                memcpy(newpix, pix, w * h * pixsz);
        } else {
-               memset(newpix, 0, w * h * pixsz);
+               memset(newpix, 0, bsz);
        }
 
        chk_free(img->pixels);
@@ -397,6 +408,17 @@ void img_getpixel4f(struct img_pixmap *img, int x, int y, float *r, float *g, fl
        }
 }
 
+struct img_colormap *img_colormap(struct img_pixmap *img)
+{
+       int cmap_offs;
+
+       if(img->fmt != IMG_FMT_IDX8 || !img->pixels) {
+               return 0;
+       }
+
+       return CMAPPTR(img->pixels, img->width * img->height * img->pixelsz);
+}
+
 void img_io_set_user_data(struct img_io *io, void *uptr)
 {
        io->uptr = uptr;
@@ -422,6 +444,7 @@ static int pixel_size(enum img_fmt fmt)
 {
        switch(fmt) {
        case IMG_FMT_GREY8:
+       case IMG_FMT_IDX8:
                return 1;
        case IMG_FMT_RGB24:
                return 3;
index b6b5269..48bda1b 100644 (file)
@@ -37,6 +37,7 @@ enum img_fmt {
        IMG_FMT_RGBAF,
        IMG_FMT_BGRA32,
        IMG_FMT_RGB565,
+       IMG_FMT_IDX8,
 
        NUM_IMG_FMT
 };
@@ -49,6 +50,13 @@ struct img_pixmap {
        char *name;
 };
 
+struct img_colormap {
+       int ncolors;
+       struct {
+               unsigned char r, g, b;
+       } color[256];
+};
+
 struct img_io {
        void *uptr;     /* user-data */
 
@@ -160,6 +168,9 @@ void img_getpixel1f(struct img_pixmap *img, int x, int y, float *pix);
 void img_getpixel4i(struct img_pixmap *img, int x, int y, int *r, int *g, int *b, int *a);
 void img_getpixel4f(struct img_pixmap *img, int x, int y, float *r, float *g, float *b, float *a);
 
+/* For IMG_FMT_IDX8 pixmaps, returns a pointer to the colormap, null otherwise */
+struct img_colormap *img_colormap(struct img_pixmap *img);
+
 
 /* OpenGL helper functions */