nuclear@14: /* nuclear@14: libimago - a multi-format image file input/output library. nuclear@14: Copyright (C) 2010-2015 John Tsiombikas nuclear@14: nuclear@14: This program is free software: you can redistribute it and/or modify nuclear@14: it under the terms of the GNU Lesser General Public License as published nuclear@14: by the Free Software Foundation, either version 3 of the License, or nuclear@14: (at your option) any later version. nuclear@14: nuclear@14: This program is distributed in the hope that it will be useful, nuclear@14: but WITHOUT ANY WARRANTY; without even the implied warranty of nuclear@14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nuclear@14: GNU Lesser General Public License for more details. nuclear@14: nuclear@14: You should have received a copy of the GNU Lesser General Public License nuclear@14: along with this program. If not, see . nuclear@14: */ nuclear@14: nuclear@14: /* -- Targa (tga) module -- */ nuclear@14: nuclear@14: #include nuclear@14: #include nuclear@14: #include nuclear@14: #include "imago2.h" nuclear@14: #include "ftype_module.h" nuclear@14: nuclear@14: nuclear@14: #if defined(__i386__) || defined(__ia64__) || defined(WIN32) || \ nuclear@14: (defined(__alpha__) || defined(__alpha)) || \ nuclear@14: defined(__arm__) || \ nuclear@14: (defined(__mips__) && defined(__MIPSEL__)) || \ nuclear@14: defined(__SYMBIAN32__) || \ nuclear@14: defined(__x86_64__) || \ nuclear@14: defined(__LITTLE_ENDIAN__) nuclear@14: /* little endian */ nuclear@14: #define read_int16_le(f) read_int16(f) nuclear@14: #else nuclear@14: /* big endian */ nuclear@14: #define read_int16_le(f) read_int16_inv(f) nuclear@14: #endif /* endian check */ nuclear@14: nuclear@14: nuclear@14: enum { nuclear@14: IMG_NONE, nuclear@14: IMG_CMAP, nuclear@14: IMG_RGBA, nuclear@14: IMG_BW, nuclear@14: nuclear@14: IMG_RLE_CMAP = 9, nuclear@14: IMG_RLE_RGBA, nuclear@14: IMG_RLE_BW nuclear@14: }; nuclear@14: nuclear@14: #define IS_RLE(x) ((x) >= IMG_RLE_CMAP) nuclear@14: #define IS_RGBA(x) ((x) == IMG_RGBA || (x) == IMG_RLE_RGBA) nuclear@14: nuclear@14: nuclear@14: struct tga_header { nuclear@14: uint8_t idlen; /* id field length */ nuclear@14: uint8_t cmap_type; /* color map type (0:no color map, 1:color map present) */ nuclear@14: uint8_t img_type; /* image type: nuclear@14: * 0: no image data nuclear@14: * 1: uncomp. color-mapped 9: RLE color-mapped nuclear@14: * 2: uncomp. true color 10: RLE true color nuclear@14: * 3: uncomp. black/white 11: RLE black/white */ nuclear@14: uint16_t cmap_first; /* color map first entry index */ nuclear@14: uint16_t cmap_len; /* color map length */ nuclear@14: uint8_t cmap_entry_sz; /* color map entry size */ nuclear@14: uint16_t img_x; /* X-origin of the image */ nuclear@14: uint16_t img_y; /* Y-origin of the image */ nuclear@14: uint16_t img_width; /* image width */ nuclear@14: uint16_t img_height; /* image height */ nuclear@14: uint8_t img_bpp; /* bits per pixel */ nuclear@14: uint8_t img_desc; /* descriptor: nuclear@14: * bits 0 - 3: alpha or overlay bits nuclear@14: * bits 5 & 4: origin (0 = bottom/left, 1 = top/right) nuclear@14: * bits 7 & 6: data interleaving */ nuclear@14: }; nuclear@14: nuclear@14: struct tga_footer { nuclear@14: uint32_t ext_off; /* extension area offset */ nuclear@14: uint32_t devdir_off; /* developer directory offset */ nuclear@14: char sig[18]; /* signature with . and \0 */ nuclear@14: }; nuclear@14: nuclear@14: nuclear@14: static int check(struct img_io *io); nuclear@14: static int read(struct img_pixmap *img, struct img_io *io); nuclear@14: static int write(struct img_pixmap *img, struct img_io *io); nuclear@14: static int read_pixel(struct img_io *io, int rdalpha, uint32_t *pix); nuclear@14: static int16_t read_int16(struct img_io *io); nuclear@14: static int16_t read_int16_inv(struct img_io *io); nuclear@14: nuclear@14: int img_register_tga(void) nuclear@14: { nuclear@14: static struct ftype_module mod = {".tga", check, read, write}; nuclear@14: return img_register_module(&mod); nuclear@14: } nuclear@14: nuclear@14: nuclear@14: static int check(struct img_io *io) nuclear@14: { nuclear@14: struct tga_footer foot; nuclear@14: int res = -1; nuclear@14: long pos = io->seek(0, SEEK_CUR, io->uptr); nuclear@14: io->seek(-18, SEEK_END, io->uptr); nuclear@14: nuclear@14: if(io->read(foot.sig, 17, io->uptr) < 17) { nuclear@14: io->seek(pos, SEEK_SET, io->uptr); nuclear@14: return -1; nuclear@14: } nuclear@14: nuclear@14: if(memcmp(foot.sig, "TRUEVISION-XFILE.", 17) == 0) { nuclear@14: res = 0; nuclear@14: } nuclear@14: io->seek(pos, SEEK_SET, io->uptr); nuclear@14: return res; nuclear@14: } nuclear@14: nuclear@14: static int iofgetc(struct img_io *io) nuclear@14: { nuclear@14: char c; nuclear@14: return io->read(&c, 1, io->uptr) < 1 ? -1 : c; nuclear@14: } nuclear@14: nuclear@14: static int read(struct img_pixmap *img, struct img_io *io) nuclear@14: { nuclear@14: struct tga_header hdr; nuclear@14: unsigned long x, y; nuclear@14: int i, c; nuclear@14: uint32_t ppixel = 0; nuclear@14: int rle_mode = 0, rle_pix_left = 0; nuclear@14: int rdalpha; nuclear@14: nuclear@14: /* read header */ nuclear@14: hdr.idlen = iofgetc(io); nuclear@14: hdr.cmap_type = iofgetc(io); nuclear@14: hdr.img_type = iofgetc(io); nuclear@14: hdr.cmap_first = read_int16_le(io); nuclear@14: hdr.cmap_len = read_int16_le(io); nuclear@14: hdr.cmap_entry_sz = iofgetc(io); nuclear@14: hdr.img_x = read_int16_le(io); nuclear@14: hdr.img_y = read_int16_le(io); nuclear@14: hdr.img_width = read_int16_le(io); nuclear@14: hdr.img_height = read_int16_le(io); nuclear@14: hdr.img_bpp = iofgetc(io); nuclear@14: if((c = iofgetc(io)) == -1) { nuclear@14: return -1; nuclear@14: } nuclear@14: hdr.img_desc = c; nuclear@14: nuclear@14: if(!IS_RGBA(hdr.img_type)) { nuclear@14: fprintf(stderr, "only true color tga images supported\n"); nuclear@14: return -1; nuclear@14: } nuclear@14: nuclear@14: io->seek(hdr.idlen, SEEK_CUR, io); /* skip the image ID */ nuclear@14: nuclear@14: /* skip the color map if it exists */ nuclear@14: if(hdr.cmap_type == 1) { nuclear@14: io->seek(hdr.cmap_len * hdr.cmap_entry_sz / 8, SEEK_CUR, io); nuclear@14: } nuclear@14: nuclear@14: x = hdr.img_width; nuclear@14: y = hdr.img_height; nuclear@14: rdalpha = hdr.img_desc & 0xf; nuclear@14: nuclear@14: /* TODO make this IMG_FMT_RGB24 if there's no alpha channel */ nuclear@14: if(img_set_pixels(img, x, y, IMG_FMT_RGBA32, 0) == -1) { nuclear@14: return -1; nuclear@14: } nuclear@14: nuclear@14: for(i=0; ipixels + ((hdr.img_desc & 0x20) ? i : y - (i + 1)) * x; nuclear@14: nuclear@14: for(j=0; jread(&v, 2, io); nuclear@14: return v; nuclear@14: } nuclear@14: nuclear@14: static int16_t read_int16_inv(struct img_io *io) nuclear@14: { nuclear@14: int16_t v; nuclear@14: io->read(&v, 2, io); nuclear@14: return ((v >> 8) & 0xff) | (v << 8); nuclear@14: }