trga loader - snarfed 80% from imlib2. missing paletted mode (just

like the imlib2 one) but.. handles alpha correctly- unlike imlib2 and
manyother loaders.



SVN revision: 49330
This commit is contained in:
Carsten Haitzler 2010-05-30 17:48:19 +00:00
parent 2cf09cdc4a
commit 9621532945
6 changed files with 611 additions and 2 deletions

View File

@ -118,6 +118,7 @@ want_evas_image_loader_svg="yes"
want_evas_image_loader_tiff="yes"
want_evas_image_loader_xpm="yes"
want_evas_image_loader_bmp="yes"
want_evas_image_loader_tga="yes"
want_evas_font_loader_eet="yes"
@ -695,6 +696,8 @@ EVAS_CHECK_IMAGE_LOADER([XPM], [${want_evas_image_loader_xpm}])
EVAS_CHECK_IMAGE_LOADER([BMP], [${want_evas_image_loader_bmp}])
EVAS_CHECK_IMAGE_LOADER([TGA], [${want_evas_image_loader_tga}])
#####################################################################
## Cpu based optimizations
@ -1410,6 +1413,7 @@ src/modules/loaders/png/Makefile
src/modules/loaders/tiff/Makefile
src/modules/loaders/xpm/Makefile
src/modules/loaders/bmp/Makefile
src/modules/loaders/tga/Makefile
src/modules/loaders/svg/Makefile
src/modules/loaders/pmaps/Makefile
src/modules/savers/Makefile

View File

@ -327,6 +327,26 @@ fi
])
dnl use: EVAS_CHECK_LOADER_DEP_TGA(loader, want_static[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
AC_DEFUN([EVAS_CHECK_LOADER_DEP_TGA],
[
have_dep="yes"
evas_image_loader_[]$1[]_cflags=""
evas_image_loader_[]$1[]_libs=""
AC_SUBST([evas_image_loader_$1_cflags])
AC_SUBST([evas_image_loader_$1_libs])
if test "x${have_dep}" = "xyes" ; then
m4_default([$3], [:])
else
m4_default([$4], [:])
fi
])
dnl use: EVAS_CHECK_IMAGE_LOADER(loader, want_loader, macro)

View File

@ -32,12 +32,13 @@ static const struct ext_loader_s loaders[] =
{ "pgm", "pmaps" },
{ "ppm", "pmaps" },
{ "pnm", "pmaps" },
{ "bmp", "bmp" }
{ "bmp", "bmp" },
{ "tga", "tga" }
};
static const char *loaders_name[] =
{
"png", "jpeg", "eet", "xpm", "tiff", "gif", "svg", "pmaps", "edb", "bmp"
"png", "jpeg", "eet", "xpm", "tiff", "gif", "svg", "pmaps", "edb", "bmp", "tga"
};
struct evas_image_foreach_loader_data

View File

@ -62,3 +62,9 @@ SUBDIRS += bmp
endif
endif
if BUILD_LOADER_TGA
if !EVAS_STATIC_BUILD_TGA
SUBDIRS += tga
endif
endif

View File

@ -0,0 +1,32 @@
MAINTAINERCLEANFILES = Makefile.in
AM_CPPFLAGS = \
-I. \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib/include \
@FREETYPE_CFLAGS@ \
@EINA_CFLAGS@ \
@EVIL_CFLAGS@ \
@WIN32_CPPFLAGS@
if BUILD_LOADER_TGA
if !EVAS_STATIC_BUILD_TGA
pkgdir = $(libdir)/evas/modules/loaders/tga/$(MODULE_ARCH)
pkg_LTLIBRARIES = module.la
module_la_SOURCES = evas_image_load_tga.c
module_la_LIBADD = @EINA_LIBS@ @EVIL_LIBS@ $(top_builddir)/src/lib/libevas.la
module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version
module_la_LIBTOOLFLAGS = --tag=disable-static
else
noinst_LTLIBRARIES = libevas_loader_tga.la
libevas_loader_png_la_SOURCES = evas_image_load_tga.c
libevas_loader_png_la_LIBADD =
endif
endif

View File

@ -0,0 +1,546 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include "evas_common.h"
#include "evas_private.h"
/* TGA pixel formats */
#define TGA_TYPE_MAPPED 1 // handle
#define TGA_TYPE_COLOR 2
#define TGA_TYPE_GRAY 3
#define TGA_TYPE_MAPPED_RLE 9 // handle
#define TGA_TYPE_COLOR_RLE 10
#define TGA_TYPE_GRAY_RLE 11
/* TGA header flags */
#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;
static Eina_Bool evas_image_load_file_head_tga(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4);
static Eina_Bool evas_image_load_file_data_tga(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4);
static Evas_Image_Load_Func evas_image_load_tga_func =
{
EINA_TRUE,
evas_image_load_file_head_tga,
evas_image_load_file_data_tga
};
static int
read_short(FILE *file, short *ret)
{
unsigned char b[2];
if (E_FREAD(b, sizeof(unsigned char), 2, file) != 2) return 0;
*ret = (b[1] << 8) | b[0];
return 1;
}
static int
read_int(FILE *file, int *ret)
{
unsigned char b[4];
if (E_FREAD(b, sizeof(unsigned char), 4, file) != 4) return 0;
*ret = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
return 1;
}
static Eina_Bool
evas_image_load_file_head_tga(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
{
int fd;
unsigned char *seg = MAP_FAILED, *filedata;
struct stat ss;
tga_header *header;
tga_footer *footer;
char hasa = 0, footer_present = 0, vinverted = 0, rle = 0;
int w = 0, h = 0, bpp;
fd = open(file, O_RDONLY);
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
if (fd < 0) return EINA_FALSE;
if (fstat(fd, &ss) < 0) goto close_file;
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
if (ss.st_size < (sizeof(tga_header) + sizeof(tga_footer))) goto close_file;
seg = mmap(0, ss.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (seg == MAP_FAILED) goto close_file;
filedata = seg;
header = (tga_header *)filedata;
// no unaligned data accessed, so ok
footer = (tga_footer *)(filedata + (ss.st_size - sizeof(tga_footer)));
if (!memcmp(footer->signature, TGA_SIGNATURE, sizeof(footer->signature)))
{
// footer is ther and matches. this is a tga file - any problems now
// are a corrupt file
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
footer_present = 1;
}
filedata = (char *)filedata + sizeof(tga_header);
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:
goto close_file;
}
bpp = header->bpp;
if (!((bpp == 32) || (bpp == 24) || (bpp == 16) || (bpp == 8)))
goto close_file;
if ((bpp == 32) && (header->descriptor & TGA_DESC_ABITS)) hasa = 1;
w = (header->widthHi << 8) | header->widthLo;
h = (header->heightHi << 8) | header->heightLo;
if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
IMG_TOO_BIG(w, h))
goto close_file;
ie->w = w;
ie->h = h;
if (hasa) ie->flags.alpha = 1;
if (seg != MAP_FAILED) munmap(seg, ss.st_size);
close(fd);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
close_file:
if (seg != MAP_FAILED) munmap(seg, ss.st_size);
close(fd);
return EINA_FALSE;
}
static Eina_Bool
evas_image_load_file_data_tga(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
{
int fd;
unsigned char *seg = MAP_FAILED, *filedata;
struct stat ss;
tga_header *header;
tga_footer *footer;
char hasa = 0, footer_present = 0, vinverted = 0, rle = 0;
int w = 0, h = 0, x, y, bpp;
unsigned int *surface, *dataptr;
unsigned int datasize;
unsigned char *bufptr, *bufend;
fd = open(file, O_RDONLY);
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
if (fd < 0) return EINA_FALSE;
if (fstat(fd, &ss) < 0) goto close_file;
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
if (ss.st_size < (sizeof(tga_header) + sizeof(tga_footer))) goto close_file;
seg = mmap(0, ss.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (seg == MAP_FAILED) goto close_file;
filedata = seg;
header = (tga_header *)filedata;
// no unaligned data accessed, so ok
footer = (tga_footer *)(filedata + (ss.st_size - sizeof(tga_footer)));
if (!memcmp(footer->signature, TGA_SIGNATURE, sizeof(footer->signature)))
{
// footer is ther and matches. this is a tga file - any problems now
// are a corrupt file
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
footer_present = 1;
}
filedata = (char *)filedata + sizeof(tga_header);
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:
goto close_file;
}
bpp = header->bpp;
if (!((bpp == 32) || (bpp == 24) || (bpp == 16) || (bpp == 8)))
goto close_file;
if ((bpp == 32) && (header->descriptor & TGA_DESC_ABITS)) hasa = 1;
w = (header->widthHi << 8) | header->widthLo;
h = (header->heightHi << 8) | header->heightLo;
if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
IMG_TOO_BIG(w, h))
goto close_file;
if ((w != ie->w) || (h != ie->h))
{
*error = EVAS_LOAD_ERROR_GENERIC;
goto close_file;
}
evas_cache_image_surface_alloc(ie, w, h);
surface = evas_cache_image_pixels(ie);
if (!surface)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
datasize = ss.st_size - sizeof(tga_header) - header->idLength;
if (footer_present)
datasize = ss.st_size - sizeof(tga_header) - header->idLength -
sizeof(tga_footer);
bufptr = filedata + header->idLength;
bufend = filedata + datasize;
dataptr = surface;
if (!rle)
{
for (y = 0; y < h; y++)
{
if (vinverted)
/* some TGA's are stored upside-down! */
dataptr = surface + ((h - y - 1) * w);
else
dataptr = surface + (y * w);
switch (bpp)
{
case 32:
for (x = 0; (x < w) && ((bufptr + 4) <= bufend); x++)
{
if (hasa)
*dataptr =
((255 - bufptr[3]) << 24) | (bufptr[2] << 16) |
(bufptr[1] << 8) | (bufptr[0] );
else
*dataptr =
(0xff << 24) | (bufptr[2] << 16) |
(bufptr[1] << 8) | (bufptr[0] );
dataptr++;
bufptr += 4;
}
break;
case 24:
for (x = 0; (x < w) && ((bufptr + 3) <= bufend); x++)
{
*dataptr =
(0xff << 24) | (bufptr[2] << 16) |
(bufptr[1] << 8) | (bufptr[0] );
dataptr++;
bufptr += 3;
}
break;
case 16:
for (x = 0; (x < w) && ((bufptr + 3) <= bufend); x++)
{
unsigned char r, g, b, a;
unsigned short tmp;
tmp =
(((unsigned short)bufptr[1]) << 8) |
(((unsigned short)bufptr[0]));
r = (tmp >> 7) & 0xf8; r |= r >> 5;
g = (tmp >> 2) & 0xf8; g |= g >> 5;
b = (tmp << 3) & 0xf8; b |= b >> 5;
a = 0xff;
if ((hasa) && (tmp & 0x8000)) a = 0;
*dataptr =
(a << 24) | (r << 16) |
(g << 8) | (b );
dataptr++;
bufptr += 2;
}
break;
case 8:
for (x = 0; (x < w) && ((bufptr + 1) <= bufend); x++)
{
*dataptr =
(0xff << 24) | (bufptr[0] << 16) |
(bufptr[0] << 8) | (bufptr[0] );
dataptr++;
bufptr += 1;
}
break;
default:
break;
}
}
}
else
{
int count, i;
unsigned char val;
unsigned int *dataend;
dataptr = surface;
dataend = dataptr + (w * h);
while ((bufptr < bufend) && (dataptr < dataend))
{
val = *bufptr;
bufptr++;
count = (val & 0x7f) + 1;
if (val & 0x80) // rel packet
{
switch (bpp)
{
case 32:
if (bufptr < (bufend - 4))
{
unsigned char r, g, b, a;
a = 255 - bufptr[3];
r = bufptr[2];
g = bufptr[1];
b = bufptr[0];
if (!hasa) a = 0xff;
bufptr += 4;
for (i = 0; (i < count) && (dataptr < dataend); i++)
{
*dataptr =
(a << 24) | (r << 16) | (g << 8) | (b);
dataptr++;
}
}
break;
case 24:
if (bufptr < (bufend - 3))
{
unsigned char r, g, b;
r = bufptr[2];
g = bufptr[1];
b = bufptr[0];
bufptr += 3;
for (i = 0; (i < count) && (dataptr < dataend); i++)
{
*dataptr =
(0xff << 24) | (r << 16) | (g << 8) | (b);
dataptr++;
}
}
break;
case 16:
if (bufptr < (bufend - 2))
{
unsigned char r, g, b, a;
unsigned short tmp;
tmp =
(((unsigned short)bufptr[1]) << 8) |
(((unsigned short)bufptr[0]));
r = (tmp >> 7) & 0xf8; r |= r >> 5;
g = (tmp >> 2) & 0xf8; g |= g >> 5;
b = (tmp << 3) & 0xf8; b |= b >> 5;
a = 0xff;
if ((hasa) && (tmp & 0x8000)) a = 0;
bufptr += 2;
for (i = 0; (i < count) && (dataptr < dataend); i++)
{
*dataptr =
*dataptr =
(a << 24) | (r << 16) |
(g << 8) | (b );
dataptr++;
}
}
break;
case 8:
if (bufptr < (bufend - 1))
{
unsigned char g;
g = bufptr[0];
bufptr += 1;
for (i = 0; (i < count) && (dataptr < dataend); i++)
{
*dataptr =
(0xff << 24) | (g << 16) | (g << 8) | (g);
dataptr++;
}
}
break;
default:
break;
}
}
else // raw
{
switch (bpp)
{
case 32:
for (i = 0; (i < count) && (bufptr < (bufend - 4)) && (dataptr < dataend); i++)
{
if (hasa)
*dataptr =
((255 - bufptr[3]) << 24) | (bufptr[2] << 16) |
(bufptr[1] << 8) | (bufptr[0] );
else
*dataptr =
(0xff << 24) | (bufptr[2] << 16) |
(bufptr[1] << 8) | (bufptr[0] );
dataptr++;
bufptr += 4;
}
break;
case 24:
for (i = 0; (i < count) && (bufptr < (bufend - 3)) && (dataptr < dataend); i++)
{
*dataptr =
(0xff << 24) | (bufptr[2] << 16) |
(bufptr[1] << 8) | (bufptr[0] );
dataptr++;
bufptr += 3;
}
break;
case 16:
for (i = 0; (i < count) && (bufptr < (bufend - 2)) && (dataptr < dataend); i++)
{
unsigned char r, g, b, a;
unsigned short tmp;
tmp =
(((unsigned short)bufptr[1]) << 8) |
(((unsigned short)bufptr[0]));
r = (tmp >> 7) & 0xf8; r |= r >> 5;
g = (tmp >> 2) & 0xf8; g |= g >> 5;
b = (tmp << 3) & 0xf8; b |= b >> 5;
a = 0xff;
if ((hasa) && (tmp & 0x8000)) a = 0;
*dataptr =
(a << 24) | (r << 16) |
(g << 8) | (b );
dataptr++;
bufptr += 2;
}
break;
case 8:
for (i = 0; (i < count) && (bufptr < (bufend - 1)) && (dataptr < dataend); i++)
{
*dataptr =
(0xff << 24) | (bufptr[0] << 16) |
(bufptr[0] << 8) | (bufptr[0] );
dataptr++;
bufptr += 1;
}
break;
default:
break;
}
}
}
if (vinverted)
{
unsigned int *adv, *adv2, tmp;
adv = surface;
adv2 = surface + (w * (h - 1));
for (y = 0; y < (h / 2); y++)
{
for (x = 0; x < w; x++)
{
tmp = adv[x];
adv[x] = adv2[x];
adv2[x] = tmp;
}
adv2 -= w;
adv += w;
}
}
}
evas_common_image_premul(ie);
if (seg != MAP_FAILED) munmap(seg, ss.st_size);
close(fd);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
close_file:
if (seg != MAP_FAILED) munmap(seg, ss.st_size);
close(fd);
return EINA_FALSE;
}
static int
module_open(Evas_Module *em)
{
if (!em) return 0;
em->functions = (void *)(&evas_image_load_tga_func);
return 1;
}
static void
module_close(Evas_Module *em)
{
}
static Evas_Module_Api evas_modapi =
{
EVAS_MODULE_API_VERSION,
"tga",
"none",
{
module_open,
module_close
}
};
EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, tga);
#ifndef EVAS_STATIC_BUILD_TGA
EVAS_EINA_MODULE_DEFINE(image_loader, tga);
#endif