From 9621532945665adff90b76623f09fb0e02ad565e Mon Sep 17 00:00:00 2001 From: Carsten Haitzler Date: Sun, 30 May 2010 17:48:19 +0000 Subject: [PATCH] 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 --- legacy/evas/configure.ac | 4 + legacy/evas/m4/evas_check_loader.m4 | 20 + .../src/lib/engines/common/evas_image_load.c | 5 +- legacy/evas/src/modules/loaders/Makefile.am | 6 + .../evas/src/modules/loaders/tga/Makefile.am | 32 + .../modules/loaders/tga/evas_image_load_tga.c | 546 ++++++++++++++++++ 6 files changed, 611 insertions(+), 2 deletions(-) create mode 100644 legacy/evas/src/modules/loaders/tga/Makefile.am create mode 100644 legacy/evas/src/modules/loaders/tga/evas_image_load_tga.c diff --git a/legacy/evas/configure.ac b/legacy/evas/configure.ac index 56973454a0..1877f0abbd 100644 --- a/legacy/evas/configure.ac +++ b/legacy/evas/configure.ac @@ -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 diff --git a/legacy/evas/m4/evas_check_loader.m4 b/legacy/evas/m4/evas_check_loader.m4 index 19a65a9850..cd64c9d76b 100644 --- a/legacy/evas/m4/evas_check_loader.m4 +++ b/legacy/evas/m4/evas_check_loader.m4 @@ -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) diff --git a/legacy/evas/src/lib/engines/common/evas_image_load.c b/legacy/evas/src/lib/engines/common/evas_image_load.c index 2d5850fc57..e776fcfe95 100644 --- a/legacy/evas/src/lib/engines/common/evas_image_load.c +++ b/legacy/evas/src/lib/engines/common/evas_image_load.c @@ -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 diff --git a/legacy/evas/src/modules/loaders/Makefile.am b/legacy/evas/src/modules/loaders/Makefile.am index 761ae2b6c9..7aa6cff46b 100644 --- a/legacy/evas/src/modules/loaders/Makefile.am +++ b/legacy/evas/src/modules/loaders/Makefile.am @@ -62,3 +62,9 @@ SUBDIRS += bmp endif endif +if BUILD_LOADER_TGA +if !EVAS_STATIC_BUILD_TGA +SUBDIRS += tga +endif +endif + diff --git a/legacy/evas/src/modules/loaders/tga/Makefile.am b/legacy/evas/src/modules/loaders/tga/Makefile.am new file mode 100644 index 0000000000..5d120db0aa --- /dev/null +++ b/legacy/evas/src/modules/loaders/tga/Makefile.am @@ -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 diff --git a/legacy/evas/src/modules/loaders/tga/evas_image_load_tga.c b/legacy/evas/src/modules/loaders/tga/evas_image_load_tga.c new file mode 100644 index 0000000000..a469ae2b47 --- /dev/null +++ b/legacy/evas/src/modules/loaders/tga/evas_image_load_tga.c @@ -0,0 +1,546 @@ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_EVIL +# include +#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