This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/imbuf/intern/targa.c

643 lines
13 KiB
C
Raw Normal View History

2002-10-12 11:37:38 +00:00
/**
*
* ***** BEGIN GPL/BL DUAL 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. The Blender
* Foundation also sells licenses for use in proprietary software under
* the Blender License. See http://www.blender.org/BL/ for information
* about this.
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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/BL DUAL LICENSE BLOCK *****
* $Id$
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
2002-10-12 11:37:38 +00:00
#ifdef WIN32
#include "BLI_winstuff.h"
#include <io.h>
#endif
#include "BLI_blenlib.h"
#include "imbuf.h"
#include "imbuf_patch.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_allocimbuf.h"
#include "IMB_cmap.h"
#include "IMB_targa.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;
/* volgorde = 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]){ /* drie dezelfde? */
bytes --; /* bytes goed zetten */
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){ /* zoek naar eerste afwijkende byte */
if (--bytes == 0) break; /* of einde regel */
}
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 == 0) return (0);
if (ibuf->rect == 0) 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);
}
short imb_savetarga(struct ImBuf * ibuf, int file, int flags)
{
char buf[20];
FILE *fildes;
int i;
short ok = 0;
2002-10-12 11:37:38 +00:00
if (ibuf == 0) return (0);
if (ibuf->rect == 0) return (0);
memset(buf,0,sizeof(buf));
/* buf[0] = 0; lengte string */
buf[16] = (ibuf->depth + 0x7 ) & ~0x7;
if (ibuf->cmap) {
buf[1] = 1;
buf[2] = 9;
buf[3] = ibuf->mincol & 0xff;
buf[4] = ibuf->mincol >> 8;
buf[5] = ibuf->maxcol & 0xff;
buf[6] = ibuf->maxcol >> 8;
buf[7] = 24;
if ((flags & IB_ttob) == 0) {
IMB_flipy(ibuf);
buf[17] = 0x20;
}
} else if (ibuf->depth > 8 ){
buf[2] = 10;
} else{
buf[2] = 11;
}
if (ibuf->ftype == RAWTGA) buf[2] &= ~8;
buf[8] = ibuf->xorig & 0xff;
buf[9] = ibuf->xorig >> 8;
buf[10] = ibuf->yorig & 0xff;
buf[11] = ibuf->yorig >> 8;
buf[12] = ibuf->x & 0xff;
buf[13] = ibuf->x >> 8;
buf[14] = ibuf->y & 0xff;
buf[15] = ibuf->y >> 8;
if (flags & IB_ttob) buf[17] ^= 0x20;
/* Don't forget to indicate that your 32 bit
* targa uses 8 bits for the alpha channel! */
if (ibuf->depth==32) {
buf[17] |= 0x08;
}
2002-10-12 11:37:38 +00:00
if (write(file, buf, 18) != 18) return (0);
if (ibuf->cmap){
for (i = 0 ; i<ibuf->maxcol ; i++){
if (write(file,((uchar *)(ibuf->cmap + i)) + 1,3) != 3) return (0);
}
}
fildes = fdopen(file,"ab");
if (ibuf->cmap && (flags & IB_cmap) == 0) IMB_converttocmap(ibuf);
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 >= 4096) return(0);
if (tga->ysize <= 0 || tga->ysize >= 4096) return(0);
if (tga->pixsize > 32) return(0);
if (tga->pixsize == 0) return(0);
return(1);
}
int imb_is_a_targa(void *buf) {
TARGA tga;
return checktarga(&tga, buf);
}
static void decodetarga(struct ImBuf *ibuf, unsigned char *mem, int psize)
/* struct ImBuf *ibuf; */
/* uchar *mem; */
/* int psize; */
{
int count, col, size;
unsigned int *rect;
uchar * cp = (uchar *) &col;
if (ibuf == 0) return;
if (ibuf->rect == 0) return;
size = ibuf->x * ibuf->y;
rect = ibuf->rect;
/* alpha zetten */
cp[0] = 0xff;
cp[1] = cp[2] = 0;
while(size > 0){
count = *mem++;
if (count >= 128) {
/*if (count == 128) printf("TARGA: 128 in file !\n");*/
count -= 127;
if (psize & 2){
if (psize & 1){
/* volgorde = 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){
col = (mem[0] << 8) + 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){
/* volgorde = 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){
col = (mem[0] << 8) + mem[1];
mem += 2;
} else{
col = *mem++;
}
}
*rect++ = col;
count --;
}
}
}
}
if (size) printf("decodetarga: count would overwrite %d pixels\n", -size);
}
static void ldtarga(struct ImBuf * ibuf,unsigned char * mem, int psize)
{
int col,size;
unsigned int *rect;
uchar * cp = (uchar *) &col;
if (ibuf == 0) return;
if (ibuf->rect == 0) return;
size = ibuf->x * ibuf->y;
rect = ibuf->rect;
/* alpha zetten */
cp[0] = 0xff;
cp[1] = cp[2] = 0;
while(size > 0){
if (psize & 2){
if (psize & 1){
/* volgorde = 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{
/* zet alpha bij 24 bits kleuren */
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){
col = (mem[1] << 8) + mem[0];
mem += 2;
} else{
col = *mem++;
}
}
*rect++ = col;
size--;
}
}
struct ImBuf *imb_loadtarga(unsigned char *mem, int flags)
{
TARGA tga;
struct ImBuf * ibuf;
int col, count, size;
unsigned int * rect;
uchar * cp = (uchar *) &col;
if (checktarga(&tga,mem) == 0) return(0);
if (flags & IB_test) ibuf = IMB_allocImBuf(tga.xsize,tga.ysize,tga.pixsize,0,0);
else ibuf = IMB_allocImBuf(tga.xsize,tga.ysize,(tga.pixsize + 0x7) & ~0x7,1,0);
if (ibuf == 0) return(0);
ibuf->ftype = TGA;
ibuf->xorig = tga.xorig;
ibuf->yorig = tga.yorig;
mem = mem + 18 + tga.numid;
cp[0] = 0xff;
cp[1] = cp[2] = 0;
if (tga.mapsize){
ibuf->mincol = tga.maporig;
ibuf->maxcol = tga.mapsize;
imb_addcmapImBuf(ibuf);
ibuf->cbits = 8;
for (count = 0 ; count < ibuf->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:
col = (mem[1] << 8) + mem[0];
mem += 2;
break;
case 1:
col = *mem++;
break;
}
ibuf->cmap[count] = col;
}
size = 0;
for (col = ibuf->maxcol - 1; col > 0; col >>= 1) size++;
ibuf->depth = size;
if (tga.mapbits != 32) { /* alpha bits zetten */
ibuf->cmap[0] &= BIG_LONG(0x00ffffff);
}
}
if (flags & IB_test) return (ibuf);
if (tga.imgtyp != 1 && tga.imgtyp != 9) IMB_freecmapImBuf(ibuf); /* kan soms gebeuren (beuh) */
switch(tga.imgtyp){
case 1:
case 2:
case 3:
if (tga.pixsize <= 8) ldtarga(ibuf,mem,0);
else if (tga.pixsize <= 16) ldtarga(ibuf,mem,1);
else if (tga.pixsize <= 24) ldtarga(ibuf,mem,2);
else if (tga.pixsize <= 32) ldtarga(ibuf,mem,3);
break;
case 9:
case 10:
case 11:
if (tga.pixsize <= 8) decodetarga(ibuf,mem,0);
else if (tga.pixsize <= 16) decodetarga(ibuf,mem,1);
else if (tga.pixsize <= 24) decodetarga(ibuf,mem,2);
else if (tga.pixsize <= 32) decodetarga(ibuf,mem,3);
break;
}
if (ibuf->cmap){
if ((flags & IB_cmap) == 0) IMB_applycmap(ibuf);
}
if (tga.pixsize == 16 && ibuf->cmap == 0){
rect = ibuf->rect;
for (size = ibuf->x * ibuf->y; size > 0; size --){
col = *rect;
col = ((col & 0x1f) << 19) + ((col & 0x3e0) << 6) + ((col & 0x7c00) >> 7) ;
col += (col & 0xe0e0e0) >> 5;
*rect++ = col + 0xff000000;
}
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 (flags & IB_ttob) tga.imgdes ^= 0x20;
if (tga.imgdes & 0x20) IMB_flipy(ibuf);
if (ibuf) {
if (ibuf->rect && (flags & IB_cmap)==0)
IMB_convert_rgba_to_abgr((ibuf->x+ibuf->skipx)*ibuf->y, ibuf->rect);
}
return(ibuf);
}