3dphotoshoot
diff libs/imago/file_tga.c @ 14:06dc8b9b4f89
added libimago, libjpeg and libpng
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 07 Jun 2015 17:25:49 +0300 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/imago/file_tga.c Sun Jun 07 17:25:49 2015 +0300 1.3 @@ -0,0 +1,250 @@ 1.4 +/* 1.5 +libimago - a multi-format image file input/output library. 1.6 +Copyright (C) 2010-2015 John Tsiombikas <nuclear@member.fsf.org> 1.7 + 1.8 +This program is free software: you can redistribute it and/or modify 1.9 +it under the terms of the GNU Lesser General Public License as published 1.10 +by the Free Software Foundation, either version 3 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU Lesser General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU Lesser General Public License 1.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 1.20 +*/ 1.21 + 1.22 +/* -- Targa (tga) module -- */ 1.23 + 1.24 +#include <string.h> 1.25 +#include <stdlib.h> 1.26 +#include <stdint.h> 1.27 +#include "imago2.h" 1.28 +#include "ftype_module.h" 1.29 + 1.30 + 1.31 +#if defined(__i386__) || defined(__ia64__) || defined(WIN32) || \ 1.32 + (defined(__alpha__) || defined(__alpha)) || \ 1.33 + defined(__arm__) || \ 1.34 + (defined(__mips__) && defined(__MIPSEL__)) || \ 1.35 + defined(__SYMBIAN32__) || \ 1.36 + defined(__x86_64__) || \ 1.37 + defined(__LITTLE_ENDIAN__) 1.38 +/* little endian */ 1.39 +#define read_int16_le(f) read_int16(f) 1.40 +#else 1.41 +/* big endian */ 1.42 +#define read_int16_le(f) read_int16_inv(f) 1.43 +#endif /* endian check */ 1.44 + 1.45 + 1.46 +enum { 1.47 + IMG_NONE, 1.48 + IMG_CMAP, 1.49 + IMG_RGBA, 1.50 + IMG_BW, 1.51 + 1.52 + IMG_RLE_CMAP = 9, 1.53 + IMG_RLE_RGBA, 1.54 + IMG_RLE_BW 1.55 +}; 1.56 + 1.57 +#define IS_RLE(x) ((x) >= IMG_RLE_CMAP) 1.58 +#define IS_RGBA(x) ((x) == IMG_RGBA || (x) == IMG_RLE_RGBA) 1.59 + 1.60 + 1.61 +struct tga_header { 1.62 + uint8_t idlen; /* id field length */ 1.63 + uint8_t cmap_type; /* color map type (0:no color map, 1:color map present) */ 1.64 + uint8_t img_type; /* image type: 1.65 + * 0: no image data 1.66 + * 1: uncomp. color-mapped 9: RLE color-mapped 1.67 + * 2: uncomp. true color 10: RLE true color 1.68 + * 3: uncomp. black/white 11: RLE black/white */ 1.69 + uint16_t cmap_first; /* color map first entry index */ 1.70 + uint16_t cmap_len; /* color map length */ 1.71 + uint8_t cmap_entry_sz; /* color map entry size */ 1.72 + uint16_t img_x; /* X-origin of the image */ 1.73 + uint16_t img_y; /* Y-origin of the image */ 1.74 + uint16_t img_width; /* image width */ 1.75 + uint16_t img_height; /* image height */ 1.76 + uint8_t img_bpp; /* bits per pixel */ 1.77 + uint8_t img_desc; /* descriptor: 1.78 + * bits 0 - 3: alpha or overlay bits 1.79 + * bits 5 & 4: origin (0 = bottom/left, 1 = top/right) 1.80 + * bits 7 & 6: data interleaving */ 1.81 +}; 1.82 + 1.83 +struct tga_footer { 1.84 + uint32_t ext_off; /* extension area offset */ 1.85 + uint32_t devdir_off; /* developer directory offset */ 1.86 + char sig[18]; /* signature with . and \0 */ 1.87 +}; 1.88 + 1.89 + 1.90 +static int check(struct img_io *io); 1.91 +static int read(struct img_pixmap *img, struct img_io *io); 1.92 +static int write(struct img_pixmap *img, struct img_io *io); 1.93 +static int read_pixel(struct img_io *io, int rdalpha, uint32_t *pix); 1.94 +static int16_t read_int16(struct img_io *io); 1.95 +static int16_t read_int16_inv(struct img_io *io); 1.96 + 1.97 +int img_register_tga(void) 1.98 +{ 1.99 + static struct ftype_module mod = {".tga", check, read, write}; 1.100 + return img_register_module(&mod); 1.101 +} 1.102 + 1.103 + 1.104 +static int check(struct img_io *io) 1.105 +{ 1.106 + struct tga_footer foot; 1.107 + int res = -1; 1.108 + long pos = io->seek(0, SEEK_CUR, io->uptr); 1.109 + io->seek(-18, SEEK_END, io->uptr); 1.110 + 1.111 + if(io->read(foot.sig, 17, io->uptr) < 17) { 1.112 + io->seek(pos, SEEK_SET, io->uptr); 1.113 + return -1; 1.114 + } 1.115 + 1.116 + if(memcmp(foot.sig, "TRUEVISION-XFILE.", 17) == 0) { 1.117 + res = 0; 1.118 + } 1.119 + io->seek(pos, SEEK_SET, io->uptr); 1.120 + return res; 1.121 +} 1.122 + 1.123 +static int iofgetc(struct img_io *io) 1.124 +{ 1.125 + char c; 1.126 + return io->read(&c, 1, io->uptr) < 1 ? -1 : c; 1.127 +} 1.128 + 1.129 +static int read(struct img_pixmap *img, struct img_io *io) 1.130 +{ 1.131 + struct tga_header hdr; 1.132 + unsigned long x, y; 1.133 + int i, c; 1.134 + uint32_t ppixel = 0; 1.135 + int rle_mode = 0, rle_pix_left = 0; 1.136 + int rdalpha; 1.137 + 1.138 + /* read header */ 1.139 + hdr.idlen = iofgetc(io); 1.140 + hdr.cmap_type = iofgetc(io); 1.141 + hdr.img_type = iofgetc(io); 1.142 + hdr.cmap_first = read_int16_le(io); 1.143 + hdr.cmap_len = read_int16_le(io); 1.144 + hdr.cmap_entry_sz = iofgetc(io); 1.145 + hdr.img_x = read_int16_le(io); 1.146 + hdr.img_y = read_int16_le(io); 1.147 + hdr.img_width = read_int16_le(io); 1.148 + hdr.img_height = read_int16_le(io); 1.149 + hdr.img_bpp = iofgetc(io); 1.150 + if((c = iofgetc(io)) == -1) { 1.151 + return -1; 1.152 + } 1.153 + hdr.img_desc = c; 1.154 + 1.155 + if(!IS_RGBA(hdr.img_type)) { 1.156 + fprintf(stderr, "only true color tga images supported\n"); 1.157 + return -1; 1.158 + } 1.159 + 1.160 + io->seek(hdr.idlen, SEEK_CUR, io); /* skip the image ID */ 1.161 + 1.162 + /* skip the color map if it exists */ 1.163 + if(hdr.cmap_type == 1) { 1.164 + io->seek(hdr.cmap_len * hdr.cmap_entry_sz / 8, SEEK_CUR, io); 1.165 + } 1.166 + 1.167 + x = hdr.img_width; 1.168 + y = hdr.img_height; 1.169 + rdalpha = hdr.img_desc & 0xf; 1.170 + 1.171 + /* TODO make this IMG_FMT_RGB24 if there's no alpha channel */ 1.172 + if(img_set_pixels(img, x, y, IMG_FMT_RGBA32, 0) == -1) { 1.173 + return -1; 1.174 + } 1.175 + 1.176 + for(i=0; i<y; i++) { 1.177 + uint32_t *ptr; 1.178 + int j; 1.179 + 1.180 + ptr = (uint32_t*)img->pixels + ((hdr.img_desc & 0x20) ? i : y - (i + 1)) * x; 1.181 + 1.182 + for(j=0; j<x; j++) { 1.183 + /* if the image is raw, then just read the next pixel */ 1.184 + if(!IS_RLE(hdr.img_type)) { 1.185 + if(read_pixel(io, rdalpha, &ppixel) == -1) { 1.186 + return -1; 1.187 + } 1.188 + } else { 1.189 + /* otherwise, for RLE... */ 1.190 + 1.191 + /* if we have pixels left in the packet ... */ 1.192 + if(rle_pix_left) { 1.193 + /* if it's a raw packet, read the next pixel, otherwise keep the same */ 1.194 + if(!rle_mode) { 1.195 + if(read_pixel(io, rdalpha, &ppixel) == -1) { 1.196 + return -1; 1.197 + } 1.198 + } 1.199 + --rle_pix_left; 1.200 + } else { 1.201 + /* read RLE packet header */ 1.202 + unsigned char phdr = iofgetc(io); 1.203 + rle_mode = (phdr & 128); /* last bit shows the mode for this packet (1: rle, 0: raw) */ 1.204 + rle_pix_left = (phdr & ~128); /* the rest gives the count of pixels minus one (we also read one here, so no +1) */ 1.205 + /* and read the first pixel of the packet */ 1.206 + if(read_pixel(io, rdalpha, &ppixel) == -1) { 1.207 + return -1; 1.208 + } 1.209 + } 1.210 + } 1.211 + 1.212 + *ptr++ = ppixel; 1.213 + } 1.214 + } 1.215 + 1.216 + return 0; 1.217 +} 1.218 + 1.219 +static int write(struct img_pixmap *img, struct img_io *io) 1.220 +{ 1.221 + return -1; /* TODO */ 1.222 +} 1.223 + 1.224 +#define PACK_COLOR32(r,g,b,a) \ 1.225 + ((((a) & 0xff) << 24) | \ 1.226 + (((r) & 0xff) << 0) | \ 1.227 + (((g) & 0xff) << 8) | \ 1.228 + (((b) & 0xff) << 16)) 1.229 + 1.230 +static int read_pixel(struct img_io *io, int rdalpha, uint32_t *pix) 1.231 +{ 1.232 + int r, g, b, a; 1.233 + b = iofgetc(io); 1.234 + g = iofgetc(io); 1.235 + r = iofgetc(io); 1.236 + a = rdalpha ? iofgetc(io) : 0xff; 1.237 + *pix = PACK_COLOR32(r, g, b, a); 1.238 + return a == -1 || r == -1 ? -1 : 0; 1.239 +} 1.240 + 1.241 +static int16_t read_int16(struct img_io *io) 1.242 +{ 1.243 + int16_t v; 1.244 + io->read(&v, 2, io); 1.245 + return v; 1.246 +} 1.247 + 1.248 +static int16_t read_int16_inv(struct img_io *io) 1.249 +{ 1.250 + int16_t v; 1.251 + io->read(&v, 2, io); 1.252 + return ((v >> 8) & 0xff) | (v << 8); 1.253 +}