This source file includes following definitions.
- save
- load
- formats
- tgaflip
#include "loader_common.h"
#include <sys/stat.h>
#include <sys/mman.h>
#include "colormod.h"
#include "blend.h"
static void tgaflip(DATA32 * in, int w, int h);
#define TGA_TYPE_MAPPED 1
#define TGA_TYPE_COLOR 2
#define TGA_TYPE_GRAY 3
#define TGA_TYPE_MAPPED_RLE 9
#define TGA_TYPE_COLOR_RLE 10
#define TGA_TYPE_GRAY_RLE 11
#define TGA_DESC_ABITS 0x0f
#define TGA_DESC_HORIZONTAL 0x10
#define TGA_DESC_VERTICAL 0x20
#define TGA_SIGNATURE "TRUEVISION-XFILE"
typedef struct {
unsigned char idLength;
unsigned char colorMapType;
unsigned char imageType;
unsigned char colorMapIndexLo, colorMapIndexHi;
unsigned char colorMapLengthLo, colorMapLengthHi;
unsigned char colorMapSize;
unsigned char xOriginLo, xOriginHi;
unsigned char yOriginLo, yOriginHi;
unsigned char widthLo, widthHi;
unsigned char heightLo, heightHi;
unsigned char bpp;
unsigned char descriptor;
} tga_header;
typedef struct {
unsigned int extensionAreaOffset;
unsigned int developerDirectoryOffset;
char signature[16];
char dot;
char null;
} tga_footer;
char
save(ImlibImage * im, ImlibProgressFunction progress, char progress_granularity)
{
FILE *f;
DATA32 *dataptr;
unsigned char *buf, *bufptr;
int y, pl = 0;
char pper = 0;
tga_header header;
if (!im->data)
return 0;
f = fopen(im->real_file, "wb");
if (!f)
return 0;
memset(&header, 0x0, sizeof(header));
header.imageType = TGA_TYPE_COLOR;
header.widthLo = im->w & 0xFF;
header.widthHi = im->w >> 8;
header.heightLo = im->h & 0xFF;
header.heightHi = im->h >> 8;
header.bpp = (im->flags & F_HAS_ALPHA) ? 32 : 24;
header.descriptor = (im->flags & F_HAS_ALPHA) ? 8 : 0;
header.descriptor |= TGA_DESC_VERTICAL;
buf = malloc(im->w * im->h * ((im->flags & F_HAS_ALPHA) ? 4 : 3));
if (!buf)
{
fclose(f);
return 0;
}
dataptr = im->data;
bufptr = buf;
for (y = 0; y < im->h; y++)
{
int x;
unsigned char r, g, b, a;
for (x = 0; x < im->w; x++)
{
if (im->flags & F_HAS_ALPHA)
{
READ_RGBA(dataptr, r, g, b, a);
*bufptr++ = b;
*bufptr++ = g;
*bufptr++ = r;
*bufptr++ = a;
}
else
{
READ_RGB(dataptr, r, g, b);
*bufptr++ = b;
*bufptr++ = g;
*bufptr++ = r;
}
dataptr++;
}
if (progress)
{
char per;
int l;
per = (char)((100 * y) / im->h);
if (((per - pper) >= progress_granularity) || (y == (im->h - 1)))
{
l = y - pl;
if (!progress(im, per, 0, (y - l), im->w, l))
{
free(buf);
fclose(f);
return 2;
}
pper = per;
pl = y;
}
}
}
fwrite(&header, sizeof(header), 1, f);
fwrite(buf, 1, im->w * im->h * ((im->flags & F_HAS_ALPHA) ? 4 : 3), f);
free(buf);
fclose(f);
return 1;
}
char
load(ImlibImage * im, ImlibProgressFunction progress,
char progress_granularity, char immediate_load)
{
int fd;
void *seg, *filedata;
struct stat ss;
int bpp, vinverted = 0;
int rle = 0, footer_present = 0;
tga_header *header;
tga_footer *footer;
if (im->data)
return 0;
fd = open(im->real_file, O_RDONLY);
if (fd < 0)
return 0;
if (fstat(fd, &ss) < 0)
{
close(fd);
return 0;
}
if (ss.st_size < sizeof(tga_header) + sizeof(tga_footer))
{
close(fd);
return 0;
}
seg = mmap(0, ss.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (seg == MAP_FAILED)
{
close(fd);
return 0;
}
filedata = seg;
header = (tga_header *) filedata;
footer = (tga_footer *) ((char *)filedata + ss.st_size - sizeof(tga_footer));
if (memcmp(footer->signature, TGA_SIGNATURE, sizeof(footer->signature)) == 0)
footer_present = 1;
if (!footer_present)
{
}
filedata = (char *)filedata + sizeof(tga_header);
if (header->idLength)
filedata = (char *)filedata + header->idLength;
vinverted = !(header->descriptor & TGA_DESC_VERTICAL);
switch (header->imageType)
{
case TGA_TYPE_COLOR_RLE:
case TGA_TYPE_GRAY_RLE:
rle = 1;
break;
case TGA_TYPE_COLOR:
case TGA_TYPE_GRAY:
rle = 0;
break;
default:
munmap(seg, ss.st_size);
close(fd);
return 0;
}
bpp = header->bpp;
if (!((bpp == 32) || (bpp == 24) || (bpp == 8)))
{
munmap(seg, ss.st_size);
close(fd);
return 0;
}
im->w = (header->widthHi << 8) | header->widthLo;
im->h = (header->heightHi << 8) | header->heightLo;
if (!IMAGE_DIMENSIONS_OK(im->w, im->h))
{
munmap(seg, ss.st_size);
close(fd);
return 0;
}
if (!im->format)
{
if (bpp == 32)
SET_FLAG(im->flags, F_HAS_ALPHA);
else
UNSET_FLAG(im->flags, F_HAS_ALPHA);
im->format = strdup("tga");
}
if (((!im->data) && (im->loader)) || (immediate_load) || (progress))
{
unsigned long datasize;
unsigned char *bufptr, *bufend;
DATA32 *dataptr;
int y;
im->data = malloc(im->w * im->h * sizeof(DATA32));
if (!im->data)
{
im->w = 0;
munmap(seg, ss.st_size);
close(fd);
return 0;
}
datasize = ss.st_size - sizeof(tga_header) - header->idLength -
(footer_present ? sizeof(tga_footer) : 0);
bufptr = filedata;
bufend = filedata + datasize;
dataptr = im->data;
if (!rle)
{
for (y = 0; y < im->h; y++)
{
int x;
if (vinverted)
dataptr = im->data + ((im->h - y - 1) * im->w);
else
dataptr = im->data + (y * im->w);
for (x = 0; (x < im->w) && (bufptr + bpp / 8 <= bufend); x++)
{
switch (bpp)
{
case 32:
WRITE_RGBA(dataptr, *(bufptr + 2),
*(bufptr + 1),
*(bufptr + 0),
*(bufptr + 3)
);
dataptr++;
bufptr += 4;
break;
case 24:
WRITE_RGBA(dataptr, *(bufptr + 2),
*(bufptr + 1),
*(bufptr + 0),
(char)0xff
);
dataptr++;
bufptr += 3;
break;
case 8:
WRITE_RGBA(dataptr,
*bufptr, *bufptr, *bufptr, (char)0xff);
dataptr++;
bufptr += 1;
break;
}
}
}
if (progress)
{
progress(im, 100, 0, 0, im->w, im->h);
}
}
else
{
unsigned char curbyte, red, green, blue, alpha;
DATA32 *final_pixel = dataptr + im->w * im->h;
while ((dataptr < final_pixel) &&
((bufptr + 1 + (bpp / 8)) <= bufend))
{
int count;
curbyte = *bufptr++;
count = (curbyte & 0x7F) + 1;
if (curbyte & 0x80)
{
int i;
switch (bpp)
{
case 32:
blue = *bufptr++;
green = *bufptr++;
red = *bufptr++;
alpha = *bufptr++;
for (i = 0; (i < count) && (dataptr < final_pixel);
i++)
{
WRITE_RGBA(dataptr, red, green, blue, alpha);
dataptr++;
}
break;
case 24:
blue = *bufptr++;
green = *bufptr++;
red = *bufptr++;
for (i = 0; (i < count) && (dataptr < final_pixel);
i++)
{
WRITE_RGBA(dataptr, red, green, blue,
(char)0xff);
dataptr++;
}
break;
case 8:
alpha = *bufptr++;
for (i = 0; (i < count) && (dataptr < final_pixel);
i++)
{
WRITE_RGBA(dataptr, alpha, alpha, alpha,
(char)0xff);
dataptr++;
}
break;
}
}
else
{
int i;
for (i = 0; (i < count) && (dataptr < final_pixel); i++)
{
switch (bpp)
{
case 32:
WRITE_RGBA(dataptr, *(bufptr + 2),
*(bufptr + 1),
*(bufptr + 0),
*(bufptr + 3)
);
dataptr++;
bufptr += 4;
break;
case 24:
WRITE_RGBA(dataptr, *(bufptr + 2),
*(bufptr + 1),
*(bufptr + 0),
(char)0xff
);
dataptr++;
bufptr += 3;
break;
case 8:
WRITE_RGBA(dataptr, *bufptr,
*bufptr, *bufptr, (char)0xff);
dataptr++;
bufptr += 1;
break;
}
}
}
}
if (vinverted)
tgaflip(im->data, im->w, im->h);
if (progress)
{
progress(im, 100, 0, 0, im->w, im->h);
}
}
}
munmap(seg, ss.st_size);
close(fd);
return 1;
}
void
formats(ImlibLoader * l)
{
char *list_formats[] = { "tga" };
{
int i;
l->num_formats = (sizeof(list_formats) / sizeof(char *));
l->formats = malloc(sizeof(char *) * l->num_formats);
for (i = 0; i < l->num_formats; i++)
l->formats[i] = strdup(list_formats[i]);
}
}
static void
tgaflip(DATA32 * in, int w, int h)
{
DATA32 *adv, *adv2;
int x, y;
adv = in;
adv2 = in + (w * (h - 1));
for (y = 0; y < (h / 2); y++)
{
DATA32 tmp;
for (x = 0; x < w; x++)
{
tmp = adv[x];
adv[x] = adv2[x];
adv2[x] = tmp;
}
adv2 -= w;
adv += w;
}
}