3dphotoshoot

annotate 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
rev   line source
nuclear@14 1 /*
nuclear@14 2 libimago - a multi-format image file input/output library.
nuclear@14 3 Copyright (C) 2010-2015 John Tsiombikas <nuclear@member.fsf.org>
nuclear@14 4
nuclear@14 5 This program is free software: you can redistribute it and/or modify
nuclear@14 6 it under the terms of the GNU Lesser General Public License as published
nuclear@14 7 by the Free Software Foundation, either version 3 of the License, or
nuclear@14 8 (at your option) any later version.
nuclear@14 9
nuclear@14 10 This program is distributed in the hope that it will be useful,
nuclear@14 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
nuclear@14 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
nuclear@14 13 GNU Lesser General Public License for more details.
nuclear@14 14
nuclear@14 15 You should have received a copy of the GNU Lesser General Public License
nuclear@14 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
nuclear@14 17 */
nuclear@14 18
nuclear@14 19 /* -- Targa (tga) module -- */
nuclear@14 20
nuclear@14 21 #include <string.h>
nuclear@14 22 #include <stdlib.h>
nuclear@14 23 #include <stdint.h>
nuclear@14 24 #include "imago2.h"
nuclear@14 25 #include "ftype_module.h"
nuclear@14 26
nuclear@14 27
nuclear@14 28 #if defined(__i386__) || defined(__ia64__) || defined(WIN32) || \
nuclear@14 29 (defined(__alpha__) || defined(__alpha)) || \
nuclear@14 30 defined(__arm__) || \
nuclear@14 31 (defined(__mips__) && defined(__MIPSEL__)) || \
nuclear@14 32 defined(__SYMBIAN32__) || \
nuclear@14 33 defined(__x86_64__) || \
nuclear@14 34 defined(__LITTLE_ENDIAN__)
nuclear@14 35 /* little endian */
nuclear@14 36 #define read_int16_le(f) read_int16(f)
nuclear@14 37 #else
nuclear@14 38 /* big endian */
nuclear@14 39 #define read_int16_le(f) read_int16_inv(f)
nuclear@14 40 #endif /* endian check */
nuclear@14 41
nuclear@14 42
nuclear@14 43 enum {
nuclear@14 44 IMG_NONE,
nuclear@14 45 IMG_CMAP,
nuclear@14 46 IMG_RGBA,
nuclear@14 47 IMG_BW,
nuclear@14 48
nuclear@14 49 IMG_RLE_CMAP = 9,
nuclear@14 50 IMG_RLE_RGBA,
nuclear@14 51 IMG_RLE_BW
nuclear@14 52 };
nuclear@14 53
nuclear@14 54 #define IS_RLE(x) ((x) >= IMG_RLE_CMAP)
nuclear@14 55 #define IS_RGBA(x) ((x) == IMG_RGBA || (x) == IMG_RLE_RGBA)
nuclear@14 56
nuclear@14 57
nuclear@14 58 struct tga_header {
nuclear@14 59 uint8_t idlen; /* id field length */
nuclear@14 60 uint8_t cmap_type; /* color map type (0:no color map, 1:color map present) */
nuclear@14 61 uint8_t img_type; /* image type:
nuclear@14 62 * 0: no image data
nuclear@14 63 * 1: uncomp. color-mapped 9: RLE color-mapped
nuclear@14 64 * 2: uncomp. true color 10: RLE true color
nuclear@14 65 * 3: uncomp. black/white 11: RLE black/white */
nuclear@14 66 uint16_t cmap_first; /* color map first entry index */
nuclear@14 67 uint16_t cmap_len; /* color map length */
nuclear@14 68 uint8_t cmap_entry_sz; /* color map entry size */
nuclear@14 69 uint16_t img_x; /* X-origin of the image */
nuclear@14 70 uint16_t img_y; /* Y-origin of the image */
nuclear@14 71 uint16_t img_width; /* image width */
nuclear@14 72 uint16_t img_height; /* image height */
nuclear@14 73 uint8_t img_bpp; /* bits per pixel */
nuclear@14 74 uint8_t img_desc; /* descriptor:
nuclear@14 75 * bits 0 - 3: alpha or overlay bits
nuclear@14 76 * bits 5 & 4: origin (0 = bottom/left, 1 = top/right)
nuclear@14 77 * bits 7 & 6: data interleaving */
nuclear@14 78 };
nuclear@14 79
nuclear@14 80 struct tga_footer {
nuclear@14 81 uint32_t ext_off; /* extension area offset */
nuclear@14 82 uint32_t devdir_off; /* developer directory offset */
nuclear@14 83 char sig[18]; /* signature with . and \0 */
nuclear@14 84 };
nuclear@14 85
nuclear@14 86
nuclear@14 87 static int check(struct img_io *io);
nuclear@14 88 static int read(struct img_pixmap *img, struct img_io *io);
nuclear@14 89 static int write(struct img_pixmap *img, struct img_io *io);
nuclear@14 90 static int read_pixel(struct img_io *io, int rdalpha, uint32_t *pix);
nuclear@14 91 static int16_t read_int16(struct img_io *io);
nuclear@14 92 static int16_t read_int16_inv(struct img_io *io);
nuclear@14 93
nuclear@14 94 int img_register_tga(void)
nuclear@14 95 {
nuclear@14 96 static struct ftype_module mod = {".tga", check, read, write};
nuclear@14 97 return img_register_module(&mod);
nuclear@14 98 }
nuclear@14 99
nuclear@14 100
nuclear@14 101 static int check(struct img_io *io)
nuclear@14 102 {
nuclear@14 103 struct tga_footer foot;
nuclear@14 104 int res = -1;
nuclear@14 105 long pos = io->seek(0, SEEK_CUR, io->uptr);
nuclear@14 106 io->seek(-18, SEEK_END, io->uptr);
nuclear@14 107
nuclear@14 108 if(io->read(foot.sig, 17, io->uptr) < 17) {
nuclear@14 109 io->seek(pos, SEEK_SET, io->uptr);
nuclear@14 110 return -1;
nuclear@14 111 }
nuclear@14 112
nuclear@14 113 if(memcmp(foot.sig, "TRUEVISION-XFILE.", 17) == 0) {
nuclear@14 114 res = 0;
nuclear@14 115 }
nuclear@14 116 io->seek(pos, SEEK_SET, io->uptr);
nuclear@14 117 return res;
nuclear@14 118 }
nuclear@14 119
nuclear@14 120 static int iofgetc(struct img_io *io)
nuclear@14 121 {
nuclear@14 122 char c;
nuclear@14 123 return io->read(&c, 1, io->uptr) < 1 ? -1 : c;
nuclear@14 124 }
nuclear@14 125
nuclear@14 126 static int read(struct img_pixmap *img, struct img_io *io)
nuclear@14 127 {
nuclear@14 128 struct tga_header hdr;
nuclear@14 129 unsigned long x, y;
nuclear@14 130 int i, c;
nuclear@14 131 uint32_t ppixel = 0;
nuclear@14 132 int rle_mode = 0, rle_pix_left = 0;
nuclear@14 133 int rdalpha;
nuclear@14 134
nuclear@14 135 /* read header */
nuclear@14 136 hdr.idlen = iofgetc(io);
nuclear@14 137 hdr.cmap_type = iofgetc(io);
nuclear@14 138 hdr.img_type = iofgetc(io);
nuclear@14 139 hdr.cmap_first = read_int16_le(io);
nuclear@14 140 hdr.cmap_len = read_int16_le(io);
nuclear@14 141 hdr.cmap_entry_sz = iofgetc(io);
nuclear@14 142 hdr.img_x = read_int16_le(io);
nuclear@14 143 hdr.img_y = read_int16_le(io);
nuclear@14 144 hdr.img_width = read_int16_le(io);
nuclear@14 145 hdr.img_height = read_int16_le(io);
nuclear@14 146 hdr.img_bpp = iofgetc(io);
nuclear@14 147 if((c = iofgetc(io)) == -1) {
nuclear@14 148 return -1;
nuclear@14 149 }
nuclear@14 150 hdr.img_desc = c;
nuclear@14 151
nuclear@14 152 if(!IS_RGBA(hdr.img_type)) {
nuclear@14 153 fprintf(stderr, "only true color tga images supported\n");
nuclear@14 154 return -1;
nuclear@14 155 }
nuclear@14 156
nuclear@14 157 io->seek(hdr.idlen, SEEK_CUR, io); /* skip the image ID */
nuclear@14 158
nuclear@14 159 /* skip the color map if it exists */
nuclear@14 160 if(hdr.cmap_type == 1) {
nuclear@14 161 io->seek(hdr.cmap_len * hdr.cmap_entry_sz / 8, SEEK_CUR, io);
nuclear@14 162 }
nuclear@14 163
nuclear@14 164 x = hdr.img_width;
nuclear@14 165 y = hdr.img_height;
nuclear@14 166 rdalpha = hdr.img_desc & 0xf;
nuclear@14 167
nuclear@14 168 /* TODO make this IMG_FMT_RGB24 if there's no alpha channel */
nuclear@14 169 if(img_set_pixels(img, x, y, IMG_FMT_RGBA32, 0) == -1) {
nuclear@14 170 return -1;
nuclear@14 171 }
nuclear@14 172
nuclear@14 173 for(i=0; i<y; i++) {
nuclear@14 174 uint32_t *ptr;
nuclear@14 175 int j;
nuclear@14 176
nuclear@14 177 ptr = (uint32_t*)img->pixels + ((hdr.img_desc & 0x20) ? i : y - (i + 1)) * x;
nuclear@14 178
nuclear@14 179 for(j=0; j<x; j++) {
nuclear@14 180 /* if the image is raw, then just read the next pixel */
nuclear@14 181 if(!IS_RLE(hdr.img_type)) {
nuclear@14 182 if(read_pixel(io, rdalpha, &ppixel) == -1) {
nuclear@14 183 return -1;
nuclear@14 184 }
nuclear@14 185 } else {
nuclear@14 186 /* otherwise, for RLE... */
nuclear@14 187
nuclear@14 188 /* if we have pixels left in the packet ... */
nuclear@14 189 if(rle_pix_left) {
nuclear@14 190 /* if it's a raw packet, read the next pixel, otherwise keep the same */
nuclear@14 191 if(!rle_mode) {
nuclear@14 192 if(read_pixel(io, rdalpha, &ppixel) == -1) {
nuclear@14 193 return -1;
nuclear@14 194 }
nuclear@14 195 }
nuclear@14 196 --rle_pix_left;
nuclear@14 197 } else {
nuclear@14 198 /* read RLE packet header */
nuclear@14 199 unsigned char phdr = iofgetc(io);
nuclear@14 200 rle_mode = (phdr & 128); /* last bit shows the mode for this packet (1: rle, 0: raw) */
nuclear@14 201 rle_pix_left = (phdr & ~128); /* the rest gives the count of pixels minus one (we also read one here, so no +1) */
nuclear@14 202 /* and read the first pixel of the packet */
nuclear@14 203 if(read_pixel(io, rdalpha, &ppixel) == -1) {
nuclear@14 204 return -1;
nuclear@14 205 }
nuclear@14 206 }
nuclear@14 207 }
nuclear@14 208
nuclear@14 209 *ptr++ = ppixel;
nuclear@14 210 }
nuclear@14 211 }
nuclear@14 212
nuclear@14 213 return 0;
nuclear@14 214 }
nuclear@14 215
nuclear@14 216 static int write(struct img_pixmap *img, struct img_io *io)
nuclear@14 217 {
nuclear@14 218 return -1; /* TODO */
nuclear@14 219 }
nuclear@14 220
nuclear@14 221 #define PACK_COLOR32(r,g,b,a) \
nuclear@14 222 ((((a) & 0xff) << 24) | \
nuclear@14 223 (((r) & 0xff) << 0) | \
nuclear@14 224 (((g) & 0xff) << 8) | \
nuclear@14 225 (((b) & 0xff) << 16))
nuclear@14 226
nuclear@14 227 static int read_pixel(struct img_io *io, int rdalpha, uint32_t *pix)
nuclear@14 228 {
nuclear@14 229 int r, g, b, a;
nuclear@14 230 b = iofgetc(io);
nuclear@14 231 g = iofgetc(io);
nuclear@14 232 r = iofgetc(io);
nuclear@14 233 a = rdalpha ? iofgetc(io) : 0xff;
nuclear@14 234 *pix = PACK_COLOR32(r, g, b, a);
nuclear@14 235 return a == -1 || r == -1 ? -1 : 0;
nuclear@14 236 }
nuclear@14 237
nuclear@14 238 static int16_t read_int16(struct img_io *io)
nuclear@14 239 {
nuclear@14 240 int16_t v;
nuclear@14 241 io->read(&v, 2, io);
nuclear@14 242 return v;
nuclear@14 243 }
nuclear@14 244
nuclear@14 245 static int16_t read_int16_inv(struct img_io *io)
nuclear@14 246 {
nuclear@14 247 int16_t v;
nuclear@14 248 io->read(&v, 2, io);
nuclear@14 249 return ((v >> 8) & 0xff) | (v << 8);
nuclear@14 250 }