add generic image loader. allows for GPL loaders, unstable loaders and
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 26 Apr 2011 01:03:06 +0000 (01:03 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 26 Apr 2011 01:03:06 +0000 (01:03 +0000)
more. making a loader is a matter of a binary of a specific name and
evas passes certain input on the cmd-line and your binary produces
output on stdout (and also optionally additionally in a shm or tmp
file).

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

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

index 8842747..7ed0336 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 
        * Add PSD file format support.
 
+2011-04-26  Carsten Haitzler (The Rasterman)
+
+       * Added "generic" image loader that can just execute some command
+        to load any given file format and read the RGBA data as stdout
+        from the command, or from an intermediate temporary file or
+        shared memory segment the executable loader provides. Evas
+        doesn't care about the loader beyond it providing output via
+        stdout to define image parameters (size, alpha channel and data
+        information), and evas will call a specific loader binary
+        based on extension name of srouce file. This allows for evas to
+        load image data from files where the loader may be prone to
+        instability, or require use of libraries that are GPL or
+        otherwise undesireable in terms of the result to applications
+        using evas. So basically, if you want a GPL loader or have a
+        very unstable one, write a loader binary and call it
+        evas_image_loader.extension e.g. evas_image_loader.pdf or
+        evas_image_loader.xcf or evas_image_loader.xcf.gz etc. etc.
+
index 2d22dc9..b6e87c0 100644 (file)
@@ -123,6 +123,7 @@ want_evas_image_loader_tga="yes"
 want_evas_image_loader_wbmp="yes"
 want_evas_image_loader_ico="yes"
 want_evas_image_loader_psd="yes"
+want_evas_image_loader_generic="yes"
 
 want_evas_font_loader_eet="yes"
 
@@ -476,6 +477,32 @@ case "$host_os" in
 esac
 AC_SUBST(dlopen_libs)
 
+SHM_OPEN_LINK=""
+AC_MSG_CHECKING([whether shm_open() is present])
+LIBS_save=${LIBS}
+LIBS="${LIBS} -lrt"
+AC_LINK_IFELSE(
+   [AC_LANG_PROGRAM(
+      [[
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+      ]],
+      [[
+int fd;
+fd = shm_open("/", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+shm_unlink("/");
+      ]])],
+   [
+    have_shm_open="yes"
+    AC_DEFINE(HAVE_SHM_OPEN, 1, [Have shm_open() call])
+    SHM_OPEN_LINK="-lrt"
+   ],
+   [have_shm_open="no"])
+LIBS=${LIBS_save}
+AC_MSG_RESULT([${have_shm_open}])
+AC_SUBST(SHM_OPEN_LINK)
+
 # (shm_open (for cache server)
 AC_ARG_ENABLE([evas-cserve],
    AC_HELP_STRING([--disable-evas-cserve],
@@ -838,6 +865,8 @@ EVAS_CHECK_IMAGE_LOADER([ICO], [${want_evas_image_loader_ico}])
 
 EVAS_CHECK_IMAGE_LOADER([PSD], [${want_evas_image_loader_psd}])
 
+EVAS_CHECK_IMAGE_LOADER([GENERIC], [${want_evas_image_loader_generic}])
+
 #####################################################################
 ## Cpu based optimizations
 
@@ -1611,6 +1640,7 @@ src/modules/loaders/svg/Makefile
 src/modules/loaders/pmaps/Makefile
 src/modules/loaders/wbmp/Makefile
 src/modules/loaders/psd/Makefile
+src/modules/loaders/generic/Makefile
 src/modules/savers/Makefile
 src/modules/savers/edb/Makefile
 src/modules/savers/eet/Makefile
@@ -1703,6 +1733,7 @@ echo "  TIFF....................: $have_evas_image_loader_tiff"
 echo "  WBMP....................: $have_evas_image_loader_wbmp"
 echo "  XPM.....................: $have_evas_image_loader_xpm"
 echo "  PSD.....................: $have_evas_image_loader_psd"
+echo "  GENERIC.................: $have_evas_image_loader_generic"
 echo
 echo "Font Sourcing Systems:"
 echo "  EET.....................: $have_evas_font_loader_eet"
index 2bff191..52f953f 100644 (file)
@@ -410,6 +410,26 @@ fi
 
 ])
 
+dnl use: EVAS_CHECK_LOADER_DEP_GENERIC(loader, want_static[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+
+AC_DEFUN([EVAS_CHECK_LOADER_DEP_GENERIC],
+[
+
+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 2ddbd1b..31b3d01 100644 (file)
@@ -9,36 +9,40 @@ struct ext_loader_s
 };
 
 static const struct ext_loader_s loaders[] =
-{
-   { "png", "png" },
-   { "jpg", "jpeg" },
-   { "jpeg", "jpeg" },
-   { "jfif", "jpeg" },
-   { "eet", "eet" },
-   { "edj", "eet" },
-   { "eap", "eet" },
-   { "edb", "edb" },
-   { "xpm", "xpm" },
-   { "tiff", "tiff" },
-   { "tif", "tiff" },
-   { "svg", "svg" },
-   { "svgz", "svg" },
-   { "gif", "gif" },
-   { "pbm", "pmaps" },
-   { "pgm", "pmaps" },
-   { "ppm", "pmaps" },
-   { "pnm", "pmaps" },
-   { "bmp", "bmp" },
-   { "tga", "tga" },
-   { "wbmp", "wbmp" },
-   { "ico", "ico" },
-   { "cur", "ico" },
-   { "psd", "psd" }
+{ /* map extensions to loaders to use for good first-guess tries */
+   { ".png", "png" },
+   { ".jpg", "jpeg" },
+   { ".jpeg", "jpeg" },
+   { ".jfif", "jpeg" },
+   { ".eet", "eet" },
+   { ".edj", "eet" },
+   { ".eap", "eet" },
+   { ".edb", "edb" },
+   { ".xpm", "xpm" },
+   { ".tiff", "tiff" },
+   { ".tif", "tiff" },
+   { ".svg", "svg" },
+   { ".svgz", "svg" },
+   { ".svg.gz", "svg" },
+   { ".gif", "gif" },
+   { ".pbm", "pmaps" },
+   { ".pgm", "pmaps" },
+   { ".ppm", "pmaps" },
+   { ".pnm", "pmaps" },
+   { ".bmp", "bmp" },
+   { ".tga", "tga" },
+   { ".wbmp", "wbmp" },
+   { ".ico", "ico" },
+   { ".cur", "ico" },
+   { ".psd", "psd" },
+   { ".pdf", "generic" },
+   { ".xcf", "generic" },
+   { ".xcf.gz", "generic" }
 };
 
 static const char *loaders_name[] =
-{
-  "png", "jpeg", "eet", "xpm", "tiff", "gif", "svg", "pmaps", "edb", "bmp", "tga", "wbmp", "ico", "psd"
+{ /* in order of most likely needed */
+  "png", "jpeg", "eet", "xpm", "tiff", "gif", "svg", "pmaps", "bmp", "tga", "wbmp", "ico", "psd", "edb", "generic"
 };
 
 struct evas_image_foreach_loader_data
@@ -76,11 +80,10 @@ EAPI int
 evas_common_load_rgba_image_module_from_file(Image_Entry *ie)
 {
    Evas_Image_Load_Func *evas_image_load_func = NULL;
-   const char           *loader = NULL;
+   const char           *loader = NULL, *end;
    Evas_Module          *em;
-   char                 *dot;
    unsigned int          i;
-   int                   ret = EVAS_LOAD_ERROR_NONE;
+   int                   len, ret = EVAS_LOAD_ERROR_NONE;
    struct evas_image_foreach_loader_data fdata;
 
 
@@ -96,20 +99,20 @@ evas_common_load_rgba_image_module_from_file(Image_Entry *ie)
              return EVAS_LOAD_ERROR_NONE;
           }
      }
-#endif   
-   dot = strrchr (ie->file, '.');
-   if (dot)
+#endif
+   len = strlen(ie->file);
+   end = ie->file + len;
+   for (i = 0; i < (sizeof (loaders) / sizeof(struct ext_loader_s)); i++)
      {
-       for (i = 0, ++dot; i < (sizeof (loaders) / sizeof (struct ext_loader_s)); ++i)
-         {
-            if (!strcasecmp(dot, loaders[i].extension))
-              {
-                 loader = loaders[i].loader;
-                 DBG("known loader '%s' handles extension '%s' of file '%s'",
-                     loader, dot, ie->file);
-                 break;
-              }
-         }
+        int len2 = strlen(loaders[i].extension);
+        if (len2 > len) continue;
+        if (!strcasecmp(end - len2, loaders[i].extension))
+          {
+             loader = loaders[i].loader;
+             DBG("known loader '%s' handles extension '%s' of file '%s'",
+                 loader, end - len2, ie->file);
+             break;
+          }
      }
 
    if (loader)
index f90cfd2..ddd51a5 100644 (file)
@@ -86,3 +86,9 @@ SUBDIRS += psd
 endif
 endif
 
+if BUILD_LOADER_GENERIC
+if !EVAS_STATIC_BUILD_GENERIC
+SUBDIRS += generic
+endif
+endif
+
diff --git a/src/modules/loaders/generic/.cvsignore b/src/modules/loaders/generic/.cvsignore
new file mode 100644 (file)
index 0000000..a51c966
--- /dev/null
@@ -0,0 +1,6 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.lo
+*.la
\ No newline at end of file
diff --git a/src/modules/loaders/generic/Makefile.am b/src/modules/loaders/generic/Makefile.am
new file mode 100644 (file)
index 0000000..a9e522e
--- /dev/null
@@ -0,0 +1,38 @@
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+@FREETYPE_CFLAGS@ \
+@PIXMAN_CFLAGS@ \
+@evas_image_loader_generic_cflags@ \
+@EINA_CFLAGS@ \
+@EVIL_CFLAGS@ \
+@WIN32_CPPFLAGS@
+
+AM_CFLAGS = @WIN32_CFLAGS@
+
+
+if BUILD_LOADER_GENERIC
+if !EVAS_STATIC_BUILD_GENERIC
+
+pkgdir = $(libdir)/evas/modules/loaders/generic/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = evas_image_load_generic.c
+
+module_la_LIBADD = @EINA_LIBS@ @evas_image_loader_generic_libs@ @SHM_OPEN_LINK@ $(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_generic.la
+
+libevas_loader_generic_la_SOURCES = evas_image_load_generic.c
+libevas_loader_generic_la_LIBADD = @evas_image_loader_generic_libs@ @SHM_OPEN_LINK@
+
+endif
+endif
diff --git a/src/modules/loaders/generic/evas_image_load_generic.c b/src/modules/loaders/generic/evas_image_load_generic.c
new file mode 100644 (file)
index 0000000..e8bc039
--- /dev/null
@@ -0,0 +1,395 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_common.h"
+#include "evas_private.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+static Eina_Bool evas_image_load_file_head_generic(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_generic(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4);
+
+Evas_Image_Load_Func evas_image_load_generic_func =
+{
+  EINA_TRUE,
+  evas_image_load_file_head_generic,
+  evas_image_load_file_data_generic
+};
+
+static Eina_Bool
+illegal_char(const char *str)
+{
+   const char *p;
+   
+   for (p = str; *p; p++)
+     {
+        if (*p <  '-')  return EINA_TRUE;
+        if (*p == '/')  return EINA_TRUE;
+        if (*p == ';')  return EINA_TRUE;
+        if (*p == ':')  return EINA_TRUE;
+        if (*p == '<')  return EINA_TRUE;
+        if (*p == '>')  return EINA_TRUE;
+        if (*p == '?')  return EINA_TRUE;
+        if (*p == '[')  return EINA_TRUE;
+        if (*p == '\\') return EINA_TRUE;
+        if (*p == ']')  return EINA_TRUE;
+        if (*p == '`')  return EINA_TRUE;
+        if (*p == '{')  return EINA_TRUE;
+        if (*p == '|')  return EINA_TRUE;
+        if (*p == '}')  return EINA_TRUE;
+        if (*p == '~')  return EINA_TRUE;
+        if (*p == 0x7f) return EINA_TRUE;
+     }
+   return EINA_FALSE;
+}
+
+static void
+escape_copy(const char *src, char *dst)
+{
+   const char *s;
+   char *d;
+   
+   for (s = src, d = dst; *s; s++, d++)
+     {
+        if ((*s == ' ')  ||
+            (*s == '!')  ||
+            (*s == '"')  ||
+            (*s == '#')  ||
+            (*s == '$')  ||
+            (*s == '%')  ||
+            (*s == '&')  ||
+            (*s == '\'') ||
+            (*s == '(')  ||
+            (*s == ')')  ||
+            (*s == '*')  ||
+            (*s == '[')  ||
+            (*s == '\\') ||
+            (*s == ']')  ||
+            (*s == '`')  ||
+            (*s == '{')  ||
+            (*s == '|')  ||
+            (*s == '}')  ||
+            (*s == '~'))
+          {
+             *d = '\\';
+             d++;
+          }
+        *d = *s;
+     }
+   *d = 0;
+}
+
+static void
+dotcat(char *dest, const char *src)
+{
+   int len = strlen(dest);
+   const char *s;
+   char *d;
+   
+   for (d = dest + len, s = src; *s; d++, s++) *d = tolower(*s);
+   *d = 0;
+}
+
+static Eina_Bool
+evas_image_load_file_head_generic(Image_Entry *ie, const char *file, const char *key, int *error)
+{
+   Eina_Bool res = EINA_FALSE;
+   int w = 0, h = 0, alpha = 0;
+   const char *dot1 = NULL, *dot2 = NULL, *end, *p;
+   char *cmd = NULL, decoders[3][128], buf[4096];
+   char *img_loader = "evas_image_loader"; // FIXME: specific path
+   // eg $libdir/evas/generic_loaders
+   int cmd_len, len, decoders_num = 0, try_count = 0;
+   int read_data = 0;
+   char *tmpfname = NULL, *shmfname = NULL;
+   
+   DATA32 *body;
+   FILE *f;
+   
+   // enough for command + params excluding filem key and loadopts
+   cmd_len = 1024 + strlen(img_loader);
+   cmd_len += strlen(file) * 2;
+   if (key) cmd_len += strlen(key) * 2;
+   cmd = alloca(cmd_len);
+
+   len = strlen(file);
+   if (len < 1)
+     {
+        *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+       return EINA_FALSE;
+     }
+   end = file + len;
+   for (p = end - 1; p >= file; p--)
+     {
+        if      ((!dot1) && (*p == '.')) dot1 = p; 
+        else if ((!dot2) && (*p == '.')) dot2 = p;
+        else if ((dot1) && (dot2)) break;
+    }
+   if (dot2)
+     {
+        // double extn not too long        
+        if (((end - dot2) <= 10) && (!illegal_char(dot2)))
+          {
+             strcpy(&(decoders[decoders_num][0]), img_loader);
+             dotcat(&(decoders[decoders_num][0]), dot2);
+             decoders_num++;
+          }
+        // single extn not too long
+        if (((end - dot1) <= 5) && (!illegal_char(dot1)))
+          {
+             strcpy(&(decoders[decoders_num][0]), img_loader);
+             dotcat(&(decoders[decoders_num][0]), dot1);
+             decoders_num++;
+          }
+        strcpy(decoders[decoders_num], img_loader);
+        decoders_num++;
+     }
+   else if (dot1)
+     {
+        // single extn not too long
+        if (((end - dot1) <= 5) && (!illegal_char(dot1)))
+          {
+             strcpy(&(decoders[decoders_num][0]), img_loader);
+             dotcat(&(decoders[decoders_num][0]), dot1);
+             decoders_num++;
+          }
+        strcpy(decoders[decoders_num], img_loader);
+        decoders_num++;
+     }
+   else
+     {
+        strcpy(decoders[decoders_num], img_loader);
+        decoders_num++;
+     }
+   
+   for (try_count = 0; try_count < decoders_num; try_count++)
+     {
+        // FIXME: strcats could be more efficient, not that it matters much
+        // here as we are about to build a cmd to exec via a shell that
+        // will interpret shell stuff and path hunt that will then exec the
+        // program itself that will dynamically link that will again
+        // parse the arguments and finally do something...
+        strcpy(cmd, decoders[try_count]);
+        strcat(cmd, " ");
+        // filename first arg
+        len = strlen(cmd);
+        escape_copy(file, cmd + len);
+        if (key)
+          {
+             strcat(cmd, " -key ");
+             len = strlen(cmd);
+             escape_copy(key, cmd + len);
+          }
+        if (ie->load_opts.scale_down_by > 1)
+          {
+             strcat(cmd, " -opt-scale-down-by ");
+             snprintf(buf, sizeof(buf), "%i", ie->load_opts.scale_down_by);
+             strcat(cmd, buf);
+          }
+        if (ie->load_opts.dpi > 0.0)
+          {
+             strcat(cmd, " -opt-dpi ");
+             snprintf(buf, sizeof(buf), "%i", (int)(ie->load_opts.dpi * 1000.0));
+             strcat(cmd, buf);
+          }
+        if ((ie->load_opts.w > 0) &&
+            (ie->load_opts.h > 0))
+          {
+             strcat(cmd, " -opt-size ");
+             snprintf(buf, sizeof(buf), "%i %i", ie->load_opts.w, ie->load_opts.h);
+             strcat(cmd, buf);
+         }
+        f = popen(cmd, "r");
+        if (f) break;
+     }
+   if (!f)
+     {
+       *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+       return EINA_FALSE;
+     }
+   while (fgets(buf, sizeof(buf), f))
+     {
+        len = strlen(buf);
+        if (len > 0)
+          {
+             if ((buf[len - 1] == '\n')) buf[len - 1] = 0;
+             if (!strncmp(buf, "size ", 5))
+               {
+                  int tw = 0, th = 0;
+                  
+                  len = sscanf(buf, "%*s %i %i", &tw, &th);
+                  if (len == 2)
+                    {
+                       if ((tw > 0) && (th > 0))
+                         {
+                            w = tw;
+                            h = th;
+                         }
+                    }
+               }
+             else if (!strncmp(buf, "alpha ", 6))
+               {
+                  int ta;
+                  
+                  len = sscanf(buf, "%*s %i", &ta);
+                  if (len == 1)
+                    {
+                       alpha = ta;
+                    }
+               }
+             else if (!strncmp(buf, "tmpfile ", 8))
+               {
+                  tmpfname = buf + 8;
+                  goto getdata;
+               }
+#ifdef HAVE_SHM_OPEN        
+             else if (!strncmp(buf, "shmfile ", 8))
+               {
+                  shmfname = buf + 8;
+                  goto getdata;
+               }
+#endif             
+             else if (!strncmp(buf, "data", 4))
+               {
+                  read_data = 1;
+                  goto getdata;
+               }
+          }
+     }
+getdata:
+   if ((!read_data) && (!tmpfname) && (!shmfname))
+     {
+       *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+       goto on_error;
+     }
+   if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
+       IMG_TOO_BIG(w, h))
+     {
+       *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+       goto on_error;
+     }
+   if (alpha) ie->flags.alpha = 1;
+   ie->w = w;
+   ie->h = h;
+   
+   evas_cache_image_surface_alloc(ie, ie->w, ie->h);
+   body = evas_cache_image_pixels(ie);
+   if (!body)
+     {
+        *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+        goto on_error;
+     }
+   
+   if ((tmpfname) || (shmfname))
+     {
+        int fd = -1;
+        
+        // open
+        if (tmpfname)
+           fd = open(tmpfname, O_RDONLY, S_IRUSR);
+#ifdef HAVE_SHM_OPEN        
+        else if (shmfname)
+           fd = shm_open(shmfname, O_RDONLY, S_IRUSR);
+#endif        
+        if (fd >= 0)
+          {
+             void *addr;
+             
+             // mmap
+             addr = mmap(NULL, w * h * sizeof(DATA32), 
+                         PROT_READ, MAP_SHARED, fd, 0);
+             if (addr != MAP_FAILED)
+               {
+                  memcpy(body, addr, w * h * sizeof(DATA32));
+                  munmap(addr, w * h * sizeof(DATA32));
+               }
+             // close
+             if (tmpfname)
+               {
+                  close(fd);
+                  unlink(tmpfname);
+               }
+#ifdef HAVE_SHM_OPEN        
+             else if (shmfname)
+               {
+                  close(fd);
+                  shm_unlink(shmfname);
+               }
+#endif             
+          }
+        else
+          {
+             *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+             goto on_error;
+          }
+     }
+   else if (read_data)
+     {
+        if (fread(body, w * h * sizeof(DATA32), 1, f) != 1)
+          {
+             *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+             goto on_error;
+          }
+     }
+   
+   res = EINA_TRUE;
+   *error = EVAS_LOAD_ERROR_NONE;
+   
+ on_error:
+   if (f) pclose(f);
+   return res;
+}
+
+static Eina_Bool
+evas_image_load_file_data_generic(Image_Entry *ie, const char *file, const char *key, int *error)
+{
+   DATA32 *body;
+
+   body = evas_cache_image_pixels(ie);
+   if (!body)
+     {
+        return evas_image_load_file_head_generic(ie, file, key, error);
+     }
+   *error = EVAS_LOAD_ERROR_NONE;
+   return EINA_TRUE;
+}
+
+static int
+module_open(Evas_Module *em)
+{
+   if (!em) return 0;
+   em->functions = (void *)(&evas_image_load_generic_func);
+   return 1;
+}
+
+static void
+module_close(Evas_Module *em __UNUSED__)
+{
+}
+
+static Evas_Module_Api evas_modapi =
+{
+   EVAS_MODULE_API_VERSION,
+   "generic",
+   "none",
+   {
+     module_open,
+     module_close
+   }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, generic);
+
+#ifndef EVAS_STATIC_BUILD_GENERIC
+EVAS_EINA_MODULE_DEFINE(image_loader, generic);
+#endif