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)
{
{
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);
}
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;
}
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 {
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 {
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;
}
}
}
}
+ if(fmt == IMG_FMT_IDX8) {
+ struct img_colormap *dest = img_colormap(img);
+ *dest = cmap;
+ }
+
return 0;
}
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;
}
pix[1] = g;
pix[2] = b;
- if(rdalpha) {
+ if(fmt == IMG_FMT_RGBA32) {
if((a = iofgetc(io)) == -1) {
return -1;
}
#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);
{
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);
}
}
+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;
{
switch(fmt) {
case IMG_FMT_GREY8:
+ case IMG_FMT_IDX8:
return 1;
case IMG_FMT_RGB24:
return 3;