/* * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** * $Id$ */ /** \file blender/imbuf/intern/targa.c * \ingroup imbuf */ #ifdef WIN32 #include #endif #include "BLI_blenlib.h" #include "MEM_guardedalloc.h" #include "imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_allocimbuf.h" #include "IMB_filetype.h" /* this one is only def-ed once, strangely... related to GS? */ #define GSS(x) (((uchar *)(x))[1] << 8 | ((uchar *)(x))[0]) /***/ typedef struct TARGA { unsigned char numid; unsigned char maptyp; unsigned char imgtyp; short maporig; short mapsize; unsigned char mapbits; short xorig; short yorig; short xsize; short ysize; unsigned char pixsize; unsigned char imgdes; } TARGA; /***/ static int tga_out1(unsigned int data, FILE *file) { uchar *p; p = (uchar *) & data; if (putc(p[0],file) == EOF) return(EOF); return (~EOF); } static int tga_out2(unsigned int data, FILE * file) { uchar *p; p = (uchar *) & data; if (putc(p[0],file) == EOF) return(EOF); if (putc(p[1],file) == EOF) return(EOF); return (~EOF); } static int tga_out3(unsigned int data, FILE * file) { uchar *p; p = (uchar *) & data; if (putc(p[2],file) == EOF) return(EOF); if (putc(p[1],file) == EOF) return(EOF); if (putc(p[0],file) == EOF) return(EOF); return (~EOF); } static int tga_out4(unsigned int data, FILE * file) { uchar *p; p = (uchar *) & data; /* order = bgra */ if (putc(p[2],file) == EOF) return(EOF); if (putc(p[1],file) == EOF) return(EOF); if (putc(p[0],file) == EOF) return(EOF); if (putc(p[3],file) == EOF) return(EOF); return (~EOF); } static short makebody_tga(ImBuf * ibuf, FILE * file, int (*out)(unsigned int, FILE*)) { register int last,this; register int copy, bytes; register unsigned int *rect, *rectstart, *temp; int y; for (y = 0; y < ibuf->y; y++) { bytes = ibuf->x - 1; rectstart = rect = ibuf->rect + (y * ibuf->x); last = *rect++; this = *rect++; copy = last^this; while (bytes > 0){ if (copy){ do{ last = this; this = *rect++; if (last == this){ if (this == rect[-3]){ /* three the same? */ bytes --; /* set bytes */ break; } } }while (--bytes != 0); copy = rect-rectstart; copy --; if (bytes) copy -= 2; temp = rect; rect = rectstart; while (copy){ last = copy; if (copy>=128) last = 128; copy -= last; if (fputc(last-1,file) == EOF) return(0); do{ if (out(*rect++,file) == EOF) return(0); }while(--last != 0); } rectstart = rect; rect = temp; last = this; copy = FALSE; } else { while (*rect++ == this){ /* seek for first different byte */ if (--bytes == 0) break; /* oor end of line */ } rect --; copy = rect-rectstart; rectstart = rect; bytes --; this = *rect++; while (copy){ if (copy>128){ if (fputc(255,file) == EOF) return(0); copy -= 128; } else { if (copy == 1){ if (fputc(0,file) == EOF) return(0); } else if (fputc(127 + copy,file) == EOF) return(0); copy = 0; } if (out(last,file) == EOF) return(0); } copy=TRUE; } } } return (1); } static int dumptarga(struct ImBuf * ibuf, FILE * file) { int size; uchar *rect; if (ibuf == NULL) return (0); if (ibuf->rect == NULL) return (0); size = ibuf->x * ibuf->y; rect = (uchar *) ibuf->rect; if (ibuf->depth <= 8) { while(size > 0){ if (putc(*rect, file) == EOF) return (0); size--; rect += 4; } } else if (ibuf->depth <= 16) { while(size > 0){ putc(rect[0], file); if (putc(rect[1], file) == EOF) return (0); size--; rect += 4; } } else if (ibuf->depth <= 24) { while(size > 0){ putc(rect[2], file); putc(rect[1], file); if (putc(rect[0], file) == EOF) return (0); size--; rect += 4; } } else if (ibuf->depth <= 32) { while(size > 0){ putc(rect[2], file); putc(rect[1], file); putc(rect[0], file); if (putc(rect[3], file) == EOF) return (0); size--; rect += 4; } } else return (0); return (1); } int imb_savetarga(struct ImBuf * ibuf, const char *name, int flags) { char buf[20]= {0}; FILE *fildes; short ok = 0; (void)flags; /* unused */ buf[16] = (ibuf->depth + 0x7 ) & ~0x7; if (ibuf->depth > 8 ){ buf[2] = 10; } else{ buf[2] = 11; } if (ibuf->ftype == RAWTGA) buf[2] &= ~8; buf[8] = 0; buf[9] = 0; buf[10] = 0; buf[11] = 0; buf[12] = ibuf->x & 0xff; buf[13] = ibuf->x >> 8; buf[14] = ibuf->y & 0xff; buf[15] = ibuf->y >> 8; /* Don't forget to indicate that your 32 bit * targa uses 8 bits for the alpha channel! */ if (ibuf->depth==32) { buf[17] |= 0x08; } fildes = fopen(name,"wb"); if (!fildes) return 0; if (fwrite(buf, 1, 18,fildes) != 18) { fclose(fildes); return (0); } if (ibuf->ftype == RAWTGA) { ok = dumptarga(ibuf, fildes); } else { switch((ibuf->depth + 7) >> 3){ case 1: ok = makebody_tga(ibuf, fildes, tga_out1); break; case 2: ok = makebody_tga(ibuf, fildes, tga_out2); break; case 3: ok = makebody_tga(ibuf, fildes, tga_out3); break; case 4: ok = makebody_tga(ibuf, fildes, tga_out4); break; } } fclose(fildes); return (ok); } static int checktarga(TARGA *tga, unsigned char *mem) { tga->numid = mem[0]; tga->maptyp = mem[1]; tga->imgtyp = mem[2]; tga->maporig = GSS(mem+3); tga->mapsize = GSS(mem+5); tga->mapbits = mem[7]; tga->xorig = GSS(mem+8); tga->yorig = GSS(mem+10); tga->xsize = GSS(mem+12); tga->ysize = GSS(mem+14); tga->pixsize = mem[16]; tga->imgdes = mem[17]; if (tga->maptyp > 1) return(0); switch (tga->imgtyp){ case 1: /* raw cmap */ case 2: /* raw rgb */ case 3: /* raw b&w */ case 9: /* cmap */ case 10: /* rgb */ case 11: /* b&w */ break; default: return(0); } if (tga->mapsize && tga->mapbits > 32) return(0); if (tga->xsize <= 0 || tga->xsize >= 8192) return(0); if (tga->ysize <= 0 || tga->ysize >= 8192) return(0); if (tga->pixsize > 32) return(0); if (tga->pixsize == 0) return(0); return(1); } int imb_is_a_targa(unsigned char *buf) { TARGA tga; return checktarga(&tga, buf); } static void complete_partial_load(struct ImBuf *ibuf, unsigned int *rect) { int size = (ibuf->x * ibuf->y) - (rect - ibuf->rect); if(size) { printf("decodetarga: incomplete file, %.1f%% missing\n", 100*((float)size / (ibuf->x * ibuf->y))); /* not essential but makes displaying partially rendered TGA's less ugly */ memset(rect, 0, size); } else { /* shouldnt happen */ printf("decodetarga: incomplete file, all pixels written\n"); } } static void decodetarga(struct ImBuf *ibuf, unsigned char *mem, size_t mem_size, int psize) { unsigned char *mem_end = mem+mem_size; int count, col, size; unsigned int *rect; uchar * cp = (uchar *) &col; if (ibuf == NULL) return; if (ibuf->rect == NULL) return; size = ibuf->x * ibuf->y; rect = ibuf->rect; /* set alpha */ cp[0] = 0xff; cp[1] = cp[2] = 0; while(size > 0){ count = *mem++; if(mem>mem_end) goto partial_load; if (count >= 128) { /*if (count == 128) printf("TARGA: 128 in file !\n");*/ count -= 127; if (psize & 2){ if (psize & 1){ /* order = bgra */ cp[0] = mem[3]; cp[1] = mem[0]; cp[2] = mem[1]; cp[3] = mem[2]; /*col = (mem[3] << 24) + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/ mem += 4; } else{ cp[1] = mem[0]; cp[2] = mem[1]; cp[3] = mem[2]; /*col = 0xff000000 + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/ mem += 3; } } else{ if (psize & 1){ cp[0] = mem[0]; cp[1] = mem[1]; mem += 2; } else{ col = *mem++; } } size -= count; if (size >= 0) { while (count > 0) { *rect++ = col; count--; } } } else{ count ++; size -= count; if (size >= 0) { while (count > 0){ if (psize & 2){ if (psize & 1){ /* order = bgra */ cp[0] = mem[3]; cp[1] = mem[0]; cp[2] = mem[1]; cp[3] = mem[2]; /*col = (mem[3] << 24) + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/ mem += 4; } else{ cp[1] = mem[0]; cp[2] = mem[1]; cp[3] = mem[2]; /*col = 0xff000000 + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/ mem += 3; } } else{ if (psize & 1){ cp[0] = mem[0]; cp[1] = mem[1]; mem += 2; } else{ col = *mem++; } } *rect++ = col; count --; if(mem>mem_end) goto partial_load; } if(mem>mem_end) goto partial_load; } } } if (size) { printf("decodetarga: count would overwrite %d pixels\n", -size); } return; partial_load: complete_partial_load(ibuf, rect); } static void ldtarga(struct ImBuf * ibuf,unsigned char * mem, size_t mem_size, int psize) { unsigned char *mem_end = mem+mem_size; int col,size; unsigned int *rect; uchar * cp = (uchar *) &col; if (ibuf == NULL) return; if (ibuf->rect == NULL) return; size = ibuf->x * ibuf->y; rect = ibuf->rect; /* set alpha */ cp[0] = 0xff; cp[1] = cp[2] = 0; while(size > 0){ if(mem>mem_end) goto partial_load; if (psize & 2){ if (psize & 1){ /* order = bgra */ cp[0] = mem[3]; cp[1] = mem[0]; cp[2] = mem[1]; cp[3] = mem[2]; /*col = (mem[3] << 24) + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/ mem += 4; } else{ /* set alpha for 24 bits colors */ cp[1] = mem[0]; cp[2] = mem[1]; cp[3] = mem[2]; /*col = 0xff000000 + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/ mem += 3; } } else{ if (psize & 1){ cp[0] = mem[0]; cp[1] = mem[1]; mem += 2; } else{ col = *mem++; } } *rect++ = col; size--; } return; partial_load: complete_partial_load(ibuf, rect); } struct ImBuf *imb_loadtarga(unsigned char *mem, size_t mem_size, int flags) { TARGA tga; struct ImBuf * ibuf; int col, count, size; unsigned int *rect, *cmap= NULL /*, mincol= 0*/, maxcol= 0; uchar * cp = (uchar *) &col; if (checktarga(&tga,mem) == 0) return(NULL); if (flags & IB_test) ibuf = IMB_allocImBuf(tga.xsize,tga.ysize,tga.pixsize, 0); else ibuf = IMB_allocImBuf(tga.xsize,tga.ysize,(tga.pixsize + 0x7) & ~0x7, IB_rect); if (ibuf == NULL) return(NULL); ibuf->ftype = TGA; ibuf->profile = IB_PROFILE_SRGB; mem = mem + 18 + tga.numid; cp[0] = 0xff; cp[1] = cp[2] = 0; if (tga.mapsize){ /* load color map */ /*mincol = tga.maporig;*/ /*UNUSED*/ maxcol = tga.mapsize; cmap = MEM_callocN(sizeof(unsigned int)*maxcol, "targa cmap"); for (count = 0 ; count < maxcol ; count ++) { switch (tga.mapbits >> 3) { case 4: cp[0] = mem[3]; cp[1] = mem[0]; cp[2] = mem[1]; cp[3] = mem[2]; mem += 4; break; case 3: cp[1] = mem[0]; cp[2] = mem[1]; cp[3] = mem[2]; mem += 3; break; case 2: cp[1] = mem[1]; cp[0] = mem[0]; mem += 2; break; case 1: col = *mem++; break; } cmap[count] = col; } size = 0; for (col = maxcol - 1; col > 0; col >>= 1) size++; ibuf->depth = size; if (tga.mapbits != 32) { /* set alpha bits */ cmap[0] &= BIG_LONG(0x00ffffffl); } } if (flags & IB_test) return (ibuf); if (tga.imgtyp != 1 && tga.imgtyp != 9) { /* happens sometimes (beuh) */ if(cmap) { MEM_freeN(cmap); cmap= NULL; } } switch(tga.imgtyp){ case 1: case 2: case 3: if (tga.pixsize <= 8) ldtarga(ibuf,mem,mem_size,0); else if (tga.pixsize <= 16) ldtarga(ibuf,mem,mem_size,1); else if (tga.pixsize <= 24) ldtarga(ibuf,mem,mem_size,2); else if (tga.pixsize <= 32) ldtarga(ibuf,mem,mem_size,3); break; case 9: case 10: case 11: if (tga.pixsize <= 8) decodetarga(ibuf,mem,mem_size,0); else if (tga.pixsize <= 16) decodetarga(ibuf,mem,mem_size,1); else if (tga.pixsize <= 24) decodetarga(ibuf,mem,mem_size,2); else if (tga.pixsize <= 32) decodetarga(ibuf,mem,mem_size,3); break; } if(cmap) { /* apply color map */ rect = ibuf->rect; for(size = ibuf->x * ibuf->y; size>0; --size, ++rect) { col = *rect; if (col >= 0 && col < maxcol) *rect = cmap[col]; } MEM_freeN(cmap); } if (tga.pixsize == 16) { rect = ibuf->rect; for (size = ibuf->x * ibuf->y; size > 0; --size, ++rect){ col = *rect; cp = (uchar*)rect; mem = (uchar*)&col; cp[3] = ((mem[1] << 1) & 0xf8); cp[2] = ((mem[0] & 0xe0) >> 2) + ((mem[1] & 0x03) << 6); cp[1] = ((mem[0] << 3) & 0xf8); cp[1] += cp[1] >> 5; cp[2] += cp[2] >> 5; cp[3] += cp[3] >> 5; cp[0] = 0xff; } ibuf->depth = 24; } if (tga.imgtyp == 3 || tga.imgtyp == 11){ uchar *crect; unsigned int *lrect, col; crect = (uchar *) ibuf->rect; lrect = (unsigned int *) ibuf->rect; for (size = ibuf->x * ibuf->y; size > 0; size --){ col = *lrect++; crect[0] = 255; crect[1] = crect[2] = crect[3] = col; crect += 4; } } if (tga.imgdes & 0x20) IMB_flipy(ibuf); if (ibuf && ibuf->rect) IMB_convert_rgba_to_abgr(ibuf); return(ibuf); }