trga loader - snarfed 80% from imlib2. missing paletted mode (just
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 30 May 2010 17:48:19 +0000 (17:48 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 30 May 2010 17:48:19 +0000 (17:48 +0000)
like the imlib2 one) but.. handles alpha correctly- unlike imlib2 and
manyother loaders.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@49330 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

configure.ac
m4/evas_check_loader.m4
src/lib/engines/common/evas_image_load.c
src/modules/loaders/Makefile.am
src/modules/loaders/tga/Makefile.am [new file with mode: 0644]
src/modules/loaders/tga/evas_image_load_tga.c [new file with mode: 0644]

index 5697345..1877f0a 100644 (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
index 19a65a9..cd64c9d 100644 (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)
 
 
index 2d5850f..e776fcf 100644 (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
index 761ae2b..7aa6cff 100644 (file)
@@ -62,3 +62,9 @@ SUBDIRS += bmp
 endif
 endif
 
+if BUILD_LOADER_TGA
+if !EVAS_STATIC_BUILD_TGA
+SUBDIRS += tga
+endif
+endif
+
diff --git a/src/modules/loaders/tga/Makefile.am b/src/modules/loaders/tga/Makefile.am
new file mode 100644 (file)
index 0000000..5d120db
--- /dev/null
@@ -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/src/modules/loaders/tga/evas_image_load_tga.c b/src/modules/loaders/tga/evas_image_load_tga.c
new file mode 100644 (file)
index 0000000..a469ae2
--- /dev/null
@@ -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