summaryrefslogtreecommitdiff
path: root/src/modules/evas/image_loaders
diff options
context:
space:
mode:
authorBogdan Devichev <b.devichev@samsung.com>2014-11-26 18:50:43 +0200
committerCedric BAIL <cedric@osg.samsung.com>2014-12-23 21:13:43 +0100
commit043055fc8eb3d7db11856f4d142f5e0e3262b3a6 (patch)
tree4da5d613fc0d859a8e5c588a072f00f1a8bf520e /src/modules/evas/image_loaders
parenta14e0b8b3283ff4ac34f13258268326882e4b1ec (diff)
downloadefl-043055fc8eb3d7db11856f4d142f5e0e3262b3a6.tar.gz
evas: preparation of places for model_saver_loader separated from image_saver_loader.
Diffstat (limited to 'src/modules/evas/image_loaders')
-rw-r--r--src/modules/evas/image_loaders/bmp/evas_image_load_bmp.c1411
-rw-r--r--src/modules/evas/image_loaders/dds/evas_image_load_dds.c569
-rw-r--r--src/modules/evas/image_loaders/dds/s3tc.h17
-rw-r--r--src/modules/evas/image_loaders/dds/s3tc_decoder.c219
-rw-r--r--src/modules/evas/image_loaders/eet/evas_image_load_eet.c245
-rw-r--r--src/modules/evas/image_loaders/generic/evas_image_load_generic.c479
-rw-r--r--src/modules/evas/image_loaders/gif/evas_image_load_gif.c914
-rw-r--r--src/modules/evas/image_loaders/ico/evas_image_load_ico.c844
-rw-r--r--src/modules/evas/image_loaders/jp2k/evas_image_load_jp2k.c409
-rw-r--r--src/modules/evas/image_loaders/jpeg/evas_image_load_jpeg.c1500
-rw-r--r--src/modules/evas/image_loaders/pmaps/evas_image_load_pmaps.c591
-rw-r--r--src/modules/evas/image_loaders/png/evas_image_load_png.c467
-rw-r--r--src/modules/evas/image_loaders/psd/evas_image_load_psd.c937
-rw-r--r--src/modules/evas/image_loaders/tga/evas_image_load_tga.c593
-rw-r--r--src/modules/evas/image_loaders/tgv/evas_image_load_tgv.c587
-rw-r--r--src/modules/evas/image_loaders/tiff/evas_image_load_tiff.c380
-rw-r--r--src/modules/evas/image_loaders/wbmp/evas_image_load_wbmp.c208
-rw-r--r--src/modules/evas/image_loaders/webp/evas_image_load_webp.c156
-rw-r--r--src/modules/evas/image_loaders/xpm/evas_image_load_xpm.c747
19 files changed, 11273 insertions, 0 deletions
diff --git a/src/modules/evas/image_loaders/bmp/evas_image_load_bmp.c b/src/modules/evas/image_loaders/bmp/evas_image_load_bmp.c
new file mode 100644
index 0000000000..d54cfdc8f6
--- /dev/null
+++ b/src/modules/evas/image_loaders/bmp/evas_image_load_bmp.c
@@ -0,0 +1,1411 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include <math.h>
+
+#include "evas_common_private.h"
+#include "evas_private.h"
+
+typedef struct _BMP_Header BMP_Header;
+struct _BMP_Header
+{
+ unsigned int bmpsize;
+ unsigned short res1;
+ unsigned short res2;
+ unsigned int offset;
+ unsigned int head_size;
+ int width;
+ int height;
+ unsigned short bit_count;
+ int comp;
+ // hdpi
+ // vdpi
+ int palette_size;
+ // important_colors
+
+ unsigned int rmask;
+ unsigned int gmask;
+ unsigned int bmask;
+ unsigned int amask;
+
+ Eina_Bool hasa;
+};
+
+typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
+struct _Evas_Loader_Internal
+{
+ Eina_File *f;
+ Evas_Image_Load_Opts *opts;
+};
+
+static Eina_Bool
+read_short(unsigned char *map, size_t length, size_t *position, short *ret)
+{
+ unsigned char b[2];
+
+ if (*position + 2 > length) return EINA_FALSE;
+ b[0] = map[(*position)++];
+ b[1] = map[(*position)++];
+ *ret = (b[1] << 8) | b[0];
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_ushort(unsigned char *map, size_t length, size_t *position, unsigned short *ret)
+{
+ unsigned char b[2];
+
+ if (*position + 2 > length) return EINA_FALSE;
+ b[0] = map[(*position)++];
+ b[1] = map[(*position)++];
+ *ret = (b[1] << 8) | b[0];
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_int(unsigned char *map, size_t length, size_t *position, int *ret)
+{
+ unsigned char b[4];
+ int i;
+
+ if (*position + 4 > length) return EINA_FALSE;
+ for (i = 0; i < 4; i++)
+ b[i] = map[(*position)++];
+ *ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_uint(unsigned char *map, size_t length, size_t *position, unsigned int *ret)
+{
+ unsigned char b[4];
+ int i;
+
+ if (*position + 4 > length) return EINA_FALSE;
+ for (i = 0; i < 4; i++)
+ b[i] = map[(*position)++];
+ *ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_uchar(unsigned char *map, size_t length, size_t *position, unsigned char *ret)
+{
+ if (*position + 1 > length) return EINA_FALSE;
+ *ret = map[(*position)++];
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_skip(size_t length, size_t *position, int skip)
+{
+ if (*position + skip > length) return EINA_FALSE;
+ *position += skip;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_mem(unsigned char *map, size_t length, size_t *position, void *buffer, int size)
+{
+ if (*position + size > length) return EINA_FALSE;
+ memcpy(buffer, map + *position, size);
+ *position += size;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_evas_image_load_file_header(void *map, size_t fsize, size_t *position, int *image_size,
+ BMP_Header *header, int *error)
+{
+ if (strncmp(map, "BM", 2)) return EINA_FALSE; // magic number
+ *position += 2;
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ if (!read_uint(map, fsize, position, &header->bmpsize)) return EINA_FALSE;
+ if (!read_ushort(map, fsize, position, &header->res1)) return EINA_FALSE;
+ if (!read_ushort(map, fsize, position, &header->res2)) return EINA_FALSE;
+ if (!read_uint(map, fsize, position, &header->offset)) return EINA_FALSE;
+ if (!read_uint(map, fsize, position, &header->head_size)) return EINA_FALSE;
+ if (header->offset > fsize) return EINA_FALSE;
+
+ switch (header->head_size)
+ {
+ case 12: // OS/2 V1 + Windows 3.0
+ {
+ short tmp;
+
+ if (!read_short(map, fsize, position, &tmp)) return EINA_FALSE;
+ header->width = tmp; // width
+ if (!read_short(map, fsize, position, &tmp)) return EINA_FALSE;
+ header->height = tmp; // height
+ if (!read_short(map, fsize, position, &tmp)) return EINA_FALSE;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, position, &tmp)) return EINA_FALSE;
+ header->bit_count = tmp; // bits per pixel: 1, 4, 8 & 24
+ break;
+ }
+ case 64: // OS/2 V2
+ {
+ short tmp;
+ int tmp2;
+
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->width = tmp2; // width
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->height = tmp2; // height
+ if (!read_short(map, fsize, position, &tmp)) return EINA_FALSE;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, position, &tmp)) return EINA_FALSE;
+ header->bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->comp = tmp2; // compression method
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ if (tmp2 <= *image_size) *image_size = tmp2; // bitmap data size, GIMP can handle image size error
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ //hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ //vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ //important_colors = tmp2; // number of important colors - 0 if all
+ if (!read_skip(fsize, position, 24)) return EINA_FALSE; // skip unused header
+ if (*image_size == 0) *image_size = fsize - header->offset;
+ break;
+ }
+ case 40: // Windows 3.0 + (v3)
+ {
+ short tmp;
+ int tmp2;
+
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->width = tmp2; // width
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->height = tmp2; // height
+ if (!read_short(map, fsize, position, &tmp)) return EINA_FALSE;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, position, &tmp)) return EINA_FALSE;
+ header->bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->comp = tmp2; // compression method
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ if (tmp2 <= *image_size) *image_size = tmp2; // bitmap data size, GIMP can handle image size error
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ //hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ //vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ //important_colors = tmp2; // number of important colors - 0 if all
+ if (*image_size == 0) *image_size = fsize - header->offset;
+ if ((header->comp == 0) && (header->bit_count == 32)) header->hasa = 1; // GIMP seems to store it this way
+ break;
+ }
+ case 108: // Windows 95/NT4 + (v4)
+ {
+ short tmp;
+ int tmp2;
+
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->width = tmp2; // width
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->height = tmp2; // height
+ if (!read_short(map, fsize, position, &tmp)) return EINA_FALSE;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, position, &tmp)) return EINA_FALSE;
+ header->bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->comp = tmp2; // compression method
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ if (tmp2 <= *image_size) *image_size = tmp2; // bitmap data size, GIMP can handle image size error
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ //hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ //vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ //important_colors = tmp2; // number of important colors - 0 if all
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->rmask = tmp2; // red mask
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->gmask = tmp2; // green mask
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->bmask = tmp2; // blue mask
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->amask = tmp2; // alpha mask
+ if (!read_skip(fsize, position, 36)) return EINA_FALSE; // skip unused cie
+ if (!read_skip(fsize, position, 12)) return EINA_FALSE; // skip unused gamma
+ if (*image_size == 0) *image_size = fsize - header->offset;
+ if ((header->amask) && (header->bit_count == 32)) header->hasa = 1;
+ break;
+ }
+ case 124: // Windows 98/2000 + (v5)
+ {
+ short tmp;
+ int tmp2;
+
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->width = tmp2; // width
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->height = tmp2; // height
+ if (!read_short(map, fsize, position, &tmp)) return EINA_FALSE;
+ //planes = tmp; // must be 1
+ if (!read_short(map, fsize, position, &tmp)) return EINA_FALSE;
+ header->bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->comp = tmp2; // compression method
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ if (tmp2 <= *image_size) *image_size = tmp2; // bitmap data size, GIMP can handle image size error
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ //hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ //vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ //important_colors = tmp2; // number of important colors - 0 if all
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->rmask = tmp2; // red mask
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->gmask = tmp2; // green mask
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->bmask = tmp2; // blue mask
+ if (!read_int(map, fsize, position, &tmp2)) return EINA_FALSE;
+ header->amask = tmp2; // alpha mask
+ if (!read_skip(fsize, position, 36)) return EINA_FALSE; // skip unused cie
+ if (!read_skip(fsize, position, 12)) return EINA_FALSE; // skip unused gamma
+ if (!read_skip(fsize, position, 16)) return EINA_FALSE; // skip others
+ if (*image_size == 0) *image_size = fsize - header->offset;
+ if ((header->amask) && (header->bit_count == 32)) header->hasa = 1;
+ break;
+ }
+ default:
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+static void *
+evas_image_load_file_open_bmp(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
+ Evas_Image_Load_Opts *opts,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error)
+{
+ Evas_Loader_Internal *loader;
+
+ loader = calloc(1, sizeof (Evas_Loader_Internal));
+ if (!loader)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return NULL;
+ }
+
+ loader->f = f;
+ loader->opts = opts;
+
+ return loader;
+}
+
+static void
+evas_image_load_file_close_bmp(void *loader_data)
+{
+ free(loader_data);
+}
+
+static Eina_Bool
+evas_image_load_file_head_bmp(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Evas_Loader_Internal *loader;
+ Evas_Image_Load_Opts *load_opts;
+ Eina_File *f;
+ void *map = NULL;
+ size_t position = 0;
+ BMP_Header header;
+ int image_size = 0;
+ size_t fsize;
+ Eina_Bool r = EINA_FALSE;
+
+ loader = loader_data;
+ f = loader->f;
+ load_opts = loader->opts;
+
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ fsize = eina_file_size_get(f);
+ if (fsize < 2) goto close_file;
+
+ map = eina_file_map_all(f, EINA_FILE_RANDOM);
+ if (!map) goto close_file;
+
+ memset(&header, 0, sizeof (header));
+
+ if (!_evas_image_load_file_header(map, fsize, &position, &image_size, &header, error))
+ goto close_file;
+
+ if (header.height < 0)
+ {
+ header.height = -header.height;
+ //right_way_up = 1;
+ }
+
+ if ((header.width < 1) || (header.height < 1) ||
+ (header.width > IMG_MAX_SIZE) || (header.height > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(header.width, header.height))
+ {
+ if (IMG_TOO_BIG(header.width, header.height))
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ else
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+ /* It is not bad idea that bmp loader support scale down decoding
+ * because of memory issue in mobile world.*/
+ if (load_opts->scale_down_by > 1)
+ {
+ header.width /= load_opts->scale_down_by;
+ header.height /= load_opts->scale_down_by;
+ }
+
+ if (header.bit_count < 16)
+ {
+ //if ((palette_size < 0) || (palette_size > 256)) pal_num = 256;
+ //else pal_num = palette_size;
+ if (header.bit_count == 1)
+ {
+ if (header.comp == 0) // no compression
+ {
+ }
+ else
+ goto close_file;
+ }
+ else if (header.bit_count == 4)
+ {
+ if (header.comp == 0) // no compression
+ {
+ }
+ else if (header.comp == 2) // rle 4bit/pixel
+ {
+ }
+ else
+ goto close_file;
+ }
+ else if (header.bit_count == 8)
+ {
+ if (header.comp == 0) // no compression
+ {
+ }
+ else if (header.comp == 1) // rle 8bit/pixel
+ {
+ }
+ else
+ goto close_file;
+ }
+ }
+ else if ((header.bit_count == 16) || (header.bit_count == 24) || (header.bit_count == 32))
+ {
+ if (header.comp == 0) // no compression
+ {
+ // handled
+ }
+ else if (header.comp == 3) // bit field
+ {
+ // handled
+ }
+ else if (header.comp == 4) // jpeg - only printer drivers
+ goto close_file;
+ else if (header.comp == 3) // png - only printer drivers
+ goto close_file;
+ else
+ goto close_file;
+ }
+ else
+ goto close_file;
+
+ prop->w = header.width;
+ prop->h = header.height;
+ if (header.hasa) prop->alpha = 1;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ r = EINA_TRUE;
+
+ close_file:
+ if (map) eina_file_map_free(f, map);
+ return r;
+}
+
+static Eina_Bool
+evas_image_load_file_data_bmp(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Evas_Loader_Internal *loader;
+ Evas_Image_Load_Opts *opts;
+ Eina_File *f;
+ BMP_Header header;
+ void *map = NULL;
+ size_t position = 0;
+ unsigned char *buffer = NULL, *buffer_end = NULL, *p;
+ int x = 0, y = 0, image_size = 0;
+ unsigned int *pal = NULL, pal_num = 0, *pix = NULL, fix, *surface = pixels;
+ int right_way_up = 0;
+ unsigned char r, g, b, a;
+ size_t fsize;
+
+ /* for scale decoding */
+ unsigned int *scale_surface = NULL, *scale_pix = NULL;
+ int scale_ratio = 1, image_w = 0, image_h = 0;
+ int row_size = 0; /* Row size is rounded up to a multiple of 4bytes */
+ int read_line = 0; /* total read line */
+
+ loader = loader_data;
+ f = loader->f;
+ opts = loader->opts;
+
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ fsize = eina_file_size_get(f);
+ if (fsize < 2) goto close_file;
+
+ map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (!map) goto close_file;
+
+ memset(&header, 0, sizeof (header));
+ header.palette_size = -1;
+
+ if (!_evas_image_load_file_header(map, fsize, &position, &image_size, &header, error))
+ goto close_file;
+
+ if (header.height < 0)
+ {
+ header.height = -header.height;
+ right_way_up = 1;
+ }
+ if ((header.width < 1) || (header.height < 1) || (header.width > IMG_MAX_SIZE) || (header.height > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(header.width, header.height))
+ {
+ if (IMG_TOO_BIG(header.width, header.height))
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ else
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+ /* It is not bad idea that bmp loader support scale down decoding
+ * because of memory issue in mobile world. */
+ if (opts->scale_down_by > 1)
+ scale_ratio = opts->scale_down_by;
+ image_w = header.width;
+ image_h = header.height;
+
+ if (scale_ratio > 1)
+ {
+ header.width /= scale_ratio;
+ header.height /= scale_ratio;
+
+ if ((header.width < 1) || (header.height < 1) )
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+ }
+
+ if ((header.width != (int)prop->w) || (header.height != (int)prop->h))
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+
+ row_size = ceil((double)(image_w * header.bit_count) / 32) * 4;
+ if (image_size != row_size * header.height)
+ image_size = row_size * header.height;
+
+ if (header.bit_count < 16)
+ {
+ unsigned int i;
+
+ if (header.bit_count == 1)
+ {
+ if ((header.palette_size <= 0) || (header.palette_size > 2)) pal_num = 2;
+ else pal_num = header.palette_size;
+ }
+ else if (header.bit_count == 4)
+ {
+ if ((header.palette_size <= 0) || (header.palette_size > 16)) pal_num = 16;
+ else pal_num = header.palette_size;
+ }
+ else if (header.bit_count == 8)
+ {
+ if ((header.palette_size <= 0) || (header.palette_size > 256)) pal_num = 256;
+ else pal_num = header.palette_size;
+ }
+ pal = alloca(256 * 4);
+ for (i = 0; i < pal_num; i++)
+ {
+ if (!read_uchar(map, fsize, &position, &b)) goto close_file;
+ if (!read_uchar(map, fsize, &position, &g)) goto close_file;
+ if (!read_uchar(map, fsize, &position, &r)) goto close_file;
+ if ((header.head_size != 12) /*&& (palette_size != 0)*/)
+ { // OS/2 V1 doesn't do the pad byte
+ if (!read_uchar(map, fsize, &position, &a)) goto close_file;
+ }
+ a = 0xff; // fillin a as solid for paletted images
+ pal[i] = ARGB_JOIN(a, r, g, b);
+ }
+ position = header.offset;
+
+ if ((scale_ratio == 1) || (header.comp !=0))
+ buffer = malloc(image_size + 8); // add 8 for padding to avoid checks
+ else
+ {
+ scale_surface = malloc(image_w * sizeof(DATA32)); //for one line decoding
+ if (!scale_surface)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+ buffer = malloc(row_size); // scale down is usually set because of memory issue, so read line by line
+ }
+
+ if (!buffer)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+ if ((scale_ratio == 1) || (header.comp !=0))
+ buffer_end = buffer + image_size;
+ else
+ buffer_end = buffer + row_size;
+ p = buffer;
+
+ if ((scale_ratio == 1) || (header.comp !=0))
+ {
+ if (!read_mem(map, fsize, &position, buffer, image_size)) goto close_file;
+ }
+ else
+ {
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ }
+
+ if (header.bit_count == 1)
+ {
+ if (header.comp == 0) // no compression
+ {
+ pix = surface;
+
+ for (y = 0; y < header.height; y++)
+ {
+ if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
+ if (scale_ratio > 1) pix = scale_surface; // one line decoding
+
+ for (x = 0; x < image_w; x++)
+ {
+ if ((x & 0x7) == 0x0)
+ {
+ *pix = pal[*p >> 7];
+ }
+ else if ((x & 0x7) == 0x1)
+ {
+ *pix = pal[(*p >> 6) & 0x1];
+ }
+ else if ((x & 0x7) == 0x2)
+ {
+ *pix = pal[(*p >> 5) & 0x1];
+ }
+ else if ((x & 0x7) == 0x3)
+ {
+ *pix = pal[(*p >> 4) & 0x1];
+ }
+ else if ((x & 0x7) == 0x4)
+ {
+ *pix = pal[(*p >> 3) & 0x1];
+ }
+ else if ((x & 0x7) == 0x5)
+ {
+ *pix = pal[(*p >> 2) & 0x1];
+ }
+ else if ((x & 0x7) == 0x6)
+ {
+ *pix = pal[(*p >> 1) & 0x1];
+ }
+ else
+ {
+ *pix = pal[*p & 0x1];
+ p++;
+ }
+ if (p >= buffer_end) break;
+ pix++;
+ }
+
+ if (scale_ratio > 1)
+ {
+ if (!right_way_up) scale_pix = surface + ((header.height - 1 - y) * header.width);
+ else scale_pix = surface + (y * header.width);
+
+ pix = scale_surface;
+ for (x = 0; x < header.width; x++)
+ {
+ *scale_pix = *pix;
+ scale_pix ++;
+ pix += scale_ratio;
+ }
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ if ((x & 0x7) != 0) p++;
+ fix = (int)(((uintptr_t)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else
+ goto close_file;
+ }
+ else if (header.bit_count == 4)
+ {
+ if (header.comp == 0) // no compression
+ {
+ pix = surface;
+ for (y = 0; y < header.height; y++)
+ {
+ if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
+ if (scale_ratio > 1) pix = scale_surface; // one line decoding
+ for (x = 0; x < image_w; x++)
+ {
+ if ((x & 0x1) == 0x1)
+ {
+ *pix = pal[*p & 0x0f];
+ p++;
+ }
+ else
+ {
+ *pix = pal[*p >> 4];
+ }
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ if (!right_way_up) scale_pix = surface + ((header.height - 1 - y) * header.width);
+ else scale_pix = surface + (y * header.width);
+
+ pix = scale_surface;
+ for (x = 0; x < header.width; x++)
+ {
+ *scale_pix = *pix;
+ scale_pix ++;
+ pix += scale_ratio;
+ }
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ if ((x & 0x1) != 0) p++;
+ fix = (int)(((uintptr_t)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else if (header.comp == 2) // rle 4bit/pixel
+ {
+ int count = 0, done = 0, wpad;
+ int scale_x = 0, scale_y = 0;
+ Eina_Bool scale_down_line = EINA_TRUE;
+
+ pix = surface;
+ if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
+ wpad = ((image_w + 1) / 2) * 2;
+ while (p < buffer_end)
+ {
+ if (p[0])
+ {
+ if (scale_down_line)
+ {
+ if ((x + p[0]) <= wpad)
+ {
+ unsigned int col1 = pal[p[1] >> 4];
+ unsigned int col2 = pal[p[1] & 0xf];
+
+ count = p[0] / 2;
+ while (count > 0)
+ {
+ if (x < header.width)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < header.width))
+ {
+ *pix = col1;
+ pix++;
+ scale_x++;
+ }
+ x++;
+ }
+ if (x < header.width)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < header.width))
+ {
+ *pix = col2;
+ pix++;
+ scale_x++;
+ }
+ x++;
+ }
+ count--;
+ }
+ if (p[0] & 0x1)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < header.width))
+ {
+ *pix = col1;
+ pix++;
+ scale_x++;
+ }
+ x++;
+ }
+ }
+ }
+ p += 2;
+ }
+ else
+ {
+ switch (p[1])
+ {
+ case 0: // EOL
+ x = 0;
+ scale_x = 0;
+ y++;
+ if ((y % scale_ratio) == 0)
+ {
+ scale_y++;
+ scale_down_line = EINA_TRUE;
+ if (!right_way_up)
+ pix = surface + ((header.height - 1 - scale_y) * header.width);
+ else
+ pix = surface + (scale_y * header.width);
+ }
+ else
+ scale_down_line = EINA_FALSE;
+ if (scale_y >= header.height)
+ {
+ p = buffer_end;
+ }
+ p += 2;
+ break;
+ case 1: // EOB
+ p = buffer_end;
+ break;
+ case 2: // DELTA
+ x += p[2];
+ y += p[3];
+ scale_x = x / scale_ratio;
+ scale_y = y / scale_ratio;
+ if ((scale_x >= header.width) || (scale_y >= header.height))
+ {
+ p = buffer_end;
+ }
+ if (!right_way_up)
+ pix = surface + scale_x + ((header.height - 1 - scale_y) * header.width);
+ else
+ pix = surface + scale_x + (scale_y * header.width);
+ p += 4;
+ break;
+ default:
+ count = p[1];
+ if (((p + count) > buffer_end) ||
+ ((x + count) > header.width))
+ {
+ p = buffer_end;
+ break;
+ }
+ p += 2;
+ done = count;
+ count /= 2;
+ while (count > 0)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < header.width))
+ {
+ *pix = pal[*p >> 4];
+ pix++;
+ scale_x++;
+ }
+ x++;
+ if (((x % scale_ratio) == 0) && (scale_x < header.width))
+ {
+ *pix = pal[*p & 0xf];
+ pix++;
+ scale_x++;
+ }
+ x++;
+
+ p++;
+ count--;
+ }
+
+ if (done & 0x1)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < header.width))
+ {
+ *pix = pal[*p >> 4];
+ scale_x++;
+ }
+ x++;
+ p++;
+ }
+ if ((done & 0x3) == 0x1)
+ p += 2;
+ else if ((done & 0x3) == 0x2)
+ p += 1;
+ break;
+ }
+ }
+ }
+ }
+ else
+ goto close_file;
+ }
+ else if (header.bit_count == 8)
+ {
+ if (header.comp == 0) // no compression
+ {
+ pix = surface;
+ for (y = 0; y < header.height; y++)
+ {
+ if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
+ for (x = 0; x < header.width; x++)
+ {
+ *pix = pal[*p];
+ p += scale_ratio;
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((uintptr_t)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else if (header.comp == 1) // rle 8bit/pixel
+ {
+ int count = 0, done = 0;
+ int scale_x = 0, scale_y = 0;
+ Eina_Bool scale_down_line = EINA_TRUE;
+
+ pix = surface;
+ if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
+
+ while (p < buffer_end)
+ {
+ if (p[0])
+ {
+ if (scale_down_line)
+ {
+ if ((x + p[0]) <= image_w)
+ {
+ unsigned int col = pal[p[1]];
+
+ count = p[0];
+ while (count > 0)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < header.width))
+ {
+ *pix = col;
+ pix++;
+ scale_x ++;
+ }
+ x++;
+ count--;
+ }
+ }
+ }
+ p += 2;
+ }
+ else
+ {
+ switch (p[1])
+ {
+ case 0: // EOL
+ x = 0;
+ scale_x = 0;
+ y++;
+ if ((y % scale_ratio) == 0)
+ {
+ scale_y++;
+ scale_down_line = EINA_TRUE;
+ if (!right_way_up)
+ pix = surface + ((header.height - 1 - scale_y) * header.width);
+ else
+ pix = surface + (scale_y * header.width);
+ }
+ else
+ scale_down_line = EINA_FALSE;
+
+ if (scale_y >= header.height)
+ {
+ p = buffer_end;
+ }
+ p += 2;
+ break;
+ case 1: // EOB
+ p = buffer_end;
+ break;
+ case 2: // DELTA
+ x += p[2];
+ y += p[3];
+ scale_x = x / scale_ratio;
+ scale_y = y / scale_ratio;
+ if ((scale_x >= header.width) || (scale_y >= header.height))
+ {
+ p = buffer_end;
+ }
+ if (!right_way_up)
+ pix = surface + scale_x + ((header.height - 1 - scale_y) * header.width);
+ else
+ pix = surface + scale_x + (scale_y * header.width);
+ p += 4;
+ break;
+ default:
+ count = p[1];
+ if (((p + count) > buffer_end) ||
+ ((x + count) > image_w))
+ {
+ p = buffer_end;
+ break;
+ }
+ p += 2;
+ done = count;
+ while (count > 0)
+ {
+ if (((x % scale_ratio) == 0) && (scale_x < header.width))
+ {
+ *pix = pal[*p];
+ pix++;
+ scale_x ++;
+ }
+ p++;
+ x++;
+ count--;
+ }
+ if (done & 0x1) p++;
+ break;
+ }
+ }
+ }
+ }
+ else
+ goto close_file;
+ }
+ }
+ else if ((header.bit_count == 16) || (header.bit_count == 24) || (header.bit_count == 32))
+ {
+ if (header.comp == 0) // no compression
+ {
+ position = header.offset;
+ if (scale_ratio == 1)
+ buffer = malloc(image_size + 8); // add 8 for padding to avoid checks
+ else
+ buffer = malloc(row_size); // scale down is usually set because of memory issue, so read line by line
+ if (!buffer)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+ if (scale_ratio == 1)
+ buffer_end = buffer + image_size;
+ else
+ buffer_end = buffer + row_size;
+
+ p = buffer;
+ if (scale_ratio == 1)
+ {
+ if (!read_mem(map, fsize, &position, buffer, image_size)) goto close_file;
+ }
+ else
+ {
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ }
+ if (header.bit_count == 16)
+ {
+ unsigned short tmp;
+
+ pix = surface;
+ for (y = 0; y < header.height; y++)
+ {
+ if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
+ for (x = 0; x < header.width; x++)
+ {
+ tmp = *((unsigned short *)(p));
+
+ r = (tmp >> 7) & 0xf8; r |= r >> 5;
+ g = (tmp >> 2) & 0xf8; g |= g >> 5;
+ b = (tmp << 3) & 0xf8; b |= b >> 5;
+ *pix = ARGB_JOIN(0xff, r, g, b);
+
+ p += 2 * scale_ratio;
+
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((uintptr_t)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else if (header.bit_count == 24)
+ {
+ pix = surface;
+ for (y = 0; y < header.height; y++)
+ {
+ if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
+ for (x = 0; x < header.width; x++)
+ {
+ b = p[0];
+ g = p[1];
+ r = p[2];
+ *pix = ARGB_JOIN(0xff, r, g, b);
+ p += 3 * scale_ratio;
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((uintptr_t)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else if (header.bit_count == 32)
+ {
+ int none_zero_alpha = 0;
+ pix = surface;
+ for (y = 0; y < header.height; y++)
+ {
+ if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
+ for (x = 0; x < header.width; x++)
+ {
+ b = p[0];
+ g = p[1];
+ r = p[2];
+ a = p[3];
+ if (a) none_zero_alpha = 1;
+ if (!header.hasa) a = 0xff;
+ *pix = ARGB_JOIN(a, r, g, b);
+ p += 4 * scale_ratio;
+
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((uintptr_t)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ if (!none_zero_alpha)
+ {
+ prop->alpha = 0;
+ if (header.hasa)
+ {
+ unsigned int *pixend = surface + (header.width * header.height);
+
+ for (pix = surface; pix < pixend; pix++)
+ A_VAL(pix) = 0xff;
+ }
+ }
+ }
+ else
+ goto close_file;
+ }
+ else if (header.comp == 3) // bit field
+ {
+ if (!read_uint(map, fsize, &position, &header.rmask)) goto close_file;
+ if (!read_uint(map, fsize, &position, &header.gmask)) goto close_file;
+ if (!read_uint(map, fsize, &position, &header.bmask)) goto close_file;
+
+ position = header.offset;
+ if (scale_ratio == 1)
+ buffer = malloc(image_size + 8); // add 8 for padding to avoid checks
+ else
+ buffer = malloc(row_size); // scale down is usually set because of memory issue, so read line by line
+
+ if (!buffer)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+ if (scale_ratio == 1)
+ buffer_end = buffer + image_size;
+ else
+ buffer_end = buffer + row_size;
+
+ p = buffer;
+ if (scale_ratio == 1)
+ {
+ if (!read_mem(map, fsize, &position, buffer, image_size)) goto close_file;
+ }
+ else
+ {
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ }
+
+ if ((header.bit_count == 16) &&
+ (header.rmask == 0xf800) && (header.gmask == 0x07e0) && (header.bmask == 0x001f)
+ )
+ {
+ unsigned short tmp;
+
+ pix = surface;
+ for (y = 0; y < header.height; y++)
+ {
+ if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
+ for (x = 0; x < header.width; x++)
+ {
+ tmp = *((unsigned short *)(p));
+
+ r = (tmp >> 8) & 0xf8; r |= r >> 5;
+ g = (tmp >> 3) & 0xfc; g |= g >> 6;
+ b = (tmp << 3) & 0xf8; b |= b >> 5;
+ *pix = ARGB_JOIN(0xff, r, g, b);
+
+ p += 2 * scale_ratio;
+
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((uintptr_t)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else if ((header.bit_count == 16) &&
+ (header.rmask == 0x7c00) && (header.gmask == 0x03e0) && (header.bmask == 0x001f)
+ )
+ {
+ unsigned short tmp;
+ pix = surface;
+ for (y = 0; y < header.height; y++)
+ {
+ if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
+ for (x = 0; x < header.width; x++)
+ {
+ tmp = *((unsigned short *)(p));
+
+ r = (tmp >> 7) & 0xf8; r |= r >> 5;
+ g = (tmp >> 2) & 0xf8; g |= g >> 5;
+ b = (tmp << 3) & 0xf8; b |= b >> 5;
+ *pix = ARGB_JOIN(0xff, r, g, b);
+ p += 2 * scale_ratio;
+
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer_end, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((uintptr_t)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else if (header.bit_count == 32)
+ {
+ pix = surface;
+ for (y = 0; y < header.height; y++)
+ {
+ if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
+ for (x = 0; x < header.width; x++)
+ {
+ b = p[0];
+ g = p[1];
+ r = p[2];
+ a = p[3];
+ if (!header.hasa) a = 0xff;
+ *pix = ARGB_JOIN(a, r, g, b);
+
+ p += 4 * scale_ratio;
+
+ if (p >= buffer_end) break;
+ pix++;
+ }
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ position += row_size * (scale_ratio - 1);
+ if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((uintptr_t)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
+ }
+ }
+ else
+ goto close_file;
+ }
+ else if (header.comp == 4) // jpeg - only printer drivers
+ {
+ goto close_file;
+ }
+ else if (header.comp == 3) // png - only printer drivers
+ {
+ goto close_file;
+ }
+ else
+ goto close_file;
+ }
+ else
+ goto close_file;
+
+ if (buffer) free(buffer);
+ if (scale_surface) free(scale_surface);
+
+ eina_file_map_free(f, map);
+
+ prop->premul = EINA_TRUE;
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+
+ close_file:
+ if (buffer) free(buffer);
+ if (scale_surface) free(scale_surface);
+ if (map) eina_file_map_free(f, map);
+ return EINA_FALSE;
+}
+
+static Evas_Image_Load_Func evas_image_load_bmp_func =
+{
+ evas_image_load_file_open_bmp,
+ evas_image_load_file_close_bmp,
+ evas_image_load_file_head_bmp,
+ evas_image_load_file_data_bmp,
+ NULL,
+ EINA_TRUE,
+ EINA_FALSE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ em->functions = (void *)(&evas_image_load_bmp_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "bmp",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, bmp);
+
+#ifndef EVAS_STATIC_BUILD_BMP
+EVAS_EINA_MODULE_DEFINE(image_loader, bmp);
+#endif
diff --git a/src/modules/evas/image_loaders/dds/evas_image_load_dds.c b/src/modules/evas/image_loaders/dds/evas_image_load_dds.c
new file mode 100644
index 0000000000..d0a1c55d14
--- /dev/null
+++ b/src/modules/evas/image_loaders/dds/evas_image_load_dds.c
@@ -0,0 +1,569 @@
+/* @file evas_image_load_dds.c
+ * @author Jean-Philippe ANDRE <jpeg@videolan.org>
+ *
+ * Load Microsoft DirectDraw Surface files.
+ * Decode S3TC image format.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "Evas_Loader.h"
+#include "s3tc.h"
+
+#ifdef _WIN32
+# include <ddraw.h>
+#endif
+
+#define DDS_HEADER_SIZE 128
+
+typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
+struct _Evas_Loader_Internal
+{
+ Eina_File *f;
+
+ Evas_Colorspace format;
+ unsigned int stride, block_size, data_size;
+
+ struct {
+ unsigned int flags;
+ unsigned int fourcc;
+ unsigned int rgb_bitcount;
+ unsigned int r_mask;
+ unsigned int g_mask;
+ unsigned int b_mask;
+ unsigned int a_mask;
+ // TODO: check mipmaps to load faster a small image :)
+ } pf; // pixel format
+};
+
+#undef FOURCC
+#ifndef WORDS_BIGENDIAN
+# define FOURCC(a,b,c,d) ((d << 24) | (c << 16) | (b << 8) | a)
+#else
+# define FOURCC(a,b,c,d) ((a << 24) | (b << 16) | (c << 8) | d)
+#endif
+
+#ifndef DIRECTDRAW_VERSION
+// DIRECTDRAW_VERSION is defined in ddraw.h
+// These definitions are from the MSDN reference.
+
+enum DDSFlags {
+ DDSD_CAPS = 0x1,
+ DDSD_HEIGHT = 0x2,
+ DDSD_WIDTH = 0x4,
+ DDSD_PITCH = 0x8,
+ DDSD_PIXELFORMAT = 0x1000,
+ DDSD_MIPMAPCOUNT = 0x20000,
+ DDSD_LINEARSIZE = 0x80000,
+ DDSD_DEPTH = 0x800000
+};
+
+enum DDSPixelFormatFlags {
+ DDPF_ALPHAPIXELS = 0x1,
+ DDPF_ALPHA = 0x2,
+ DDPF_FOURCC = 0x4,
+ DDPF_RGB = 0x40,
+ DDPF_YUV = 0x200,
+ DDPF_LUMINANCE = 0x20000
+};
+
+enum DDSCaps {
+ DDSCAPS_COMPLEX = 0x8,
+ DDSCAPS_MIPMAP = 0x400000,
+ DDSCAPS_TEXTURE = 0x1000
+};
+
+#endif
+
+static const Evas_Colorspace cspaces_s3tc_dxt1_rgb[] = {
+ EVAS_COLORSPACE_RGB_S3TC_DXT1,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static const Evas_Colorspace cspaces_s3tc_dxt1_rgba[] = {
+ //EVAS_COLORSPACE_RGBA_S3TC_DXT1,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static const Evas_Colorspace cspaces_s3tc_dxt2[] = {
+ EVAS_COLORSPACE_RGBA_S3TC_DXT2,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static const Evas_Colorspace cspaces_s3tc_dxt3[] = {
+ //EVAS_COLORSPACE_RGBA_S3TC_DXT3,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static const Evas_Colorspace cspaces_s3tc_dxt4[] = {
+ EVAS_COLORSPACE_RGBA_S3TC_DXT4,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static const Evas_Colorspace cspaces_s3tc_dxt5[] = {
+ //EVAS_COLORSPACE_RGBA_S3TC_DXT5,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static void *
+evas_image_load_file_open_dds(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
+ Evas_Image_Load_Opts *opts EINA_UNUSED,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error)
+{
+ Evas_Loader_Internal *loader;
+
+ if (eina_file_size_get(f) <= DDS_HEADER_SIZE)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return NULL;
+ }
+
+ loader = calloc(1, sizeof (Evas_Loader_Internal));
+ if (!loader)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return NULL;
+ }
+
+
+ loader->f = eina_file_dup(f);
+ if (!loader->f)
+ {
+ free(loader);
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return NULL;
+ }
+
+ return loader;
+}
+
+static void
+evas_image_load_file_close_dds(void *loader_data)
+{
+ Evas_Loader_Internal *loader = loader_data;
+
+ eina_file_close(loader->f);
+ free(loader);
+}
+
+static inline unsigned int
+_dword_read(const char **m)
+{
+ unsigned int val = *((unsigned int *) *m);
+ *m += 4;
+ return val;
+}
+
+#define FAIL() do { /*fprintf(stderr, "DDS: ERROR at %s:%d\n", __FUNCTION__, __LINE__);*/ goto on_error; } while (0)
+
+static Eina_Bool
+evas_image_load_file_head_dds(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ static const unsigned int base_flags = /* 0x1007 */
+ DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+
+ Evas_Loader_Internal *loader = loader_data;
+ unsigned int flags, height, width, pitchOrLinearSize, caps, caps2;
+ Eina_Bool has_linearsize, has_mipmapcount;
+ const char *m;
+ char *map;
+
+ map = eina_file_map_all(loader->f, EINA_FILE_SEQUENTIAL);
+ if (!map)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ m = map;
+
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ if (strncmp(m, "DDS ", 4) != 0)
+ // TODO: Add support for DX10
+ goto on_error;
+ m += 4;
+
+ // Read DDS_HEADER
+ if (_dword_read(&m) != 124)
+ FAIL();
+
+ flags = _dword_read(&m);
+ if ((flags & base_flags) != (base_flags))
+ FAIL();
+
+ if ((flags & ~(DDSD_MIPMAPCOUNT | DDSD_LINEARSIZE)) != base_flags)
+ {
+ // TODO: A lot of modes are not supported.
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ FAIL();
+ }
+
+ has_linearsize = !!(flags & DDSD_LINEARSIZE);
+ if (!has_linearsize)
+ FAIL();
+
+ has_mipmapcount = !!(flags & DDSD_MIPMAPCOUNT);
+ (void) has_mipmapcount; // We don't really care about it.
+
+ height = _dword_read(&m);
+ width = _dword_read(&m);
+ pitchOrLinearSize = _dword_read(&m);
+ if (!width || !height)
+ FAIL();
+
+ // Skip depth & mipmap count + reserved[11]
+ m += 13 * sizeof(unsigned int);
+ // Entering DDS_PIXELFORMAT ddspf
+ if (_dword_read(&m) != 32)
+ FAIL();
+ loader->pf.flags = _dword_read(&m);
+ if (!(loader->pf.flags & DDPF_FOURCC))
+ FAIL(); // Unsupported (uncompressed formats may not have a FOURCC)
+ loader->pf.fourcc = _dword_read(&m);
+ loader->block_size = 16;
+ switch (loader->pf.fourcc)
+ {
+ case FOURCC('D', 'X', 'T', '1'):
+ loader->block_size = 8;
+ if ((loader->pf.flags & DDPF_ALPHAPIXELS) == 0)
+ {
+ prop->alpha = EINA_FALSE;
+ prop->cspaces = cspaces_s3tc_dxt1_rgb;
+ loader->format = EVAS_COLORSPACE_RGB_S3TC_DXT1;
+ }
+ else
+ {
+ prop->alpha = EINA_TRUE;
+ prop->cspaces = cspaces_s3tc_dxt1_rgba;
+ loader->format = EVAS_COLORSPACE_RGBA_S3TC_DXT1;
+ }
+ break;
+ case FOURCC('D', 'X', 'T', '2'):
+ loader->format = EVAS_COLORSPACE_RGBA_S3TC_DXT2;
+ prop->alpha = EINA_TRUE;
+ prop->cspaces = cspaces_s3tc_dxt2;
+ break;
+ case FOURCC('D', 'X', 'T', '3'):
+ loader->format = EVAS_COLORSPACE_RGBA_S3TC_DXT3;
+ prop->alpha = EINA_TRUE;
+ prop->cspaces = cspaces_s3tc_dxt5;
+ break;
+ case FOURCC('D', 'X', 'T', '4'):
+ loader->format = EVAS_COLORSPACE_RGBA_S3TC_DXT4;
+ prop->alpha = EINA_TRUE;
+ prop->cspaces = cspaces_s3tc_dxt4;
+ break;
+ case FOURCC('D', 'X', 'T', '5'):
+ loader->format = EVAS_COLORSPACE_RGBA_S3TC_DXT5;
+ prop->alpha = EINA_TRUE;
+ prop->cspaces = cspaces_s3tc_dxt5;
+ break;
+ case FOURCC('D', 'X', '1', '0'):
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ FAIL();
+ default:
+ // TODO: Implement decoding support for uncompressed formats
+ FAIL();
+ }
+ loader->pf.rgb_bitcount = _dword_read(&m);
+ loader->pf.r_mask = _dword_read(&m);
+ loader->pf.g_mask = _dword_read(&m);
+ loader->pf.b_mask = _dword_read(&m);
+ loader->pf.a_mask = _dword_read(&m);
+ caps = _dword_read(&m);
+ if ((caps & DDSCAPS_TEXTURE) == 0)
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ FAIL();
+ }
+ caps2 = _dword_read(&m);
+ if (caps2 != 0)
+ {
+ // Cube maps not supported
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ FAIL();
+ }
+ // Since the rest is unused, just ignore it.
+
+ loader->stride = ((width + 3) >> 2) * loader->block_size;
+ loader->data_size = loader->stride * ((height + 3) >> 2);
+ if (loader->data_size != pitchOrLinearSize)
+ FAIL(); // Invalid size!
+
+ // Check file size
+ if (eina_file_size_get(loader->f) < (DDS_HEADER_SIZE + loader->data_size))
+ FAIL();
+
+ prop->h = height;
+ prop->w = width;
+ prop->borders.l = 4;
+ prop->borders.t = 4;
+ prop->borders.r = 4 - (prop->w & 0x3);
+ prop->borders.b = 4 - (prop->h & 0x3);
+ *error = EVAS_LOAD_ERROR_NONE;
+
+on_error:
+ eina_file_map_free(loader->f, map);
+ return (*error == EVAS_LOAD_ERROR_NONE);
+}
+
+static Eina_Bool
+_dds_data_load(Evas_Loader_Internal *loader, Evas_Image_Property *prop,
+ unsigned char *map, void *pixels, int *error)
+{
+ const unsigned char *src;
+ int bsize = 16, srcstride, dststride, w, h;
+ unsigned char *dst;
+
+ void (* flip) (unsigned char *, const unsigned char *, int) = NULL;
+
+ *error = EVAS_LOAD_ERROR_GENERIC;
+
+ if (loader->format != prop->cspace)
+ FAIL();
+
+ switch (loader->format)
+ {
+ case EVAS_COLORSPACE_RGB_S3TC_DXT1:
+ case EVAS_COLORSPACE_RGBA_S3TC_DXT1:
+ flip = s3tc_encode_dxt1_flip;
+ bsize = 8;
+ break;
+ case EVAS_COLORSPACE_RGBA_S3TC_DXT2:
+ flip = s3tc_encode_dxt2_rgba_flip;
+ bsize = 16;
+ break;
+ case EVAS_COLORSPACE_RGBA_S3TC_DXT3:
+ flip = s3tc_encode_dxt3_rgba_flip;
+ bsize = 16;
+ break;
+ case EVAS_COLORSPACE_RGBA_S3TC_DXT4:
+ flip = s3tc_encode_dxt4_rgba_flip;
+ bsize = 16;
+ break;
+ case EVAS_COLORSPACE_RGBA_S3TC_DXT5:
+ flip = s3tc_encode_dxt5_rgba_flip;
+ bsize = 16;
+ break;
+ default: FAIL();
+ }
+
+ src = map + DDS_HEADER_SIZE;
+ w = prop->w;
+ h = prop->h;
+ srcstride = ((prop->w + 3) / 4) * bsize;
+ dststride = ((prop->w + prop->borders.l + prop->borders.r) / 4) * bsize;
+
+ // asserts
+ EINA_SAFETY_ON_FALSE_GOTO(prop->borders.l == 4, on_error);
+ EINA_SAFETY_ON_FALSE_GOTO(prop->borders.t == 4, on_error);
+ EINA_SAFETY_ON_FALSE_GOTO(prop->borders.r == (4 - (w & 0x3)), on_error);
+ EINA_SAFETY_ON_FALSE_GOTO(prop->borders.b == (4 - (h & 0x3)), on_error);
+
+ if (eina_file_size_get(loader->f) <
+ (size_t) (DDS_HEADER_SIZE + srcstride * h / 4))
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error;
+ }
+
+ // First, copy the real data
+ for (int y = 0; y < h; y += 4)
+ {
+ dst = ((unsigned char *) pixels) + ((y / 4) + 1) * dststride + bsize;
+ memcpy(dst, src, srcstride);
+ src += srcstride;
+ }
+ // Top
+ for (int x = 0; x < w; x += 4)
+ {
+ src = map + DDS_HEADER_SIZE + (x / 4) * bsize;
+ dst = ((unsigned char *) pixels) + ((x / 4) + 1) * bsize;
+ flip(dst, src, EINA_TRUE);
+ }
+ // Left
+ for (int y = 0; y < h; y += 4)
+ {
+ src = map + DDS_HEADER_SIZE + (y / 4) * srcstride;
+ dst = ((unsigned char *) pixels) + ((y / 4) + 1) * dststride;
+ flip(dst, src, EINA_FALSE);
+ }
+ // Top-left
+ dst = pixels;
+ src = dst + bsize;
+ flip(dst, src, EINA_FALSE);
+ // Right
+ if ((prop->w & 0x3) == 0)
+ {
+ for (int y = 0; y < h; y += 4)
+ {
+ src = map + DDS_HEADER_SIZE + ((y / 4) + 1) * srcstride - bsize;
+ dst = ((unsigned char *) pixels) + ((y / 4) + 2) * dststride - bsize;
+ flip(dst, src, EINA_FALSE);
+ }
+ // Top-right
+ dst = ((unsigned char *) pixels) + dststride - bsize;
+ src = dst - bsize;
+ flip(dst, src, EINA_FALSE);
+ }
+ // Bottom
+ if ((prop->h & 0x3) == 0)
+ {
+ for (int x = 0; x < w; x += 4)
+ {
+ src = map + DDS_HEADER_SIZE + ((h / 4) - 1) * srcstride + (x / 4) * bsize;
+ dst = ((unsigned char *) pixels) + ((h / 4) + 1) * dststride + ((x / 4) + 1) * bsize;
+ flip(dst, src, EINA_TRUE);
+ }
+ // Bottom-left
+ dst = ((unsigned char *) pixels) + ((h / 4) + 1) * dststride;
+ src = dst + bsize;
+ flip(dst, src, EINA_FALSE);
+ if ((prop->w & 0x3) == 0)
+ {
+ // Bottom-right
+ dst = ((unsigned char *) pixels) + ((h / 4) + 2) * dststride - bsize;
+ src = dst - bsize;
+ flip(dst, src, EINA_FALSE);
+ }
+ }
+
+ *error = EVAS_LOAD_ERROR_NONE;
+
+on_error:
+ eina_file_map_free(loader->f, (void *) map);
+ return (*error == EVAS_LOAD_ERROR_NONE);
+}
+
+Eina_Bool
+evas_image_load_file_data_dds(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ void (*func) (unsigned int *bgra, const unsigned char *s3tc) = NULL;
+ Evas_Loader_Internal *loader = loader_data;
+ unsigned int *pix = pixels;
+ unsigned char *map = NULL;
+ const unsigned char *src;
+
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+ map = eina_file_map_all(loader->f, EINA_FILE_WILLNEED);
+ if (!map)
+ return EINA_FALSE;
+
+ src = map + DDS_HEADER_SIZE;
+ if (eina_file_size_get(loader->f) < (DDS_HEADER_SIZE + loader->data_size))
+ FAIL();
+
+ if (prop->cspace != EVAS_COLORSPACE_ARGB8888)
+ return _dds_data_load(loader, prop, map, pixels, error);
+
+ // Decode to BGRA
+ switch (loader->format)
+ {
+ case EVAS_COLORSPACE_RGB_S3TC_DXT1:
+ func = s3tc_decode_dxt1_rgb;
+ prop->premul = EINA_FALSE;
+ break;
+ case EVAS_COLORSPACE_RGBA_S3TC_DXT1:
+ func = s3tc_decode_dxt1_rgba;
+ prop->premul = EINA_FALSE;
+ break;
+ case EVAS_COLORSPACE_RGBA_S3TC_DXT2:
+ func = s3tc_decode_dxt2_rgba;
+ prop->premul = EINA_FALSE;
+ break;
+ case EVAS_COLORSPACE_RGBA_S3TC_DXT3:
+ func = s3tc_decode_dxt3_rgba;
+ prop->premul = EINA_TRUE;
+ break;
+ case EVAS_COLORSPACE_RGBA_S3TC_DXT4:
+ func = s3tc_decode_dxt4_rgba;
+ prop->premul = EINA_FALSE;
+ break;
+ case EVAS_COLORSPACE_RGBA_S3TC_DXT5:
+ func = s3tc_decode_dxt5_rgba;
+ prop->premul = EINA_TRUE;
+ break;
+ default:
+ FAIL();
+ }
+ if (!func) FAIL();
+
+ for (unsigned int y = 0; y < prop->h; y += 4)
+ {
+ int blockh = prop->h - y;
+ if (blockh > 4) blockh = 4;
+
+ for (unsigned int x = 0; x < prop->w; x += 4)
+ {
+ unsigned int bgra[16];
+ int k, j;
+
+ func(bgra, src);
+ src += loader->block_size;
+
+ j = prop->w - x;
+ if (j > 4) j = 4;
+ for (k = 0; k < blockh; k++)
+ {
+ memcpy(pix + (((y + k) * prop->w) + x), bgra + (k * 4),
+ j * sizeof (unsigned int));
+ };
+ }
+ }
+
+ *error = EVAS_LOAD_ERROR_NONE;
+
+on_error:
+ eina_file_map_free(loader->f, (void *) map);
+ return (*error == EVAS_LOAD_ERROR_NONE);
+}
+
+Evas_Image_Load_Func evas_image_load_dds_func =
+{
+ evas_image_load_file_open_dds,
+ evas_image_load_file_close_dds,
+ evas_image_load_file_head_dds,
+ evas_image_load_file_data_dds,
+ NULL,
+ EINA_TRUE,
+ EINA_FALSE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ em->functions = (void *)(&evas_image_load_dds_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "dds",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, dds);
+
+#ifndef EVAS_STATIC_BUILD_DDS
+EVAS_EINA_MODULE_DEFINE(image_loader, dds);
+#endif
diff --git a/src/modules/evas/image_loaders/dds/s3tc.h b/src/modules/evas/image_loaders/dds/s3tc.h
new file mode 100644
index 0000000000..3bc965db48
--- /dev/null
+++ b/src/modules/evas/image_loaders/dds/s3tc.h
@@ -0,0 +1,17 @@
+#ifndef EFL_S3TC_H
+#define EFL_S3TC_H
+
+void s3tc_decode_dxt1_rgb(unsigned int *bgra, const unsigned char *s3tc);
+void s3tc_decode_dxt1_rgba(unsigned int *bgra, const unsigned char *s3tc);
+void s3tc_decode_dxt2_rgba(unsigned int *bgra, const unsigned char *s3tc);
+void s3tc_decode_dxt3_rgba(unsigned int *bgra, const unsigned char *s3tc);
+void s3tc_decode_dxt4_rgba(unsigned int *bgra, const unsigned char *s3tc);
+void s3tc_decode_dxt5_rgba(unsigned int *bgra, const unsigned char *s3tc);
+
+void s3tc_encode_dxt1_flip(unsigned char *dest, const unsigned char *orig, int vflip);
+void s3tc_encode_dxt2_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip);
+void s3tc_encode_dxt3_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip);
+void s3tc_encode_dxt4_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip);
+void s3tc_encode_dxt5_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip);
+
+#endif // EFL_S3TC_H
diff --git a/src/modules/evas/image_loaders/dds/s3tc_decoder.c b/src/modules/evas/image_loaders/dds/s3tc_decoder.c
new file mode 100644
index 0000000000..f934fbd4a3
--- /dev/null
+++ b/src/modules/evas/image_loaders/dds/s3tc_decoder.c
@@ -0,0 +1,219 @@
+#include "s3tc.h"
+
+// For INTERP_256 and INTERP_RGB_256
+#include "evas_common_private.h"
+#include "evas_blend_ops.h"
+
+// From evas_convert_colorspace.c
+#define CONVERT_RGB_565_TO_RGB_888(s) \
+ (((((s) << 3) & 0xf8) | (((s) >> 2) & 0x7)) | \
+ ((((s) << 5) & 0xfc00) | (((s) >> 1) & 0x300)) | \
+ ((((s) << 8) & 0xf80000) | (((s) << 3) & 0x70000)))
+
+#define ALPHA4(a) (((a) << 4) | (a))
+
+static void
+_decode_dxt1_rgb(unsigned int *bgra, const unsigned char *s3tc,
+ unsigned int amask, Eina_Bool dxt1, Eina_Bool alpha)
+{
+ unsigned short color0, color1;
+ unsigned int colors[4];
+ unsigned int bits;
+
+ color0 = s3tc[0] | (s3tc[1] << 8);
+ color1 = s3tc[2] | (s3tc[3] << 8);
+
+ colors[0] = amask | CONVERT_RGB_565_TO_RGB_888(color0);
+ colors[1] = amask | CONVERT_RGB_565_TO_RGB_888(color1);
+ if (!dxt1 || (color0 > color1))
+ {
+ // This is what's not supported by S2TC.
+ colors[2] = amask | INTERP_RGB_256((2*256)/3, colors[0], colors[1]);
+ colors[3] = amask | INTERP_RGB_256((1*256)/3, colors[0], colors[1]);
+ }
+ else
+ {
+ colors[2] = amask | INTERP_RGB_256(128, colors[0], colors[1]);
+ colors[3] = (alpha ? 0x00000000 : amask);
+ }
+
+ bits = s3tc[4] + ((s3tc[5] + ((s3tc[6] + (s3tc[7] << 8)) << 8)) << 8);
+ for (int j = 0; j < 4; j++)
+ for (int i = 0; i < 4; i++)
+ {
+ int idx = bits & 0x3;
+ bgra[(j * 4) + i] = colors[idx];
+ bits >>= 2;
+ }
+}
+
+static void
+_decode_alpha4(unsigned int *bgra, const unsigned char *s3tc)
+{
+ for (int k = 0; k < 16; k += 2)
+ {
+ unsigned int a0 = ALPHA4((*s3tc) & 0x0F);
+ unsigned int a1 = ALPHA4(((*s3tc) & 0xF0) >> 4);
+ *bgra++ |= (a0 << 24);
+ *bgra++ |= (a1 << 24);
+ s3tc++;
+ }
+}
+
+static void
+_decode_dxt_alpha(unsigned int *bgra, const unsigned char *s3tc)
+{
+ unsigned char a0 = s3tc[0];
+ unsigned char a1 = s3tc[1];
+ unsigned long long bits = 0ull;
+ unsigned char alpha[8];
+
+ for (int k = 5; k >= 0; k--)
+ bits = (bits << 8) | s3tc[k + 2];
+
+ alpha[0] = a0;
+ alpha[1] = a1;
+
+ if (a0 > a1)
+ {
+ for (int k = 0; k < 6; k++)
+ alpha[2 + k] = ((6 - k) * a0 + (k + 1) * a1) / 7;
+ }
+ else
+ {
+ for (int k = 0; k < 4; k++)
+ alpha[2 + k] = ((4 - k) * a0 + (k + 1) * a1) / 5;
+ alpha[6] = 0;
+ alpha[7] = 255;
+ }
+
+ for (int k = 0; k < 16; k++)
+ {
+ int index = (int) (bits & 0x7ull);
+ *bgra++ |= (alpha[index] << 24);
+ bits >>= 3;
+ }
+}
+
+void
+s3tc_decode_dxt1_rgb(unsigned int *bgra, const unsigned char *s3tc)
+{
+ _decode_dxt1_rgb(bgra, s3tc, 0xFF000000, EINA_TRUE, EINA_FALSE);
+}
+
+void
+s3tc_decode_dxt1_rgba(unsigned int *bgra, const unsigned char *s3tc)
+{
+ _decode_dxt1_rgb(bgra, s3tc, 0xFF000000, EINA_TRUE, EINA_TRUE);
+}
+
+void
+s3tc_decode_dxt2_rgba(unsigned int *bgra, const unsigned char *s3tc)
+{
+ _decode_dxt1_rgb(bgra, s3tc + 8, 0x0, EINA_FALSE, EINA_FALSE);
+ _decode_alpha4(bgra, s3tc);
+}
+
+void
+s3tc_decode_dxt3_rgba(unsigned int *bgra, const unsigned char *s3tc)
+{
+ _decode_dxt1_rgb(bgra, s3tc + 8, 0x0, EINA_FALSE, EINA_FALSE);
+ _decode_alpha4(bgra, s3tc);
+}
+
+void
+s3tc_decode_dxt4_rgba(unsigned int *bgra, const unsigned char *s3tc)
+{
+ _decode_dxt1_rgb(bgra, s3tc + 8, 0x0, EINA_FALSE, EINA_FALSE);
+ _decode_dxt_alpha(bgra, s3tc);
+}
+
+void
+s3tc_decode_dxt5_rgba(unsigned int *bgra, const unsigned char *s3tc)
+{
+ _decode_dxt1_rgb(bgra, s3tc + 8, 0x0, EINA_FALSE, EINA_FALSE);
+ _decode_dxt_alpha(bgra, s3tc);
+}
+
+/* Fast re-encode functions to flip S3TC blocks */
+
+static inline unsigned char
+_byte_2222_flip(unsigned char src)
+{
+ return ((src & (0x3 << 6)) >> 6) |
+ ((src & (0x3 << 4)) >> 2) |
+ ((src & (0x3 << 2)) << 2) |
+ ((src & 0x3) << 6);
+}
+
+static inline unsigned char
+_byte_44_flip(unsigned char src)
+{
+ return ((src & 0xF0) >> 4) | ((src & 0x0F) << 4);
+}
+
+void
+s3tc_encode_dxt1_flip(unsigned char *dest, const unsigned char *orig, int vflip)
+{
+ dest[0] = orig[0];
+ dest[1] = orig[1];
+ dest[2] = orig[2];
+ dest[3] = orig[3];
+
+ if (vflip)
+ {
+ dest[4] = orig[7];
+ dest[5] = orig[6];
+ dest[6] = orig[5];
+ dest[7] = orig[4];
+ }
+ else
+ {
+ dest[4] = _byte_2222_flip(orig[4]);
+ dest[5] = _byte_2222_flip(orig[5]);
+ dest[6] = _byte_2222_flip(orig[6]);
+ dest[7] = _byte_2222_flip(orig[7]);
+ }
+}
+
+void
+s3tc_encode_dxt2_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip)
+{
+ if (vflip)
+ {
+ dest[0] = orig[6];
+ dest[1] = orig[7];
+ dest[2] = orig[4];
+ dest[3] = orig[5];
+ dest[4] = orig[2];
+ dest[5] = orig[3];
+ dest[6] = orig[0];
+ dest[7] = orig[1];
+ }
+ else
+ {
+ for (int k = 0; k < 8; k += 2)
+ {
+ dest[0+k] = _byte_44_flip(orig[1+k]);
+ dest[1+k] = _byte_44_flip(orig[0+k]);
+ }
+ }
+ s3tc_encode_dxt1_flip(dest + 8, orig + 8, vflip);
+}
+
+void
+s3tc_encode_dxt3_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip)
+{
+ s3tc_encode_dxt2_rgba_flip(dest, orig, vflip);
+}
+
+void s3tc_encode_dxt4_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip)
+{
+ s3tc_encode_dxt1_flip(dest, orig, vflip);
+ s3tc_encode_dxt1_flip(dest + 8, orig + 8, vflip);
+}
+
+void s3tc_encode_dxt5_rgba_flip(unsigned char *dest, const unsigned char *orig, int vflip)
+{
+ s3tc_encode_dxt4_rgba_flip(dest, orig, vflip);
+}
diff --git a/src/modules/evas/image_loaders/eet/evas_image_load_eet.c b/src/modules/evas/image_loaders/eet/evas_image_load_eet.c
new file mode 100644
index 0000000000..3c8e49bcb3
--- /dev/null
+++ b/src/modules/evas/image_loaders/eet/evas_image_load_eet.c
@@ -0,0 +1,245 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h" /* so that EAPI in Eet.h is correctly defined */
+#endif
+
+#include <Eet.h>
+
+#include "evas_common_private.h"
+#include "evas_private.h"
+
+typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
+struct _Evas_Loader_Internal
+{
+ Eet_File *ef;
+ const char *key;
+};
+
+static void *
+evas_image_load_file_open_eet(Eina_File *f, Eina_Stringshare *key,
+ Evas_Image_Load_Opts *opts EINA_UNUSED,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error)
+{
+ Evas_Loader_Internal *loader;
+
+ if (!key)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return NULL;
+ }
+
+ loader = calloc(1, sizeof (Evas_Loader_Internal));
+ if (!loader)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return NULL;
+ }
+
+ loader->ef = eet_mmap(f);
+ if (!loader->ef)
+ {
+ free(loader);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return NULL;
+ }
+
+ loader->key = eina_stringshare_ref(key);
+ return loader;
+}
+
+static void
+evas_image_load_file_close_eet(void *loader_data)
+{
+ Evas_Loader_Internal *loader = loader_data;
+
+ eet_close(loader->ef);
+ eina_stringshare_del(loader->key);
+ free(loader);
+}
+
+static inline Eina_Bool
+_evas_image_load_return_error(int err, int *error)
+{
+ *error = err;
+ return EINA_FALSE;
+}
+
+static const Evas_Colorspace cspaces_etc1[2] = {
+ EVAS_COLORSPACE_ETC1,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static const Evas_Colorspace cspaces_etc1_alpha[] = {
+ EVAS_COLORSPACE_ETC1_ALPHA,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static const Evas_Colorspace cspaces_etc2_rgb[] = {
+ EVAS_COLORSPACE_RGB8_ETC2,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static const Evas_Colorspace cspaces_etc2_rgba[] = {
+ EVAS_COLORSPACE_RGBA8_ETC2_EAC,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static Eina_Bool
+evas_image_load_file_head_eet(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+ int a, compression, quality;
+ Eet_Image_Encoding lossy;
+ const Eet_Colorspace *cspaces = NULL;
+ int ok;
+
+ ok = eet_data_image_header_read(loader->ef, loader->key,
+ &prop->w, &prop->h, &a, &compression, &quality, &lossy);
+ if (!ok)
+ return _evas_image_load_return_error(EVAS_LOAD_ERROR_DOES_NOT_EXIST, error);
+ if (IMG_TOO_BIG(prop->w, prop->h))
+ return _evas_image_load_return_error(EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED, error);
+
+ if (eet_data_image_colorspace_get(loader->ef, loader->key, NULL, &cspaces))
+ {
+ unsigned int i;
+
+ if (cspaces != NULL)
+ {
+ for (i = 0; cspaces[i] != EET_COLORSPACE_ARGB8888; i++)
+ {
+ if (cspaces[i] == EET_COLORSPACE_ETC1)
+ {
+ prop->cspaces = cspaces_etc1;
+ break;
+ }
+ else if (cspaces[i] == EET_COLORSPACE_ETC1_ALPHA)
+ {
+ prop->cspaces = cspaces_etc1_alpha;
+ break;
+ }
+ else if (cspaces[i] == EET_COLORSPACE_RGB8_ETC2)
+ {
+ prop->cspaces = cspaces_etc2_rgb;
+ break;
+ }
+ else if (cspaces[i] == EET_COLORSPACE_RGBA8_ETC2_EAC)
+ {
+ prop->cspaces = cspaces_etc2_rgba;
+ break;
+ }
+ }
+ }
+ }
+
+ prop->alpha = !!a;
+ *error = EVAS_LOAD_ERROR_NONE;
+
+ return EINA_TRUE;
+}
+
+Eina_Bool
+evas_image_load_file_data_eet(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+ int alpha, compression, quality, ok;
+ Eet_Image_Encoding lossy;
+ DATA32 *body, *p, *end;
+ DATA32 nas = 0;
+ Eet_Colorspace cspace;
+
+ switch (prop->cspace)
+ {
+ case EVAS_COLORSPACE_ETC1: cspace = EET_COLORSPACE_ETC1; break;
+ case EVAS_COLORSPACE_ETC1_ALPHA: cspace = EET_COLORSPACE_ETC1_ALPHA; break;
+ case EVAS_COLORSPACE_RGB8_ETC2: cspace = EET_COLORSPACE_RGB8_ETC2; break;
+ case EVAS_COLORSPACE_RGBA8_ETC2_EAC: cspace = EET_COLORSPACE_RGBA8_ETC2_EAC; break;
+ case EVAS_COLORSPACE_ARGB8888: cspace = EET_COLORSPACE_ARGB8888; break;
+ default:
+ return _evas_image_load_return_error(EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED, error);
+ }
+
+ ok = eet_data_image_read_to_cspace_surface_cipher(loader->ef, loader->key, NULL, 0, 0,
+ pixels, prop->w, prop->h, prop->w * 4,
+ cspace,
+ &alpha, &compression, &quality, &lossy);
+ if (!ok)
+ return _evas_image_load_return_error(EVAS_LOAD_ERROR_GENERIC, error);
+
+ if (alpha)
+ {
+ prop->alpha = 1;
+ body = pixels;
+
+ end = body + (prop->w * prop->h);
+ for (p = body; p < end; p++)
+ {
+ DATA32 r, g, b, a;
+
+ a = A_VAL(p);
+ r = R_VAL(p);
+ g = G_VAL(p);
+ b = B_VAL(p);
+ if ((a == 0) || (a == 255)) nas++;
+ if (r > a) r = a;
+ if (g > a) g = a;
+ if (b > a) b = a;
+ *p = ARGB_JOIN(a, r, g, b);
+ }
+ if ((ALPHA_SPARSE_INV_FRACTION * nas) >= (prop->w * prop->h))
+ prop->alpha_sparse = 1;
+ }
+// result is already premultiplied now if u compile with edje
+// evas_common_image_premul(im);
+ *error = EVAS_LOAD_ERROR_NONE;
+
+ return EINA_TRUE;
+}
+
+Evas_Image_Load_Func evas_image_load_eet_func =
+{
+ evas_image_load_file_open_eet,
+ evas_image_load_file_close_eet,
+ evas_image_load_file_head_eet,
+ evas_image_load_file_data_eet,
+ NULL,
+ EINA_TRUE,
+ EINA_FALSE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ eet_init();
+ em->functions = (void *)(&evas_image_load_eet_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+ eet_shutdown();
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "eet",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, eet);
+
+#ifndef EVAS_STATIC_BUILD_EET
+EVAS_EINA_MODULE_DEFINE(image_loader, eet);
+#endif
diff --git a/src/modules/evas/image_loaders/generic/evas_image_load_generic.c b/src/modules/evas/image_loaders/generic/evas_image_load_generic.c
new file mode 100644
index 0000000000..78488d1036
--- /dev/null
+++ b/src/modules/evas/image_loaders/generic/evas_image_load_generic.c
@@ -0,0 +1,479 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_common_private.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>
+
+typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
+struct _Evas_Loader_Internal
+{
+ Eina_File *f;
+ const char *key;
+ Evas_Image_Load_Opts *opts;
+};
+
+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++)
+ {
+ // FIXME: escape tab, newline linefeed and friends
+ 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
+_load(Eina_File *ef, const char *key,
+ Evas_Image_Property *prop,
+ Evas_Image_Load_Opts *opts,
+ void *pixels,
+ int *error, Eina_Bool get_data)
+{
+ 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 *loader = "/evas/utils/evas_image_loader";
+ char *img_loader = NULL;
+ const char *libdir;
+ // 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 = NULL;
+
+ libdir = _evas_module_libdir_get();
+ cmd_len = strlen(libdir);
+ cmd_len += strlen(loader);
+ img_loader = alloca(cmd_len + 1);
+ strcpy(img_loader, libdir);
+ strcat(img_loader, loader);
+
+ // params excluding file, key and loadopts
+ cmd_len += 1024;
+ cmd_len += strlen(eina_file_filename_get(ef)) * 2;
+ if (key) cmd_len += strlen(key) * 2;
+ cmd = alloca(cmd_len + 1);
+
+ len = strlen(eina_file_filename_get(ef));
+ if (len < 1)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+ end = eina_file_filename_get(ef) + len;
+ for (p = end - 1; p >= eina_file_filename_get(ef); 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)))
+ {
+ strncpy(&(decoders[decoders_num][0]), img_loader, 127);
+ decoders[decoders_num][127] = 0;
+ dotcat(&(decoders[decoders_num][0]), dot2);
+ decoders_num++;
+ }
+ // single extn not too long
+ if (((end - dot1) <= 5) && (!illegal_char(dot1)))
+ {
+ strncpy(&(decoders[decoders_num][0]), img_loader, 127);
+ decoders[decoders_num][127] = 0;
+ dotcat(&(decoders[decoders_num][0]), dot1);
+ decoders_num++;
+ }
+ strncpy(decoders[decoders_num], img_loader, 127);
+ decoders[decoders_num][127] = 0;
+ decoders_num++;
+ }
+ else if (dot1)
+ {
+ // single extn not too long
+ if (((end - dot1) <= 5) && (!illegal_char(dot1)))
+ {
+ strncpy(&(decoders[decoders_num][0]), img_loader, 127);
+ decoders[decoders_num][127] = 0;
+ dotcat(&(decoders[decoders_num][0]), dot1);
+ decoders_num++;
+ }
+ strncpy(decoders[decoders_num], img_loader, 127);
+ decoders[decoders_num][127] = 0;
+ decoders_num++;
+ }
+ else
+ {
+ strncpy(decoders[decoders_num], img_loader, 127);
+ decoders[decoders_num][127] = 0;
+ 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...
+ if (access(decoders[try_count], X_OK)) continue;
+
+ strcpy(cmd, decoders[try_count]);
+ strcat(cmd, " ");
+ // filename first arg
+ len = strlen(cmd);
+ escape_copy(eina_file_filename_get(ef), cmd + len);
+ if (!get_data)
+ {
+ strcat(cmd, " -head ");
+ }
+ if (key)
+ {
+ strcat(cmd, " -key ");
+ len = strlen(cmd);
+ escape_copy(key, cmd + len);
+ }
+ if (opts->scale_down_by > 1)
+ {
+ strcat(cmd, " -opt-scale-down-by ");
+ snprintf(buf, sizeof(buf), "%i", opts->scale_down_by);
+ strcat(cmd, buf);
+ }
+ if (opts->dpi > 0.0)
+ {
+ strcat(cmd, " -opt-dpi ");
+ snprintf(buf, sizeof(buf), "%i", (int)(opts->dpi * 1000.0));
+ strcat(cmd, buf);
+ }
+ if ((opts->w > 0) &&
+ (opts->h > 0))
+ {
+ strcat(cmd, " -opt-size ");
+ snprintf(buf, sizeof(buf), "%i %i", opts->w, 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;
+ }
+ else if (!strncmp(buf, "done", 4))
+ {
+ read_data = 2;
+ 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 (!get_data)
+ {
+ if (alpha) prop->alpha = 1;
+ prop->w = w;
+ prop->h = h;
+ }
+ else
+ {
+ if ((int)prop->w != w ||
+ (int)prop->h != h)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto on_error;
+ }
+ body = pixels;
+
+ 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;
+
+ eina_mmap_safety_enabled_set(EINA_TRUE);
+
+ // 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 void *
+evas_image_load_file_open_generic(Eina_File *f, Eina_Stringshare *key,
+ Evas_Image_Load_Opts *opts,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error)
+{
+ Evas_Loader_Internal *loader;
+
+ loader = calloc(1, sizeof (Evas_Loader_Internal));
+ if (!loader)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return NULL;
+ }
+
+ loader->f = f;
+ loader->key = eina_stringshare_ref(key);
+ loader->opts = opts;
+ return loader;
+}
+
+static void
+evas_image_load_file_close_generic(void *loader_data)
+{
+ Evas_Loader_Internal *loader = loader_data;
+
+ eina_stringshare_del(loader->key);
+ free(loader);
+}
+
+static Eina_Bool
+evas_image_load_file_head_generic(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+
+ return _load(loader->f, loader->key, prop, loader->opts, NULL, error, EINA_FALSE);
+}
+
+static Eina_Bool
+evas_image_load_file_data_generic(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+
+ return _load(loader->f, loader->key, prop, loader->opts, pixels, error, EINA_TRUE);
+}
+
+Evas_Image_Load_Func evas_image_load_generic_func =
+{
+ evas_image_load_file_open_generic,
+ evas_image_load_file_close_generic,
+ evas_image_load_file_head_generic,
+ evas_image_load_file_data_generic,
+ NULL,
+ EINA_TRUE,
+ EINA_FALSE
+};
+
+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 EINA_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
diff --git a/src/modules/evas/image_loaders/gif/evas_image_load_gif.c b/src/modules/evas/image_loaders/gif/evas_image_load_gif.c
new file mode 100644
index 0000000000..acdf5ab8e1
--- /dev/null
+++ b/src/modules/evas/image_loaders/gif/evas_image_load_gif.c
@@ -0,0 +1,914 @@
+#include "evas_common_private.h"
+#include "evas_private.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <gif_lib.h>
+
+typedef struct _Frame_Info Frame_Info;
+typedef struct _Loader_Info Loader_Info;
+typedef struct _File_Info File_Info;
+
+struct _File_Info
+{
+ unsigned char *map;
+ int pos, len; // yes - gif uses ints for file sizes.
+};
+
+struct _Loader_Info
+{
+ Eina_File *f;
+ Evas_Image_Load_Opts *opts;
+ Evas_Image_Animated *animated;
+ GifFileType *gif;
+ int imgnum;
+ File_Info fi;
+};
+
+struct _Frame_Info
+{
+ int x, y, w, h;
+ unsigned short delay; // delay time in 1/100ths of a sec
+ short transparent : 10; // -1 == not, anything else == index
+ short dispose : 6; // 0, 1, 2, 3 (others invalid)
+ short interlace : 1; // interlaced or not
+};
+
+#ifndef MIN
+# define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+#define LOADERR(x) \
+do { \
+ *error = (x); \
+ goto on_error; \
+} while (0)
+#define PIX(_x, _y) rows[yin + _y][xin + _x]
+#define CMAP(_v) cmap->Colors[_v]
+#define PIXLK(_p) ARGB_JOIN(0xff, CMAP(_p).Red, CMAP(_p).Green, CMAP(_p).Blue)
+
+// utility funcs...
+
+// brute force find frame index - gifs are normally saml so ok for now
+static Image_Entry_Frame *
+_find_frame(Evas_Image_Animated *animated, int index)
+{
+ Eina_List *l;
+ Image_Entry_Frame *frame;
+
+ if (!animated->frames) return NULL;
+ EINA_LIST_FOREACH(animated->frames, l, frame)
+ {
+ if (frame->index == index) return frame;
+ }
+ return NULL;
+}
+
+// fill in am image with a specific rgba color value
+static void
+_fill_image(DATA32 *data, int rowpix, DATA32 val, int x, int y, int w, int h)
+{
+ int xx, yy;
+ DATA32 *p;
+
+ for (yy = 0; yy < h; yy++)
+ {
+ p = data + ((y + yy) * rowpix) + x;
+ for (xx = 0; xx < w; xx++)
+ {
+ *p = val;
+ p++;
+ }
+ }
+}
+
+// fix coords and work out an x and y inset in orig data if out of image bounds
+static void
+_clip_coords(int imw, int imh, int *xin, int *yin,
+ int x0, int y0, int w0, int h0,
+ int *x, int *y, int *w, int *h)
+{
+ if (x0 < 0)
+ {
+ w0 += x0;
+ *xin = -x0;
+ x0 = 0;
+ }
+ if ((x0 + w0) > imw) w0 = imw - x0;
+ if (y0 < 0)
+ {
+ h0 += y0;
+ *yin = -y0;
+ y0 = 0;
+ }
+ if ((y0 + h0) > imh) h0 = imh - y0;
+ *x = x0;
+ *y = y0;
+ *w = w0;
+ *h = h0;
+}
+
+// file a rgba data pixle blob with a frame color (bg or trans) depending...
+static void
+_fill_frame(DATA32 *data, int rowpix, GifFileType *gif, Frame_Info *finfo,
+ int x, int y, int w, int h)
+{
+ // solid color fill for pre frame region
+ if (finfo->transparent < 0)
+ {
+ ColorMapObject *cmap;
+ int bg;
+
+ // work out color to use from cmap
+ if (gif->Image.ColorMap) cmap = gif->Image.ColorMap;
+ else cmap = gif->SColorMap;
+ bg = gif->SBackGroundColor;
+ // and do the fill
+ _fill_image
+ (data, rowpix,
+ ARGB_JOIN(0xff, CMAP(bg).Red, CMAP(bg).Green, CMAP(bg).Blue),
+ x, y, w, h);
+ }
+ // fill in region with 0 (transparent)
+ else
+ _fill_image(data, rowpix, 0, x, y, w, h);
+}
+
+// store common fields from gif file info into frame info
+static void
+_store_frame_info(GifFileType *gif, Frame_Info *finfo)
+{
+ finfo->x = gif->Image.Left;
+ finfo->y = gif->Image.Top;
+ finfo->w = gif->Image.Width;
+ finfo->h = gif->Image.Height;
+ finfo->interlace = gif->Image.Interlace;
+}
+
+// check if image fills "screen space" and if so, if it is transparent
+// at all then the image could be transparent - OR if image doesnt fill,
+// then it could be trasnparent (full coverage of screen). some gifs will
+// be recognized as solid here for faster rendering, but not all.
+static void
+_check_transparency(Eina_Bool *full, Frame_Info *finfo, int w, int h)
+{
+ if ((finfo->x == 0) && (finfo->y == 0) &&
+ (finfo->w == w) && (finfo->h == h))
+ {
+ if (finfo->transparent >= 0) *full = EINA_FALSE;
+ }
+ else *full = EINA_FALSE;
+}
+
+// allocate frame and frame info and append to list and store fields
+static Frame_Info *
+_new_frame(Evas_Image_Animated *animated,
+ int transparent, int dispose, int delay,
+ int index)
+{
+ Image_Entry_Frame *frame;
+ Frame_Info *finfo;
+
+ // allocate frame and frame info data (MUSt be separate)
+ frame = calloc(1, sizeof(Image_Entry_Frame));
+ if (!frame) return NULL;
+ finfo = calloc(1, sizeof(Frame_Info));
+ if (!finfo)
+ {
+ free(frame);
+ return NULL;
+ }
+ // record transparent index to be used or -1 if none
+ // for this SPECIFIC frame
+ finfo->transparent = transparent;
+ // record dispose mode (3 bits)
+ finfo->dispose = dispose;
+ // record delay (2 bytes so max 65546 /100 sec)
+ finfo->delay = delay;
+ // record the index number we are at
+ frame->index = index;
+ // that frame is stored AT image/screen size
+ frame->info = finfo;
+ animated->frames = eina_list_append(animated->frames, frame);
+ return finfo;
+}
+
+// decode a gif image into rows then expand to 32bit into the destination
+// data pointer
+static Eina_Bool
+_decode_image(GifFileType *gif, DATA32 *data, int rowpix, int xin, int yin,
+ int transparent, int x, int y, int w, int h, Eina_Bool fill)
+{
+ int intoffset[] = { 0, 4, 2, 1 };
+ int intjump[] = { 8, 8, 4, 2 };
+ int i, xx, yy, pix;
+ GifRowType *rows;
+ Eina_Bool ret = EINA_FALSE;
+ ColorMapObject *cmap;
+ DATA32 *p;
+
+ // build a blob of memory to have pointers to rows of pixels
+ // AND store the decoded gif pixels (1 byte per pixel) as welll
+ rows = malloc((h * sizeof(GifRowType)) + (w * h * sizeof(GifPixelType)));
+ if (!rows) goto on_error;
+
+ // fill in the pointers at the start
+ for (yy = 0; yy < h; yy++)
+ {
+ rows[yy] = ((unsigned char *)rows) + (h * sizeof(GifRowType)) +
+ (yy * w * sizeof(GifPixelType));
+ }
+
+ // if give is interlaced, walk interlace pattern and decode into rows
+ if (gif->Image.Interlace)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ for (yy = intoffset[i]; yy < h; yy += intjump[i])
+ {
+ if (DGifGetLine(gif, rows[yy], w) != GIF_OK)
+ goto on_error;
+ }
+ }
+ }
+ // normal top to bottom - decode into rows
+ else
+ {
+ for (yy = 0; yy < h; yy++)
+ {
+ if (DGifGetLine(gif, rows[yy], w) != GIF_OK)
+ goto on_error;
+ }
+ }
+
+ // work out what colormap to use
+ if (gif->Image.ColorMap) cmap = gif->Image.ColorMap;
+ else cmap = gif->SColorMap;
+
+ // if we need to deal with transparent pixels at all...
+ if (transparent >= 0)
+ {
+ // if we are told to FILL (overwrite with transparency kept)
+ if (fill)
+ {
+ for (yy = 0; yy < h; yy++)
+ {
+ p = data + ((y + yy) * rowpix) + x;
+ for (xx = 0; xx < w; xx++)
+ {
+ pix = PIX(xx, yy);
+ if (pix != transparent) *p = PIXLK(pix);
+ else *p = 0;
+ p++;
+ }
+ }
+ }
+ // paste on top with transparent pixels untouched
+ else
+ {
+ for (yy = 0; yy < h; yy++)
+ {
+ p = data + ((y + yy) * rowpix) + x;
+ for (xx = 0; xx < w; xx++)
+ {
+ pix = PIX(xx, yy);
+ if (pix != transparent) *p = PIXLK(pix);
+ p++;
+ }
+ }
+ }
+ }
+ else
+ {
+ // walk pixels without worring about transparency at all
+ for (yy = 0; yy < h; yy++)
+ {
+ p = data + ((y + yy) * rowpix) + x;
+ for (xx = 0; xx < w; xx++)
+ {
+ pix = PIX(xx, yy);
+ *p = PIXLK(pix);
+ p++;
+ }
+ }
+ }
+ ret = EINA_TRUE;
+
+on_error:
+ free(rows);
+ return ret;
+}
+
+// flush out older rgba frame images to save memory but skip current frame
+// and previous frame (prev needed for dispose mode 3)
+static void
+_flush_older_frames(Evas_Image_Animated *animated,
+ int w, int h,
+ Image_Entry_Frame *thisframe,
+ Image_Entry_Frame *prevframe)
+{
+ Eina_List *l;
+ Image_Entry_Frame *frame;
+ // target is the amount of memory we want to be under for stored frames
+ int total = 0, target = 512 * 1024;
+
+ // total up the amount of memory used by stored frames for this image
+ EINA_LIST_FOREACH(animated->frames, l, frame)
+ {
+ if (frame->data) total++;
+ }
+ total *= (w * h * sizeof(DATA32));
+ // if we use less than target (512k) for frames - dont flush
+ if (total < target) return;
+ // clean oldest frames first and go until below target or until we loop
+ // around back to this frame (curent)
+ EINA_LIST_FOREACH(animated->frames, l, frame)
+ {
+ if (frame == thisframe) break;
+ }
+ if (!l) return;
+ // start on next frame after thisframe
+ l = l->next;
+ // handle wrap to start
+ if (!l) l = animated->frames;
+ // now walk until we hit thisframe again... then stop walk.
+ while (l)
+ {
+ frame = l->data;
+ if (frame == thisframe) break;
+ if (frame->data)
+ {
+ if ((frame != thisframe) && (frame != prevframe))
+ {
+ free(frame->data);
+ frame->data = NULL;
+ // subtract memory used and if below target - stop flush
+ total -= (w * h * sizeof(DATA32));
+ if (total < target) break;
+ }
+ }
+ // go to next - handle wrap to start
+ l = l->next;
+ if (!l) l = animated->frames;
+ }
+}
+
+static int
+_file_read(GifFileType *gft, GifByteType *buf, int len)
+{
+ File_Info *fi = gft->UserData;
+
+ if (fi->pos >= fi->len) return 0; // if at or past end - no
+ if ((fi->pos + len) >= fi->len) len = fi->len - fi->pos;
+ memcpy(buf, fi->map + fi->pos, len);
+ fi->pos += len;
+ return len;
+}
+
+static Eina_Bool
+evas_image_load_file_head_gif2(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Loader_Info *loader = loader_data;
+ Evas_Image_Animated *animated = loader->animated;
+ Eina_File *f = loader->f;
+ Eina_Bool ret = EINA_FALSE;
+ File_Info fi;
+ GifRecordType rec;
+ GifFileType *gif = NULL;
+ // it is possible which gif file have error midle of frames,
+ // in that case we should play gif file until meet error frame.
+ int imgnum = 0;
+ int loop_count = -1;
+ Frame_Info *finfo = NULL;
+ Eina_Bool full = EINA_TRUE;
+
+ // init prop struct with some default null values
+ prop->w = 0;
+ prop->h = 0;
+
+ // map the file and store/track info
+ fi.map = eina_file_map_all(f, EINA_FILE_RANDOM);
+ if (!fi.map) LOADERR(EVAS_LOAD_ERROR_CORRUPT_FILE);
+ fi.len = eina_file_size_get(f);
+ fi.pos = 0;
+
+ // actually ask libgif to open the file
+#if GIFLIB_MAJOR >= 5
+ gif = DGifOpen(&fi, _file_read, NULL);
+#else
+ gif = DGifOpen(&fi, _file_read);
+#endif
+ if (!gif) LOADERR(EVAS_LOAD_ERROR_UNKNOWN_FORMAT);
+ // get the gif "screen size" (the actual image size)
+ prop->w = gif->SWidth;
+ prop->h = gif->SHeight;
+ // if size is invalid - abort here
+ if ((prop->w < 1) || (prop->h < 1) ||
+ (prop->w > IMG_MAX_SIZE) || (prop->h > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(prop->w, prop->h))
+ {
+ if (IMG_TOO_BIG(prop->w, prop->h))
+ LOADERR(EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED);
+ LOADERR(EVAS_LOAD_ERROR_GENERIC);
+ }
+ // walk through gif records in file to figure out info
+ do
+ {
+ if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
+ {
+ // if we have a gif that ends part way through a sequence
+ // (or animation) consider it valid and just break - no error
+ if (imgnum > 1) break;
+ LOADERR(EVAS_LOAD_ERROR_UNKNOWN_FORMAT);
+ }
+ // get image description section
+ if (rec == IMAGE_DESC_RECORD_TYPE)
+ {
+ int img_code;
+ GifByteType *img;
+
+ // get image desc
+ if (DGifGetImageDesc(gif) == GIF_ERROR)
+ LOADERR(EVAS_LOAD_ERROR_UNKNOWN_FORMAT);
+ // skip decoding and just walk image to next
+ if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
+ LOADERR(EVAS_LOAD_ERROR_UNKNOWN_FORMAT);
+ // skip till next...
+ while (img)
+ {
+ img = NULL;
+ DGifGetCodeNext(gif, &img);
+ }
+ // store geometry in the last frame info data
+ if (finfo)
+ {
+ _store_frame_info(gif, finfo);
+ _check_transparency(&full, finfo, prop->w, prop->h);
+ }
+ // or if we dont have a finfo entry - create one even for stills
+ else
+ {
+ // allocate and save frame with field data
+ finfo = _new_frame(animated, -1, 0, 0, imgnum + 1);
+ if (!finfo)
+ LOADERR(EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED);
+ // store geometry info from gif image
+ _store_frame_info(gif, finfo);
+ // check for transparency/alpha
+ _check_transparency(&full, finfo, prop->w, prop->h);
+ }
+ imgnum++;
+ }
+ // we have an extension code block - for animated gifs for sure
+ else if (rec == EXTENSION_RECORD_TYPE)
+ {
+ int ext_code;
+ GifByteType *ext;
+
+ ext = NULL;
+ // get the first extension entry
+ DGifGetExtension(gif, &ext_code, &ext);
+ while (ext)
+ {
+ // graphic control extension - for animated gif data
+ // and transparent index + flag
+ if (ext_code == 0xf9)
+ {
+ // create frame and store it in image
+ finfo = _new_frame
+ (animated,
+ (ext[1] & 1) ? ext[4] : -1, // transparency index
+ (ext[1] >> 2) & 0x7, // dispose mode
+ ((int)ext[3] << 8) | (int)ext[2], // delay
+ imgnum + 1);
+ if (!finfo)
+ LOADERR(EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED);
+ }
+ // netscape extension indicating loop count...
+ else if (ext_code == 0xff) /* application extension */
+ {
+ if (!strncmp((char *)(&ext[1]), "NETSCAPE2.0", 11) ||
+ !strncmp((char *)(&ext[1]), "ANIMEXTS1.0", 11))
+ {
+ ext = NULL;
+ DGifGetExtensionNext(gif, &ext);
+ if (ext[1] == 0x01)
+ {
+ loop_count = ((int)ext[3] << 8) | (int)ext[2];
+ if (loop_count > 0) loop_count++;
+ }
+ }
+ }
+ // and continue onto the next extension entry
+ ext = NULL;
+ DGifGetExtensionNext(gif, &ext);
+ }
+ }
+ }
+ while (rec != TERMINATE_RECORD_TYPE);
+
+ // if the gif main says we have more than one image or our image counting
+ // says so, then this image is animated - indicate this
+ if ((gif->ImageCount > 1) || (imgnum > 1))
+ {
+ animated->animated = 1;
+ animated->loop_count = loop_count;
+ animated->loop_hint = EVAS_IMAGE_ANIMATED_HINT_LOOP;
+ animated->frame_count = MIN(gif->ImageCount, imgnum);
+ }
+ if (!full) prop->alpha = 1;
+ animated->cur_frame = 1;
+
+ // no errors in header scan etc. so set err and return value
+ *error = EVAS_LOAD_ERROR_NONE;
+ ret = EINA_TRUE;
+
+on_error: // jump here on any errors to clean up
+#if (GIFLIB_MAJOR > 5) || ((GIFLIB_MAJOR == 5) && (GIFLIB_MINOR >= 1))
+ if (gif) DGifCloseFile(gif, NULL);
+#else
+ if (gif) DGifCloseFile(gif);
+#endif
+ if (fi.map) eina_file_map_free(f, fi.map);
+ return ret;
+}
+
+static Eina_Bool
+evas_image_load_file_data_gif2(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Loader_Info *loader = loader_data;
+ Evas_Image_Animated *animated = loader->animated;
+ Eina_File *f = loader->f;
+ Eina_Bool ret = EINA_FALSE;
+ GifRecordType rec;
+ GifFileType *gif = NULL;
+ Image_Entry_Frame *frame;
+ int index = 0, imgnum = 0;
+ Frame_Info *finfo;
+
+ // XXX: this is so wrong - storing current frame IN the image
+ // so we have to load multiple times to animate. what if the
+ // same image is shared/loaded in 2 ore more places AND animated
+ // there?
+
+ // use index stored in image (XXX: yuk!)
+ index = animated->cur_frame;
+ // if index is invalid for animated image - error out
+ if ((animated->animated) &&
+ ((index <= 0) || (index > animated->frame_count)))
+ LOADERR(EVAS_LOAD_ERROR_GENERIC);
+ // find the given frame index
+ frame = _find_frame(animated, index);
+ if (frame)
+ {
+ if ((frame->loaded) && (frame->data))
+ {
+ // frame is already there and decoded - jump to end
+ goto on_ok;
+ }
+ }
+ else
+ LOADERR(EVAS_LOAD_ERROR_CORRUPT_FILE);
+
+open_file:
+ // actually ask libgif to open the file
+ gif = loader->gif;
+ if (!gif)
+ {
+ // there was no file previously opened
+ // map the file and store/track info
+ loader->fi.map = eina_file_map_all(f, EINA_FILE_RANDOM);
+ if (!loader->fi.map) LOADERR(EVAS_LOAD_ERROR_CORRUPT_FILE);
+ loader->fi.len = eina_file_size_get(f);
+ loader->fi.pos = 0;
+
+#if GIFLIB_MAJOR >= 5
+ gif = DGifOpen(&(loader->fi), _file_read, NULL);
+#else
+ gif = DGifOpen(&(loader->fi), _file_read);
+#endif
+ // if gif open failed... get out of here
+ if (!gif)
+ {
+ if ((loader->fi.map) && (loader->f))
+ eina_file_map_free(loader->f, loader->fi.map);
+ loader->fi.map = NULL;
+ LOADERR(EVAS_LOAD_ERROR_UNKNOWN_FORMAT);
+ }
+ loader->gif = gif;
+ loader->imgnum = 1;
+ }
+
+ // if we want to go backwards, we likely need/want to re-decode from the
+ // start as we have nothnig to build on
+ if ((index > 0) && (index < loader->imgnum) && (animated->animated))
+ {
+#if (GIFLIB_MAJOR > 5) || ((GIFLIB_MAJOR == 5) && (GIFLIB_MINOR >= 1))
+ if (loader->gif) DGifCloseFile(loader->gif, NULL);
+#else
+ if (loader->gif) DGifCloseFile(loader->gif);
+#endif
+ if ((loader->fi.map) && (loader->f))
+ eina_file_map_free(loader->f, loader->fi.map);
+ loader->gif = NULL;
+ loader->fi.map = NULL;
+ loader->imgnum = 0;
+ goto open_file;
+ }
+
+ // our current position is the previous frame we decoded from the file
+ imgnum = loader->imgnum;
+
+ // walk through gif records in file to figure out info
+ do
+ {
+ if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
+ LOADERR(EVAS_LOAD_ERROR_UNKNOWN_FORMAT);
+ if (rec == EXTENSION_RECORD_TYPE)
+ {
+ int ext_code;
+ GifByteType *ext;
+
+ ext = NULL;
+ DGifGetExtension(gif, &ext_code, &ext);
+ while (ext)
+ {
+ ext = NULL;
+ DGifGetExtensionNext(gif, &ext);
+ }
+ }
+ // get image description section
+ else if (rec == IMAGE_DESC_RECORD_TYPE)
+ {
+ int xin = 0, yin = 0, x = 0, y = 0, w = 0, h = 0;
+ int img_code;
+ GifByteType *img;
+ Image_Entry_Frame *prevframe = NULL;
+ Image_Entry_Frame *thisframe = NULL;
+
+ // get image desc
+ if (DGifGetImageDesc(gif) == GIF_ERROR)
+ LOADERR(EVAS_LOAD_ERROR_UNKNOWN_FORMAT);
+ // get the previous frame entry AND the current one to fill in
+ prevframe = _find_frame(animated, imgnum - 1);
+ thisframe = _find_frame(animated, imgnum);
+ // if we have a frame AND we're animated AND we have no data...
+ if ((thisframe) && (!thisframe->data) && (animated->animated))
+ {
+ Eina_Bool first = EINA_FALSE;
+
+ // allocate it
+ thisframe->data =
+ malloc(prop->w * prop->h * sizeof(DATA32));
+ if (!thisframe->data)
+ LOADERR(EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED);
+ // if we have no prior frame OR prior frame data... empty
+ if ((!prevframe) || (!prevframe->data))
+ {
+ first = EINA_TRUE;
+ finfo = thisframe->info;
+ memset(thisframe->data, 0,
+ prop->w * prop->h * sizeof(DATA32));
+ }
+ // we have a prior frame to copy data from...
+ else
+ {
+ finfo = prevframe->info;
+
+ // fix coords of sub image in case it goes out...
+ _clip_coords(prop->w, prop->h, &xin, &yin,
+ finfo->x, finfo->y, finfo->w, finfo->h,
+ &x, &y, &w, &h);
+ // if dispose mode is not restore - then copy pre frame
+ if (finfo->dispose != 3) // GIF_DISPOSE_RESTORE
+ memcpy(thisframe->data, prevframe->data,
+ prop->w * prop->h * sizeof(DATA32));
+ // if dispose mode is "background" then fill with bg
+ if (finfo->dispose == 2) // GIF_DISPOSE_BACKGND
+ _fill_frame(thisframe->data, prop->w, gif,
+ finfo, x, y, w, h);
+ else if (finfo->dispose == 3) // GIF_DISPOSE_RESTORE
+ {
+ Image_Entry_Frame *prevframe2;
+
+ // we need to copy data from one frame back
+ // from the prev frame into the current frame
+ // (copy the whole image - at least the sample
+ // GifWin.cpp from libgif indicates this is what
+ // needs doing
+ prevframe2 = _find_frame(animated, imgnum - 2);
+ if (prevframe2)
+ memcpy(thisframe->data, prevframe2->data,
+ prop->w * prop->h * sizeof(DATA32));
+ }
+ }
+ // now draw this frame on top
+ finfo = thisframe->info;
+ _clip_coords(prop->w, prop->h, &xin, &yin,
+ finfo->x, finfo->y, finfo->w, finfo->h,
+ &x, &y, &w, &h);
+ if (!_decode_image(gif, thisframe->data, prop->w,
+ xin, yin, finfo->transparent,
+ x, y, w, h, first))
+ LOADERR(EVAS_LOAD_ERROR_CORRUPT_FILE);
+ // mark as loaded and done
+ thisframe->loaded = EINA_TRUE;
+ // and flush old memory if needed (too much)
+ _flush_older_frames(animated, prop->w, prop->h,
+ thisframe, prevframe);
+ }
+ // if we hve a frame BUT the image is not animated... different
+ // path
+ else if ((thisframe) && (!thisframe->data) &&
+ (!animated->animated))
+ {
+ // if we don't have the data decoded yet - decode it
+ if ((!thisframe->loaded) || (!thisframe->data))
+ {
+ // use frame info but we WONT allocate frame pixels
+ finfo = thisframe->info;
+ _clip_coords(prop->w, prop->h, &xin, &yin,
+ finfo->x, finfo->y, finfo->w, finfo->h,
+ &x, &y, &w, &h);
+ // clear out all pixels
+ _fill_frame(pixels, prop->w, gif,
+ finfo, 0, 0, prop->w, prop->h);
+ // and decode the gif with overwriting
+ if (!_decode_image(gif, pixels, prop->w,
+ xin, yin, finfo->transparent,
+ x, y, w, h, EINA_TRUE))
+ LOADERR(EVAS_LOAD_ERROR_CORRUPT_FILE);
+ // mark as loaded and done
+ thisframe->loaded = EINA_TRUE;
+ }
+ // flush mem we don't need (at expense of decode cpu)
+ }
+ else
+ {
+ // skip decoding and just walk image to next
+ if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
+ LOADERR(EVAS_LOAD_ERROR_UNKNOWN_FORMAT);
+ while (img)
+ {
+ img = NULL;
+ DGifGetCodeNext(gif, &img);
+ }
+ }
+ imgnum++;
+ // if we found the image we wanted - get out of here
+ if (imgnum > index) break;
+ }
+ }
+ while (rec != TERMINATE_RECORD_TYPE);
+
+ // if we are at the end of the animation or not animated, close file
+ loader->imgnum = imgnum;
+ if ((animated->frame_count <= 1) || (rec == TERMINATE_RECORD_TYPE))
+ {
+#if (GIFLIB_MAJOR > 5) || ((GIFLIB_MAJOR == 5) && (GIFLIB_MINOR >= 1))
+ if (loader->gif) DGifCloseFile(loader->gif, NULL);
+#else
+ if (loader->gif) DGifCloseFile(loader->gif);
+#endif
+ if ((loader->fi.map) && (loader->f))
+ eina_file_map_free(loader->f, loader->fi.map);
+ loader->gif = NULL;
+ loader->fi.map = NULL;
+ loader->imgnum = 0;
+ }
+
+on_ok:
+ // no errors in header scan etc. so set err and return value
+ *error = EVAS_LOAD_ERROR_NONE;
+ ret = EINA_TRUE;
+
+ // if it was an animated image we need to copy the data to the
+ // pixels for the image from the frame holding the data
+ if (animated->animated && frame->data)
+ memcpy(pixels, frame->data, prop->w * prop->h * sizeof(DATA32));
+ prop->premul = EINA_TRUE;
+
+on_error: // jump here on any errors to clean up
+ return ret;
+}
+
+// get the time between 2 frames in the timeline
+static double
+evas_image_load_frame_duration_gif2(void *loader_data,
+ int start_frame,
+ int frame_num)
+{
+ Loader_Info *loader = loader_data;
+ Evas_Image_Animated *animated = loader->animated;
+ Image_Entry_Frame *frame;
+ int i, total = 0;
+
+ // if its not animated or requested frame data is invalid
+ if (!animated->animated) return -1.0;
+ if ((start_frame + frame_num) > animated->frame_count) return -1.0;
+ if (frame_num < 0) return -1.0;
+
+ if (frame_num < 1) frame_num = 1;
+ // walk frames from start frame though and total up delays
+ for (i = start_frame; i < (start_frame + frame_num); i++)
+ {
+ Frame_Info *finfo;
+
+ // find the frame
+ frame = _find_frame(animated, i);
+ // no frame? barf - bad file or i/o?
+ if (!frame) return -1.0;
+ // get delay and total it up
+ finfo = frame->info;
+ // if delay is sensible - use it else assume 10/100ths of a sec
+ if (finfo->delay > 0) total += finfo->delay;
+ else total += 10;
+ }
+ // return delay in seconds (since timing in gifs is in 1/100ths of a sec)
+ return (double)total / 100.0;
+}
+
+// called on opening of a file load
+static void *
+evas_image_load_file_open_gif2(Eina_File *f,
+ Eina_Stringshare *key EINA_UNUSED, // XXX: we need to use key for frame #
+ Evas_Image_Load_Opts *opts,
+ Evas_Image_Animated *animated,
+ int *error)
+{
+ Loader_Info *loader = calloc(1, sizeof (Loader_Info));
+ if (!loader)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return NULL;
+ }
+ loader->f = f;
+ loader->opts = opts;
+ loader->animated = animated;
+ return loader;
+}
+
+// called on closing of an image file load (end of load)
+static void
+evas_image_load_file_close_gif2(void *loader_data)
+{
+ Loader_Info *loader = loader_data;
+#if (GIFLIB_MAJOR > 5) || ((GIFLIB_MAJOR == 5) && (GIFLIB_MINOR >= 1))
+ if (loader->gif) DGifCloseFile(loader->gif, NULL);
+#else
+ if (loader->gif) DGifCloseFile(loader->gif);
+#endif
+ if ((loader->fi.map) && (loader->f))
+ eina_file_map_free(loader->f, loader->fi.map);
+ free(loader);
+}
+
+// general module delcaration stuff
+static Evas_Image_Load_Func evas_image_load_gif_func =
+{
+ evas_image_load_file_open_gif2,
+ evas_image_load_file_close_gif2,
+ evas_image_load_file_head_gif2,
+ evas_image_load_file_data_gif2,
+ evas_image_load_frame_duration_gif2,
+ EINA_TRUE,
+ EINA_FALSE
+};
+
+// raw module api that the rest of the world sees
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ em->functions = (void *)(&evas_image_load_gif_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "gif",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, gif);
+
+#ifndef EVAS_STATIC_BUILD_GIF
+EVAS_EINA_MODULE_DEFINE(image_loader, gif);
+#endif
diff --git a/src/modules/evas/image_loaders/ico/evas_image_load_ico.c b/src/modules/evas/image_loaders/ico/evas_image_load_ico.c
new file mode 100644
index 0000000000..7645f2a6f5
--- /dev/null
+++ b/src/modules/evas/image_loaders/ico/evas_image_load_ico.c
@@ -0,0 +1,844 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_common_private.h"
+#include "evas_private.h"
+
+static int _evas_loader_ico_log_dom = -1;
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_evas_loader_ico_log_dom, __VA_ARGS__)
+
+typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
+struct _Evas_Loader_Internal
+{
+ Eina_File *f;
+ const char *key;
+ Evas_Image_Load_Opts *opts;
+};
+
+static Eina_Bool
+read_ushort(unsigned char *map, size_t length, size_t *position, unsigned short *ret)
+{
+ unsigned char b[2];
+
+ if (*position + 2 > length) return EINA_FALSE;
+ b[0] = map[(*position)++];
+ b[1] = map[(*position)++];
+ *ret = (b[1] << 8) | b[0];
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_uint(unsigned char *map, size_t length, size_t *position, unsigned int *ret)
+{
+ unsigned char b[4];
+ unsigned int i;
+
+ if (*position + 4 > length) return EINA_FALSE;
+ for (i = 0; i < 4; i++)
+ b[i] = map[(*position)++];
+ *ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_uchar(unsigned char *map, size_t length, size_t *position, unsigned char *ret)
+{
+ if (*position + 1 > length) return EINA_FALSE;
+ *ret = map[(*position)++];
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+read_mem(unsigned char *map, size_t length, size_t *position, void *buffer, int size)
+{
+ if (*position + size > length) return EINA_FALSE;
+ memcpy(buffer, map + *position, size);
+ *position += size;
+ return EINA_TRUE;
+}
+
+enum
+{
+ SMALLEST,
+ BIGGEST,
+ SMALLER,
+ BIGGER
+};
+
+enum
+{
+ ICON = 1,
+ CURSOR = 2
+};
+
+static void *
+evas_image_load_file_open_ico(Eina_File *f, Eina_Stringshare *key,
+ Evas_Image_Load_Opts *opts,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error)
+{
+ Evas_Loader_Internal *loader;
+
+ loader = calloc(1, sizeof (Evas_Loader_Internal));
+ if (!loader)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return NULL;
+ }
+
+ loader->f = f;
+ loader->key = eina_stringshare_ref(key);
+ loader->opts = opts;
+
+ return loader;
+}
+
+static void
+evas_image_load_file_close_ico(void *loader_data)
+{
+ Evas_Loader_Internal *loader = loader_data;
+
+ eina_stringshare_del(loader->key);
+ free(loader);
+}
+
+static Eina_Bool
+evas_image_load_file_head_ico(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+ Evas_Image_Load_Opts *opts;
+ const char *key;
+ Eina_File *f;
+
+ void *map = NULL;
+ size_t position = 0;
+ unsigned short word;
+ unsigned char byte;
+ unsigned wanted_w = 0, wanted_h = 0;
+ int cols, i, planes = 0,
+ bpp = 0, pdelta, search = -1, have_choice = 0,
+ hasa = 1, icount;
+ unsigned int bmoffset, bmsize, fsize;
+ unsigned short reserved, type, count;
+ struct {
+ int pdelta;
+ int w, h;
+ int cols;
+ int bpp, planes;
+ int hot_x, hot_y;
+ unsigned int bmoffset, bmsize;
+ } chosen = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ Eina_Bool r = EINA_FALSE;
+
+ opts = loader->opts;
+ f = loader->f;
+ key = loader->key;
+
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ fsize = eina_file_size_get(f);
+ if (fsize < (6 + 16 + 40)) goto close_file;
+
+ map = eina_file_map_all(f, EINA_FILE_RANDOM);
+ if (!map) goto close_file;
+
+ // key:
+ // NULL == highest res
+ // biggest == highest res
+ // smallest == lowest res
+ //
+ // smaller == next size SMALLER than load opts WxH (if possible)
+ // bigger == next size BIGGER than load opts WxH (if possible)
+ // more ?
+
+ search = BIGGEST;
+ if ((opts->w > 0) && (opts->h > 0))
+ {
+ wanted_w = opts->w;
+ wanted_h = opts->h;
+ search = SMALLER;
+ }
+
+ if (!read_ushort(map, fsize, &position, &reserved)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &type)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &count)) goto close_file;
+ icount = count;
+ if (!((reserved == 0) &&
+ ((type == ICON) || (type == CURSOR)) &&
+ (icount > 0) && (icount <= 10000))) // between 1 and 10000 images
+ goto close_file;
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+ if (key)
+ {
+ if (!strcmp(key, "biggest"))
+ {
+ wanted_w = 0;
+ wanted_h = 0;
+ search = BIGGEST;
+ chosen.pdelta = 0;
+ }
+ else if (!strcmp(key, "smallest"))
+ {
+ wanted_w = 1;
+ wanted_h = 1;
+ search = SMALLEST;
+ chosen.pdelta = 0x7fffffff;
+ }
+ else if (!strcmp(key, "smaller"))
+ {
+ chosen.pdelta = 0x7fffffff;
+ search = SMALLER;
+ }
+ else if (!strcmp(key, "bigger"))
+ {
+ chosen.pdelta = 0x7fffffff;
+ search = BIGGER;
+ }
+ }
+ for (i = 0; i < icount; i++)
+ {
+ unsigned char tw = 0, th = 0, tcols = 0;
+ if (!read_uchar(map, fsize, &position, &tw)) goto close_file;
+ prop->w = tw;
+ if (prop->w <= 0) prop->w = 256;
+ if (!read_uchar(map, fsize, &position, &th)) goto close_file;
+ prop->h = th;
+ if (prop->h <= 0) prop->h = 256;
+ if (!read_uchar(map, fsize, &position, &tcols)) goto close_file;
+ cols = tcols;
+ if (cols <= 0) cols = 256;
+ if (!read_uchar(map, fsize, &position, &byte)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &word)) goto close_file;
+ if (type == CURSOR) planes = word;
+ //else hot_x = word;
+ if (!read_ushort(map, fsize, &position, &word)) goto close_file;
+ if (type == CURSOR) bpp = word;
+ //else hot_y = word;
+ if (!read_uint(map, fsize, &position, &bmsize)) goto close_file;
+ if (!read_uint(map, fsize, &position, &bmoffset)) goto close_file;
+ if ((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize)) goto close_file;
+ if (search == BIGGEST)
+ {
+ pdelta = prop->w * prop->h;
+ if ((!have_choice) ||
+ ((pdelta >= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ chosen.pdelta = pdelta;
+ chosen.w = prop->w;
+ chosen.h = prop->h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ else
+ {
+ if (search == SMALLEST)
+ {
+ pdelta = prop->w * prop->h;
+ if ((!have_choice) ||
+ ((pdelta <= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ chosen.pdelta = pdelta;
+ chosen.w = prop->w;
+ chosen.h = prop->h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ else if (search == SMALLER)
+ {
+ pdelta = (wanted_w * wanted_h) - (prop->w * prop->h);
+ if ((!have_choice) ||
+ ((prop->w <= wanted_w) && (prop->h <= wanted_h) &&
+ (pdelta <= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ if (pdelta < 0) pdelta = 0x7fffffff;
+ chosen.pdelta = pdelta;
+ chosen.w = prop->w;
+ chosen.h = prop->h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ else if (search == BIGGER)
+ {
+ pdelta = (prop->w * prop->h) - (wanted_w * wanted_h);
+ if ((!have_choice) ||
+ ((prop->w >= wanted_w) && (prop->h >= wanted_h) &&
+ (pdelta <= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ if (pdelta < 0) pdelta = 0x7fffffff;
+ chosen.pdelta = pdelta;
+ chosen.w = prop->w;
+ chosen.h = prop->h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ }
+ }
+ if (chosen.bmoffset == 0) goto close_file;
+ position = chosen.bmoffset;
+
+ prop->w = chosen.w;
+ prop->h = chosen.h;
+ if ((prop->w > 256) || (prop->h > 256)) goto close_file;
+ if ((prop->w < 1) || (prop->h < 1) ||
+ (prop->w > IMG_MAX_SIZE) || (prop->h > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(prop->w, prop->h))
+ {
+ if (IMG_TOO_BIG(prop->w, prop->h))
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ else
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+
+ if (hasa) prop->alpha = 1;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ r = EINA_TRUE;
+
+ close_file:
+ if (map) eina_file_map_free(f, map);
+
+ return r;
+}
+
+static Eina_Bool
+evas_image_load_file_data_ico(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+ Evas_Image_Load_Opts *opts;
+ const char *key;
+ Eina_File *f;
+
+ void *map = NULL;
+ size_t position = 0;
+ unsigned short word;
+ unsigned char byte;
+ unsigned int dword;
+ int wanted_w = 0, wanted_h = 0, w, h, cols, i, planes = 0,
+ bpp = 0, pdelta, search = -1, have_choice = 0,
+ stride, pstride, j, right_way_up = 0, diff_size = 0, cols2, icount;
+ unsigned int bmoffset, bmsize, bitcount, fsize,
+ *pal, *surface, *pix, none_zero_alpha = 0;
+ unsigned short reserved, type, count;
+ unsigned char *maskbuf, *pixbuf, *p;
+ struct {
+ int pdelta;
+ int w, h;
+ int cols;
+ int bpp, planes;
+ int hot_x, hot_y;
+ unsigned int bmoffset, bmsize;
+ } chosen = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ Eina_Bool res = EINA_FALSE;
+
+ opts = loader->opts;
+ key = loader->key;
+ f = loader->f;
+
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ fsize = eina_file_size_get(f);
+ if (fsize < (6 + 16 + 40)) goto close_file;
+
+ map = eina_file_map_all(f, EINA_FILE_RANDOM);
+ if (!map) goto close_file;
+
+ // key:
+ // NULL == highest res
+ // biggest == highest res
+ // smallest == lowest res
+ //
+ // smaller == next size SMALLER than load opts WxH (if possible)
+ // bigger == next size BIGGER than load opts WxH (if possible)
+ // more ?
+
+ search = BIGGEST;
+ if ((opts->w > 0) && (opts->h > 0))
+ {
+ wanted_w = opts->w;
+ wanted_h = opts->h;
+ search = SMALLER;
+ }
+
+ if (!read_ushort(map, fsize, &position, &reserved)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &type)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &count)) goto close_file;
+ icount = count;
+ if (!((reserved == 0) &&
+ ((type == ICON) || (type == CURSOR)) &&
+ (icount > 0) && (icount <= 10000))) // between 1 and 10000 images
+ goto close_file;
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+ if (key)
+ {
+ if (!strcmp(key, "biggest"))
+ {
+ wanted_w = 0;
+ wanted_h = 0;
+ search = BIGGEST;
+ chosen.pdelta = 0;
+ }
+ else if (!strcmp(key, "smallest"))
+ {
+ wanted_w = 1;
+ wanted_h = 1;
+ search = SMALLEST;
+ chosen.pdelta = 0x7fffffff;
+ }
+ else if (!strcmp(key, "smaller"))
+ {
+ chosen.pdelta = 0x7fffffff;
+ search = SMALLER;
+ }
+ else if (!strcmp(key, "bigger"))
+ {
+ chosen.pdelta = 0x7fffffff;
+ search = BIGGER;
+ }
+ }
+ for (i = 0; i < icount; i++)
+ {
+ unsigned char tw = 0, th = 0, tcols = 0;
+ if (!read_uchar(map, fsize, &position, &tw)) goto close_file;
+ w = tw;
+ if (w <= 0) w = 256;
+ if (!read_uchar(map, fsize, &position, &th)) goto close_file;
+ h = th;
+ if (h <= 0) h = 256;
+ if (!read_uchar(map, fsize, &position, &tcols)) goto close_file;
+ cols = tcols;
+ if (cols <= 0) cols = 256;
+ if (!read_uchar(map, fsize, &position, &byte)) goto close_file;
+ if (!read_ushort(map, fsize, &position, &word)) goto close_file;
+ if (type == 1) planes = word;
+ //else hot_x = word;
+ if (!read_ushort(map, fsize, &position, &word)) goto close_file;
+ if (type == 1) bpp = word;
+ //else hot_y = word;
+ if (!read_uint(map, fsize, &position, &bmsize)) goto close_file;
+ if (!read_uint(map, fsize, &position, &bmoffset)) goto close_file;
+ if ((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize)) goto close_file;
+ if (search == BIGGEST)
+ {
+ pdelta = w * h;
+ if ((!have_choice) ||
+ ((pdelta >= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ chosen.pdelta = pdelta;
+ chosen.w = w;
+ chosen.h = h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ else
+ {
+ if (search == SMALLEST)
+ {
+ pdelta = w * h;
+ if ((!have_choice) ||
+ ((pdelta <= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ chosen.pdelta = pdelta;
+ chosen.w = w;
+ chosen.h = h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ else if (search == SMALLER)
+ {
+ pdelta = (wanted_w * wanted_h) - (w * h);
+ if ((!have_choice) ||
+ ((w <= wanted_w) && (h <= wanted_h) &&
+ (pdelta <= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ if (pdelta < 0) pdelta = 0x7fffffff;
+ chosen.pdelta = pdelta;
+ chosen.w = w;
+ chosen.h = h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ else if (search == BIGGER)
+ {
+ pdelta = (w * h) - (wanted_w * wanted_h);
+ if ((!have_choice) ||
+ ((w >= wanted_w) && (h >= wanted_h) &&
+ (pdelta <= chosen.pdelta) &&
+ (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+ ((bpp < 3) && (cols >= chosen.cols)))))
+ {
+ have_choice = 1;
+ if (pdelta < 0) pdelta = 0x7fffffff;
+ chosen.pdelta = pdelta;
+ chosen.w = w;
+ chosen.h = h;
+ chosen.cols = cols;
+ chosen.bpp = bpp;
+ chosen.planes = planes;
+ chosen.bmsize = bmsize;
+ chosen.bmoffset = bmoffset;
+ }
+ }
+ }
+ }
+ if (chosen.bmoffset == 0) goto close_file;
+ position = chosen.bmoffset;
+
+ w = chosen.w;
+ h = chosen.h;
+ cols = chosen.cols;
+
+ // changed since we loaded header?
+ if (((int)prop->w != w) || ((int)prop->h != h)) goto close_file;
+
+ // read bmp header time... let's do some checking
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // headersize - dont care
+ if (dword != 40) // must be 40 if bmp entry - if not, something else
+ {
+ ERR("ICO at %i offset, size %i in %s is not a standard ico bmp "
+ " file entry. It may be PNG (new as of Vista - not in original spec)",
+ (int)position, (int)chosen.bmsize,
+ eina_file_filename_get(f));
+ }
+ else
+ {
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // width
+ if (dword > 0)
+ {
+ if ((int)dword != w)
+ {
+ w = dword;
+ diff_size = 1;
+ }
+ }
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // height
+ if (dword > 0)
+ {
+ if ((int)dword != (h * 2))
+ {
+ h = dword / 2;
+ diff_size = 1;
+ }
+ }
+ if (diff_size)
+ {
+ ERR("Broken ICO file: %s - "
+ " Reporting size of %ix%i in index, but bitmap is %ix%i. "
+ " May be expanded or cropped.",
+ eina_file_filename_get(f), prop->w, prop->h, w, h);
+ }
+ if (!read_ushort(map, fsize, &position, &word)) goto close_file; // planes
+ //planes2 = word;
+ if (!read_ushort(map, fsize, &position, &word)) goto close_file; // bitcount
+ bitcount = word;
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // compression
+ //compression = dword;
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // imagesize
+ //imagesize = dword;
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // z pixels per m
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // y pizels per m
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // colors used
+ //colorsused = dword;
+ if (!read_uint(map, fsize, &position, &dword)) goto close_file; // colors important
+ //colorsimportant = dword;
+
+ surface = pixels;
+ memset(surface, 0, prop->w * prop->h * 4);
+
+ if (!((bitcount == 1) || (bitcount == 4) || (bitcount == 8) ||
+ (bitcount == 24) || (bitcount == 32)))
+ goto close_file;
+ if (bitcount <= 8)
+ {
+ cols2 = 1 << bitcount;
+ if (cols == 0) cols = cols2;
+ if (cols > cols2) cols = cols2;
+ }
+ else cols = 0;
+ if (bitcount > 8) cols = 0;
+
+ pal = alloca(256 * 4);
+ for (i = 0; i < cols; i++)
+ {
+ unsigned char a, r, g, b;
+
+ if (!read_uchar(map, fsize, &position, &b)) goto close_file;
+ if (!read_uchar(map, fsize, &position, &g)) goto close_file;
+ if (!read_uchar(map, fsize, &position, &r)) goto close_file;
+ if (!read_uchar(map, fsize, &position, &a)) goto close_file;
+ a = 0xff;
+ pal[i] = ARGB_JOIN(a, r, g, b);
+ }
+ stride = ((w + 31) / 32);
+ maskbuf = alloca(stride * h);
+ pixbuf = alloca(stride * 32 * 4); // more than enough
+ if (bitcount == 1)
+ {
+ pstride = stride * 4;
+ for (i = 0; i < h; i++)
+ {
+ pix = surface + (i * w);
+ if (!right_way_up) pix = surface + ((h - 1 - i) * w);
+ if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
+ p = pixbuf;
+ if (i >= h) continue;
+ for (j = 0; j < w; j++)
+ {
+ if (j >= w) break;
+ if ((j & 0x7) == 0x0) *pix = pal[*p >> 7];
+ else if ((j & 0x7) == 0x1) *pix = pal[(*p >> 6) & 0x1];
+ else if ((j & 0x7) == 0x2) *pix = pal[(*p >> 5) & 0x1];
+ else if ((j & 0x7) == 0x3) *pix = pal[(*p >> 4) & 0x1];
+ else if ((j & 0x7) == 0x4) *pix = pal[(*p >> 3) & 0x1];
+ else if ((j & 0x7) == 0x5) *pix = pal[(*p >> 2) & 0x1];
+ else if ((j & 0x7) == 0x6) *pix = pal[(*p >> 1) & 0x1];
+ else
+ {
+ *pix = pal[*p & 0x1];
+ p++;
+ }
+ pix++;
+ }
+ }
+ }
+ else if (bitcount == 4)
+ {
+ pstride = ((w + 7) / 8) * 4;
+ for (i = 0; i < h; i++)
+ {
+ pix = surface + (i * w);
+ if (!right_way_up) pix = surface + ((h - 1 - i) * w);
+ if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
+ p = pixbuf;
+ if (i >= h) continue;
+ for (j = 0; j < w; j++)
+ {
+ if (j >= w) break;
+ if ((j & 0x1) == 0x1)
+ {
+ *pix = pal[*p & 0x0f];
+ p++;
+ }
+ else
+ {
+ *pix = pal[*p >> 4];
+ }
+ pix++;
+ }
+ }
+ }
+ else if (bitcount == 8)
+ {
+ pstride = ((w + 3) / 4) * 4;
+ for (i = 0; i < h; i++)
+ {
+ pix = surface + (i * w);
+ if (!right_way_up) pix = surface + ((h - 1 - i) * w);
+ if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
+ p = pixbuf;
+ if (i >= h) continue;
+ for (j = 0; j < w; j++)
+ {
+ if (j >= w) break;
+ *pix = pal[*p];
+ p++;
+ pix++;
+ }
+ }
+ }
+ else if (bitcount == 24)
+ {
+ pstride = w * 3;
+ for (i = 0; i < h; i++)
+ {
+ pix = surface + (i * w);
+ if (!right_way_up) pix = surface + ((h - 1 - i) * w);
+ if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
+ p = pixbuf;
+ if (i >= h) continue;
+ for (j = 0; j < w; j++)
+ {
+ unsigned char a, r, g, b;
+
+ if (j >= w) break;
+ b = p[0]; g = p[1]; r = p[2];
+ p += 3;
+ a = 0xff;
+ *pix = ARGB_JOIN(a, r, g, b);
+ pix++;
+ }
+ }
+ }
+ else if (bitcount == 32)
+ {
+ pstride = w * 4;
+ for (i = 0; i < h; i++)
+ {
+ pix = surface + (i * w);
+ if (!right_way_up) pix = surface + ((h - 1 - i) * w);
+ if (!read_mem(map, fsize, &position, pixbuf, pstride)) goto close_file;
+ p = pixbuf;
+ if (i >= h) continue;
+ for (j = 0; j < w; j++)
+ {
+ unsigned char a, r, g, b;
+
+ if (j >= w) break;
+ b = p[0]; g = p[1]; r = p[2]; a = p[3];
+ p += 4;
+ if (a) none_zero_alpha = 1;
+ *pix = ARGB_JOIN(a, r, g, b);
+ pix++;
+ }
+ }
+ }
+ if (!none_zero_alpha)
+ {
+ if (!read_mem(map, fsize, &position, maskbuf, stride * 4 * h)) goto close_file;
+ // apply mask
+ pix = surface;
+ for (i = 0; i < h; i++)
+ {
+ unsigned char *m;
+
+ pix = surface + (i * w);
+ if (!right_way_up) pix = surface + ((h - 1 - i) * w);
+ m = maskbuf + (stride * i * 4);
+ if (i >= h) continue;
+ for (j = 0; j < w; j++)
+ {
+ if (j >= w) break;
+ if (*m & (1 << (7 - (j & 0x7)))) *pix = 0;
+ else A_VAL(pix) = 0xff;
+ if ((j & 0x7) == 0x7) m++;
+ pix++;
+ }
+ }
+ }
+ }
+
+
+ prop->premul = EINA_TRUE;
+ *error = EVAS_LOAD_ERROR_NONE;
+
+ res = EINA_TRUE;
+
+ close_file:
+ if (map) eina_file_map_free(f, map);
+
+ return res;
+}
+
+static Evas_Image_Load_Func evas_image_load_ico_func =
+{
+ evas_image_load_file_open_ico,
+ evas_image_load_file_close_ico,
+ evas_image_load_file_head_ico,
+ evas_image_load_file_data_ico,
+ NULL,
+ EINA_TRUE,
+ EINA_FALSE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ _evas_loader_ico_log_dom = eina_log_domain_register
+ ("evas-ico", EVAS_DEFAULT_LOG_COLOR);
+ if (_evas_loader_ico_log_dom < 0)
+ {
+ EINA_LOG_ERR("Can not create a module log domain.");
+ return 0;
+ }
+ em->functions = (void *)(&evas_image_load_ico_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+ eina_log_domain_unregister(_evas_loader_ico_log_dom);
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "ico",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, ico);
+
+#ifndef EVAS_STATIC_BUILD_ICO
+EVAS_EINA_MODULE_DEFINE(image_loader, ico);
+#endif
diff --git a/src/modules/evas/image_loaders/jp2k/evas_image_load_jp2k.c b/src/modules/evas/image_loaders/jp2k/evas_image_load_jp2k.c
new file mode 100644
index 0000000000..ececb6d027
--- /dev/null
+++ b/src/modules/evas/image_loaders/jp2k/evas_image_load_jp2k.c
@@ -0,0 +1,409 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include <openjpeg.h>
+
+#include "Evas_Loader.h"
+
+static int _evas_loader_jp2k_log_dom = -1;
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_evas_loader_jp2k_log_dom, __VA_ARGS__)
+
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_evas_loader_jp2k_log_dom, __VA_ARGS__)
+
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_evas_loader_jp2k_log_dom, __VA_ARGS__)
+
+typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
+struct _Evas_Loader_Internal
+{
+ Eina_File *f;
+ Evas_Image_Load_Opts *opts;
+};
+
+static void
+_jp2k_error_cb(const char *msg EINA_UNUSED, void *data EINA_UNUSED)
+{
+// ERR("OpenJPEG internal error: '%s'.", msg);
+}
+
+static void
+_jp2k_warning_cb(const char *msg EINA_UNUSED, void *data EINA_UNUSED)
+{
+// WRN("OpenJPEG internal warning: '%s'.", msg);
+}
+
+static void
+_jp2k_info_cb(const char *msg EINA_UNUSED, void *data EINA_UNUSED)
+{
+// INF("OpenJPEG internal information: '%s'.", msg);
+}
+
+static Eina_Bool
+evas_image_load_file_head_jp2k_internal(unsigned int *w, unsigned int *h,
+ unsigned char *alpha,
+ Evas_Image_Load_Opts *opts EINA_UNUSED,
+ void *map, size_t length,
+ int *error)
+{
+ opj_event_mgr_t event_mgr;
+ opj_dparameters_t params;
+ opj_dinfo_t *info;
+ opj_cio_t *cio;
+ opj_image_t *image;
+ int format;
+ int k;
+
+ if (length < 2)
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ return EINA_FALSE;
+ }
+
+ if (((unsigned char *)map)[0] == 0xFF && ((unsigned char *)map)[1] == 0x4F)
+ format = CODEC_J2K;
+ else
+ format = CODEC_JP2;
+
+ memset(&event_mgr, 0, sizeof(event_mgr));
+ event_mgr.error_handler = _jp2k_error_cb;
+ event_mgr.warning_handler = _jp2k_warning_cb;
+ event_mgr.info_handler = _jp2k_info_cb;
+
+ opj_set_default_decoder_parameters(&params);
+ info = opj_create_decompress(format);
+ if (!info)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+ opj_set_event_mgr((opj_common_ptr)info, &event_mgr, NULL);
+ opj_setup_decoder(info, &params);
+
+ cio = opj_cio_open((opj_common_ptr)info, map, length);
+ if (!cio)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+
+ image = opj_decode(info, cio);
+ if (!image)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+
+ for (k = 1; k < image->numcomps; k++)
+ {
+ if (image->comps[k].w != image->comps[0].w)
+ goto free_image;
+ if (image->comps[k].h != image->comps[0].h)
+ goto free_image;
+ if (image->comps[k].prec > 8)
+ goto free_image;
+ }
+
+ *w = image->comps[0].w;
+ *h = image->comps[0].h;
+ *alpha = ((image->numcomps == 4) || (image->numcomps == 2)) ? 1 : 0;
+ *error = EVAS_LOAD_ERROR_NONE;
+
+ opj_image_destroy(image);
+ opj_cio_close(cio);
+ opj_destroy_decompress(info);
+
+ return EINA_TRUE;
+
+ free_image:
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ opj_image_destroy(image);
+ opj_cio_close(cio);
+ opj_destroy_decompress(info);
+
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+evas_image_load_file_data_jp2k_internal(Evas_Image_Load_Opts *opts EINA_UNUSED,
+ Evas_Image_Property *prop EINA_UNUSED,
+ void *pixels,
+ void *map, size_t length,
+ int *error)
+{
+ opj_dparameters_t params;
+ opj_dinfo_t *info;
+ opj_cio_t *cio;
+ opj_image_t *image;
+ unsigned int *iter;
+ int format;
+ int idx;
+
+ if (((unsigned char *)map)[0] == 0xFF && ((unsigned char *)map)[1] == 0x4F)
+ format = CODEC_J2K;
+ else
+ format = CODEC_JP2;
+
+ opj_set_default_decoder_parameters(&params);
+ info = opj_create_decompress(format);
+ opj_set_event_mgr((opj_common_ptr)info, NULL, NULL);
+ opj_setup_decoder(info, &params);
+ cio = opj_cio_open((opj_common_ptr)info, map, length);
+ image = opj_decode(info, cio);
+
+ iter = pixels;
+ idx = 0;
+
+ /*
+ * FIXME:
+ * image->numcomps == 4, image->color_space == CLRSPC_SYCC : YUV
+ */
+ /* BGR(A) */
+ if ((image->numcomps >= 3) &&
+ (image->comps[0].dx == image->comps[1].dx) &&
+ (image->comps[1].dx == image->comps[2].dx) &&
+ (image->comps[0].dy == image->comps[1].dy) &&
+ (image->comps[1].dy == image->comps[2].dy))
+ {
+ int a;
+ int r;
+ int g;
+ int b;
+ int i;
+ int j;
+
+ for (j = 0; j < image->comps[0].h; j++)
+ {
+ for (i = 0; i < image->comps[0].w; i++, idx++, iter++)
+ {
+ r = image->comps[0].data[idx];
+ r+= (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
+ if (r > 255) r = 255;
+ if (r < 0) r = 0;
+
+ g = image->comps[1].data[idx];
+ g+= (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
+ if (g > 255) g = 255;
+ if (g < 0) g = 0;
+
+ b = image->comps[2].data[idx];
+ b+= (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
+ if (b > 255) b = 255;
+ if (b < 0) b = 0;
+
+ if (image->numcomps == 4)
+ {
+ a = image->comps[3].data[idx];
+ a+= (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);
+ if (a > 255) a = 255;
+ if (a < 0) a = 0;
+ }
+ else
+ a = 255;
+
+ *iter = a << 24 | r << 16 | g << 8 | b;
+ }
+ }
+ }
+ /* *GRAY(A) */
+ else if (((image->numcomps == 1) || (image->numcomps == 2)) &&
+ (image->comps[0].dx == image->comps[1].dx) &&
+ (image->comps[1].dx == image->comps[2].dx) &&
+ (image->comps[0].dy == image->comps[1].dy) &&
+ (image->comps[1].dy == image->comps[2].dy))
+ {
+ int a;
+ int g;
+ int i;
+ int j;
+
+ for (j = 0; j < image->comps[0].h; j++)
+ {
+ for (i = 0; i < image->comps[0].w; i++, idx++, iter++)
+ {
+ g = image->comps[0].data[idx];
+ g+= (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
+ if (g > 255) g = 255;
+ if (g < 0) g = 0;
+
+ if (image->numcomps == 2)
+ {
+ a = image->comps[1].data[idx];
+ a+= (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
+ if (a > 255) a = 255;
+ if (a < 0) a = 0;
+ }
+ else
+ a = 255;
+
+ *iter = a << 24 | g << 16 | g << 8 | g;
+ }
+ }
+ }
+
+ opj_image_destroy(image);
+ opj_cio_close(cio);
+ opj_destroy_decompress(info);
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+}
+
+static void *
+evas_image_load_file_open_jp2k(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
+ Evas_Image_Load_Opts *opts,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error)
+{
+ Evas_Loader_Internal *loader;
+
+ loader = calloc(1, sizeof (Evas_Loader_Internal));
+ if (!loader)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return NULL;
+ }
+
+ loader->f = f;
+ loader->opts = opts;
+
+ return loader;
+}
+
+static void
+evas_image_load_file_close_jp2k(void *loader_data)
+{
+ free(loader_data);
+}
+
+static Eina_Bool
+evas_image_load_file_head_jp2k(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+ Evas_Image_Load_Opts *opts;
+ Eina_File *f;
+ void *map;
+ Eina_Bool val;
+
+ opts = loader->opts;
+ f = loader->f;
+
+ map = eina_file_map_all(f, EINA_FILE_RANDOM);
+ if (!map)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ val = evas_image_load_file_head_jp2k_internal(&prop->w, &prop->h,
+ &prop->alpha,
+ opts,
+ map, eina_file_size_get(f),
+ error);
+
+ eina_file_map_free(f, map);
+
+ return val;
+}
+
+static Eina_Bool
+evas_image_load_file_data_jp2k(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+ Evas_Image_Load_Opts *opts;
+ Eina_File *f;
+ void *map;
+ Eina_Bool val = EINA_FALSE;
+
+ f = loader->f;
+ opts = loader->opts;
+
+ map = eina_file_map_all(f, EINA_FILE_WILLNEED);
+ if (!map)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ goto on_error;
+ }
+
+ val = evas_image_load_file_data_jp2k_internal(opts, prop, pixels,
+ map, eina_file_size_get(f),
+ error);
+
+ eina_file_map_free(f, map);
+
+ on_error:
+ return val;
+}
+
+static Evas_Image_Load_Func evas_image_load_jp2k_func =
+{
+ evas_image_load_file_open_jp2k,
+ evas_image_load_file_close_jp2k,
+ evas_image_load_file_head_jp2k,
+ evas_image_load_file_data_jp2k,
+ NULL,
+ EINA_TRUE,
+ EINA_TRUE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+
+ _evas_loader_jp2k_log_dom = eina_log_domain_register("evas-jp2k", EINA_COLOR_BLUE);
+ if (_evas_loader_jp2k_log_dom < 0)
+ {
+ EINA_LOG_ERR("Can not create a module log domain.");
+ return 0;
+ }
+
+ em->functions = (void *)(&evas_image_load_jp2k_func);
+
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+ eina_log_domain_unregister(_evas_loader_jp2k_log_dom);
+ _evas_loader_jp2k_log_dom = -1;
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "jp2k",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, jp2k);
+
+#ifndef EVAS_STATIC_BUILD_JP2K
+EVAS_EINA_MODULE_DEFINE(image_loader, jp2k);
+#endif
+
diff --git a/src/modules/evas/image_loaders/jpeg/evas_image_load_jpeg.c b/src/modules/evas/image_loaders/jpeg/evas_image_load_jpeg.c
new file mode 100644
index 0000000000..c0047a3ea8
--- /dev/null
+++ b/src/modules/evas/image_loaders/jpeg/evas_image_load_jpeg.c
@@ -0,0 +1,1500 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#ifdef _WIN32
+# define XMD_H /* This prevents libjpeg to redefine INT32 */
+#endif
+
+#include <setjmp.h>
+#include <jpeglib.h>
+
+#include "evas_common_private.h"
+#include "evas_private.h"
+
+typedef struct _JPEG_error_mgr *emptr;
+struct _JPEG_error_mgr
+{
+ struct jpeg_error_mgr pub;
+ jmp_buf setjmp_buffer;
+};
+
+typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
+struct _Evas_Loader_Internal
+{
+ Eina_File *f;
+ Evas_Image_Load_Opts *opts;
+};
+
+
+static void _JPEGFatalErrorHandler(j_common_ptr cinfo);
+static void _JPEGErrorHandler(j_common_ptr cinfo);
+static void _JPEGErrorHandler2(j_common_ptr cinfo, int msg_level);
+static Eina_Bool _get_next_app0(unsigned char *map, size_t fsize, size_t *position);
+static Eina_Bool _get_orientation_app1(unsigned char *map, size_t fsize, size_t *position,
+ int *orientation, Eina_Bool *flipped);
+static int _get_orientation(void *map, size_t length, Eina_Bool *flipped);
+
+#if 0 /* not used at the moment */
+static int evas_image_load_file_data_jpeg_alpha_internal(Image_Entry *ie, FILE *f) EINA_ARG_NONNULL(1, 2);
+#endif
+
+static void
+_JPEGFatalErrorHandler(j_common_ptr cinfo)
+{
+ emptr errmgr;
+
+ errmgr = (emptr) cinfo->err;
+ /* cinfo->err->output_message(cinfo);*/
+ longjmp(errmgr->setjmp_buffer, 1);
+ return;
+}
+
+static void
+_JPEGErrorHandler(j_common_ptr cinfo EINA_UNUSED)
+{
+/* emptr errmgr; */
+
+/* errmgr = (emptr) cinfo->err; */
+ /* cinfo->err->output_message(cinfo);*/
+ /* longjmp(errmgr->setjmp_buffer, 1);*/
+ return;
+}
+
+static void
+_JPEGErrorHandler2(j_common_ptr cinfo EINA_UNUSED, int msg_level EINA_UNUSED)
+{
+/* emptr errmgr; */
+
+/* errmgr = (emptr) cinfo->err; */
+ /* cinfo->err->output_message(cinfo);*/
+ /* longjmp(errmgr->setjmp_buffer, 1);*/
+ return;
+}
+
+struct jpeg_membuf_src
+{
+ struct jpeg_source_mgr pub;
+
+ const unsigned char *buf;
+ size_t len;
+ struct jpeg_membuf_src *self;
+};
+
+static void
+_evas_jpeg_membuf_src_init(j_decompress_ptr cinfo EINA_UNUSED)
+{
+}
+
+static boolean
+_evas_jpeg_membuf_src_fill(j_decompress_ptr cinfo)
+{
+ static const JOCTET jpeg_eoi[2] = { 0xFF, JPEG_EOI };
+ struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src;
+
+ src->pub.bytes_in_buffer = sizeof(jpeg_eoi);
+ src->pub.next_input_byte = jpeg_eoi;
+
+ return TRUE;
+}
+
+static void
+_evas_jpeg_membuf_src_skip(j_decompress_ptr cinfo,
+ long num_bytes)
+{
+ struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src;
+
+ if ((((long)src->pub.bytes_in_buffer - (long)src->len) > num_bytes) ||
+ ((long)src->pub.bytes_in_buffer < num_bytes))
+ {
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo));
+ return;
+ }
+ src->pub.bytes_in_buffer -= num_bytes;
+ src->pub.next_input_byte += num_bytes;
+}
+
+static void
+_evas_jpeg_membuf_src_term(j_decompress_ptr cinfo)
+{
+ struct jpeg_membuf_src *src = (struct jpeg_membuf_src *)cinfo->src;
+ if (!src) return;
+ free(src);
+ cinfo->src = NULL;
+}
+
+static int
+_evas_jpeg_membuf_src(j_decompress_ptr cinfo,
+ void *map, size_t length)
+{
+ struct jpeg_membuf_src *src;
+
+ src = calloc(1, sizeof(*src));
+ if (!src)
+ return -1;
+
+ src->self = src;
+
+ cinfo->src = &src->pub;
+ src->buf = map;
+ src->len = length;
+ src->pub.init_source = _evas_jpeg_membuf_src_init;
+ src->pub.fill_input_buffer = _evas_jpeg_membuf_src_fill;
+ src->pub.skip_input_data = _evas_jpeg_membuf_src_skip;
+ src->pub.resync_to_restart = jpeg_resync_to_restart;
+ src->pub.term_source = _evas_jpeg_membuf_src_term;
+ src->pub.bytes_in_buffer = src->len;
+ src->pub.next_input_byte = src->buf;
+
+ return 0;
+}
+
+/*! Magic number for EXIF header, App0, App1*/
+static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
+static const unsigned char JfifHeader[] = {0x4A, 0x46, 0x49, 0x46, 0x00};
+static const unsigned char JfxxHeader[] = {0x4A, 0x46, 0x58, 0x58, 0x00};
+static const unsigned char App0[] = {0xff, 0xe0};
+static const unsigned char App1[] = {0xff, 0xe1};
+static const unsigned char II[] = {0x49, 0x49};
+static const unsigned char MM[] = {0x4d, 0x4d};
+typedef enum {
+ EXIF_BYTE_ALIGN_II,
+ EXIF_BYTE_ALIGN_MM
+} ExifByteAlign;
+
+static Eina_Bool
+_get_next_app0(unsigned char *map, size_t fsize, size_t *position)
+{
+ unsigned short length = 0;
+ unsigned int w = 0, h = 0;
+ unsigned int format = 0;
+ unsigned int data_size = 0;
+ unsigned char *app0_head, *p;
+
+ /* header_mark:2, length:2, identifier:5 version:2, unit:1, den=4 thum=2 */
+ if ((*position + 16) >= fsize) return EINA_FALSE;
+ app0_head = map + *position;
+
+ /* p is appn's start pointer excluding app0 marker */
+ p = app0_head + 2;
+
+ length = ((*p << 8) + *(p + 1));
+
+ /* JFIF segment format */
+ if (!memcmp(p + 2, JfifHeader, sizeof (JfifHeader)))
+ {
+ format = 3;
+ w = *(p + 14);
+ h = *(p + 15);
+ }
+ else if (!memcmp(p + 2, JfxxHeader, sizeof (JfxxHeader)))
+ {
+ if (*(p + 7) == 0x11)
+ format = 1;
+ else
+ format = 3;
+ w = *(p + 8);
+ h = *(p + 9);
+ }
+
+ data_size = format * w * h;
+
+ if ((*position + 2+ length + data_size) > fsize)
+ return EINA_FALSE;
+
+ *position = *position + 2 + length + data_size;
+
+ return EINA_TRUE;
+}
+
+/* If app1 data is abnormal, returns EINA_FALSE.
+ If app1 data is normal, returns EINA_TRUE.
+ If app1 data is normal but not orientation data, orientation value is -1.
+ */
+
+static Eina_Bool
+_get_orientation_app1(unsigned char *map, size_t fsize, size_t *position,
+ int *orientation_res, Eina_Bool *flipped)
+{
+ unsigned char *app1_head, *buf;
+ unsigned char orientation[2];
+ ExifByteAlign byte_align;
+ unsigned int num_directory = 0;
+ unsigned int i, j;
+ int direction;
+ unsigned int data_size = 0;
+
+ /* app1 mark:2, data_size:2, exif:6 tiff:8 */
+ if ((*position + 18) >= fsize) return EINA_FALSE;
+ app1_head = map + *position;
+ buf = app1_head;
+
+ data_size = ((*(buf + 2) << 8) + *(buf + 3));
+ if ((*position + 2 + data_size) > fsize) return EINA_FALSE;
+
+ if (memcmp(buf + 4, ExifHeader, sizeof (ExifHeader)))
+ {
+ *position = *position + 2 + data_size;
+ *orientation_res = -1;
+ return EINA_TRUE;
+ }
+
+ /* 2. get 10&11 byte get info of "II(0x4949)" or "MM(0x4d4d)" */
+ /* 3. get [18]&[19] get directory entry # */
+ if (!memcmp(buf + 10, MM, sizeof (MM)))
+ {
+ byte_align = EXIF_BYTE_ALIGN_MM;
+ num_directory = ((*(buf + 18) << 8) + *(buf + 19));
+ orientation[0] = 0x01;
+ orientation[1] = 0x12;
+ }
+ else if (!memcmp(buf + 10, II, sizeof (II)))
+ {
+ byte_align = EXIF_BYTE_ALIGN_II;
+ num_directory = ((*(buf + 19) << 8) + *(buf + 18));
+ orientation[0] = 0x12;
+ orientation[1] = 0x01;
+ }
+ else return EINA_FALSE;
+
+ /* check num_directory data */
+ if ((*position + (12 * num_directory + 20)) > fsize) return EINA_FALSE;
+
+ buf = app1_head + 20;
+
+ j = 0;
+
+ for (i = 0; i < num_directory; i++ )
+ {
+ if (!memcmp(buf + j, orientation, 2))
+ {
+ /*get orientation tag */
+ if (byte_align == EXIF_BYTE_ALIGN_MM)
+ direction = *(buf+ j + 9);
+ else direction = *(buf+ j + 8);
+ switch (direction)
+ {
+ case 3:
+ *orientation_res = 180;
+ *flipped = EINA_FALSE;
+ return EINA_TRUE;
+ case 4:
+ *orientation_res = 180;
+ *flipped = EINA_TRUE;
+ return EINA_TRUE;
+ case 6:
+ *orientation_res = 90;
+ *flipped = EINA_FALSE;
+ return EINA_TRUE;
+ case 7:
+ *orientation_res = 90;
+ *flipped = EINA_TRUE;
+ return EINA_TRUE;
+ case 5:
+ *orientation_res = 270;
+ *flipped = EINA_TRUE;
+ return EINA_TRUE;
+ case 8:
+ *orientation_res = 270;
+ *flipped = EINA_FALSE;
+ return EINA_TRUE;
+ case 2:
+ *orientation_res = 0;
+ *flipped = EINA_TRUE;
+ return EINA_TRUE;
+ default:
+ *orientation_res = 0;
+ *flipped = EINA_FALSE;
+ return EINA_TRUE;
+ }
+ }
+ else
+ j = j + 12;
+ }
+ return EINA_FALSE;
+}
+
+static int
+_get_orientation(void *map, size_t length, Eina_Bool *flipped)
+{
+ unsigned char *buf;
+ size_t position = 0;
+ int orientation = -1;
+ Eina_Bool res = EINA_FALSE;
+
+ *flipped = EINA_FALSE;
+
+ /* open file and get 22 byte frome file */
+ if (!map) return 0;
+ /* 1. read 22byte */
+ if (length < 22) return 0;
+ buf = (unsigned char *)map;
+
+ position = 2;
+ /* 2. check 2,3 bypte with APP0(0xFFE0) or APP1(0xFFE1) */
+ while((length - position) > 0)
+ {
+ if (!memcmp(buf + position, App0, sizeof (App0)))
+ {
+ res = _get_next_app0(map, length, &position);
+ if (!res) break;
+ }
+ else if (!memcmp(buf + position, App1, sizeof (App1)))
+ {
+ res = _get_orientation_app1(map, length, &position, &orientation, flipped);
+ if (!res) break;
+ if (orientation != -1) return orientation;
+ }
+ else break;
+ }
+ return 0;
+}
+
+static void
+_rotate_region(unsigned int *r_x, unsigned int *r_y, unsigned int *r_w, unsigned int *r_h,
+ unsigned int x, unsigned int y, unsigned int w, unsigned int h,
+ unsigned int output_w, unsigned int output_h,
+ int degree, Eina_Bool flipped)
+{
+ switch (degree)
+ {
+ case 90:
+ if (flipped)
+ {
+ *r_x = output_w - (y + h);
+ *r_y = output_h - (x + w);
+ *r_w = h;
+ *r_h = w;
+ }
+ else
+ {
+ *r_x = y;
+ *r_y = output_h - (x + y);
+ *r_w = h;
+ *r_h = w;
+ }
+ break;
+ case 180:
+ if (flipped)
+ {
+ *r_y = output_h - (y + h);
+ }
+ else
+ {
+ *r_x = output_w - (x + w);
+ *r_y = output_h - (y + h);
+ }
+ break;
+ case 270:
+ if (flipped)
+ {
+ *r_x = y;
+ *r_y = x;
+ *r_w = h;
+ *r_h = w;
+ }
+ else
+ {
+ *r_x = output_w - (y + h);
+ *r_y = x;
+ *r_w = h;
+ *r_h = w;
+ }
+ break;
+ default:
+ if (flipped)
+ *r_x = output_w - (x + w);
+ break;
+ }
+}
+
+static Eina_Bool
+evas_image_load_file_head_jpeg_internal(unsigned int *w, unsigned int *h,
+ unsigned char *scale,
+ unsigned char *rotated,
+ Eina_Bool *flipped,
+ Evas_Image_Load_Opts *opts,
+ void *map, size_t length,
+ int *error)
+{
+ unsigned int scalew, scaleh;
+ struct jpeg_decompress_struct cinfo;
+ struct _JPEG_error_mgr jerr;
+
+ /* for rotation decoding */
+ int degree = 0;
+ Eina_Bool change_wh = EINA_FALSE;
+ unsigned int load_opts_w = 0, load_opts_h = 0;
+
+ memset(&cinfo, 0, sizeof(cinfo));
+ cinfo.err = jpeg_std_error(&(jerr.pub));
+ jerr.pub.error_exit = _JPEGFatalErrorHandler;
+ jerr.pub.emit_message = _JPEGErrorHandler2;
+ jerr.pub.output_message = _JPEGErrorHandler;
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ if (cinfo.saw_JFIF_marker)
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ else
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+ jpeg_create_decompress(&cinfo);
+
+ if (_evas_jpeg_membuf_src(&cinfo, map, length))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+
+ jpeg_read_header(&cinfo, TRUE);
+ cinfo.do_fancy_upsampling = FALSE;
+ cinfo.do_block_smoothing = FALSE;
+ cinfo.dct_method = JDCT_ISLOW; // JDCT_FLOAT JDCT_IFAST(quality loss)
+ cinfo.dither_mode = JDITHER_ORDERED;
+ cinfo.buffered_image = TRUE; // buffered mode in case jpg is progressive
+ jpeg_start_decompress(&cinfo);
+
+ /* rotation decoding */
+ if (opts->orientation)
+ {
+ degree = _get_orientation(map, length, flipped);
+ if (degree != 0 || *flipped)
+ {
+ opts->degree = degree;
+ *rotated = EINA_TRUE;
+
+ if (degree == 90 || degree == 270)
+ change_wh = EINA_TRUE;
+ }
+
+ }
+
+ /* head decoding */
+ *w = cinfo.output_width;
+ *h = cinfo.output_height;
+ if ((*w < 1) || (*h < 1) || (*w > IMG_MAX_SIZE) || (*h > IMG_MAX_SIZE) ||
+ (IMG_TOO_BIG(*w, *h)))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ if (IMG_TOO_BIG(*w, *h))
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ else
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ return EINA_FALSE;
+ }
+ if (opts->scale_down_by > 1)
+ {
+ *w /= opts->scale_down_by;
+ *h /= opts->scale_down_by;
+ }
+ else if (opts->dpi > 0.0)
+ {
+ *w = (*w * opts->dpi) / 90.0;
+ *h = (*h * opts->dpi) / 90.0;
+ }
+ else if ((opts->w > 0) && (opts->h > 0))
+ {
+ unsigned int w2 = *w, h2 = *h;
+ /* user set load_opts' w,h on the assumption
+ that image already rotated according to it's orientation info */
+ if (change_wh)
+ {
+ load_opts_w = opts->w;
+ load_opts_h = opts->h;
+ opts->w = load_opts_h;
+ opts->h = load_opts_w;
+ }
+
+ if (opts->w > 0)
+ {
+ w2 = opts->w;
+ h2 = (opts->w * *h) / *w;
+ if ((opts->h > 0) && (h2 > opts->h))
+ {
+ unsigned int w3;
+ h2 = opts->h;
+ w3 = (opts->h * *w) / *h;
+ if (w3 > w2)
+ w2 = w3;
+ }
+ }
+ else if (opts->h > 0)
+ {
+ h2 = opts->h;
+ w2 = (opts->h * *w) / *h;
+ }
+ *w = w2;
+ *h = h2;
+ if (change_wh)
+ {
+ opts->w = load_opts_w;
+ opts->h = load_opts_h;
+ }
+ }
+ if (*w < 1) *w = 1;
+ if (*h < 1) *h = 1;
+
+ if ((*w != cinfo.output_width) || (*h != cinfo.output_height))
+ {
+ scalew = cinfo.output_width / *w;
+ scaleh = cinfo.output_height / *h;
+
+ *scale = scalew;
+ if (scaleh < scalew) *scale = scaleh;
+
+ if (*scale > 8) *scale = 8;
+ else if (*scale < 1) *scale = 1;
+
+ if (*scale == 3) *scale = 2;
+ else if (*scale == 5) *scale = 4;
+ else if (*scale == 6) *scale = 4;
+ else if (*scale == 7) *scale = 4;
+ }
+
+ if (*scale > 1)
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ jpeg_create_decompress(&cinfo);
+
+ if (_evas_jpeg_membuf_src(&cinfo, map, length))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+
+ jpeg_read_header(&cinfo, TRUE);
+ cinfo.do_fancy_upsampling = FALSE;
+ cinfo.do_block_smoothing = FALSE;
+ cinfo.scale_num = 1;
+ cinfo.scale_denom = *scale;
+ cinfo.buffered_image = TRUE; // buffered mode in case jpg is progressive
+ jpeg_calc_output_dimensions(&(cinfo));
+ jpeg_start_decompress(&cinfo);
+ }
+
+ *w = cinfo.output_width;
+ *h = cinfo.output_height;
+
+ // be nice and clip region to image. if its totally outside, fail load
+ if ((opts->region.w > 0) && (opts->region.h > 0))
+ {
+ unsigned int load_region_x = 0, load_region_y = 0;
+ unsigned int load_region_w = 0, load_region_h = 0;
+ if (*rotated)
+ {
+ load_region_x = opts->region.x;
+ load_region_y = opts->region.y;
+ load_region_w = opts->region.w;
+ load_region_h = opts->region.h;
+
+ _rotate_region(&opts->region.x, &opts->region.y, &opts->region.w, &opts->region.h,
+ load_region_x, load_region_y, load_region_w, load_region_h,
+ *w, *h, degree, *flipped);
+ }
+ RECTS_CLIP_TO_RECT(opts->region.x, opts->region.y,
+ opts->region.w, opts->region.h,
+ 0, 0, *w, *h);
+ if ((opts->region.w <= 0) || (opts->region.h <= 0))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ return EINA_FALSE;
+ }
+ *w = opts->region.w;
+ *h = opts->region.h;
+ if (*rotated)
+ {
+ opts->region.x = load_region_x;
+ opts->region.y = load_region_y;
+ opts->region.w = load_region_w;
+ opts->region.h = load_region_h;
+ }
+ }
+/* end head decoding */
+
+ if (change_wh)
+ {
+ unsigned int tmp;
+ tmp = *w;
+ *w = *h;
+ *h = tmp;
+ }
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+}
+
+/*
+static double
+get_time(void)
+{
+ struct timeval timev;
+
+ gettimeofday(&timev, NULL);
+ return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
+}
+*/
+
+static void
+_rotate_180(DATA32 *data, int w, int h)
+{
+ DATA32 *p1, *p2;
+ DATA32 pt;
+ int x;
+
+ p1 = data;
+ p2 = data + (h * w) - 1;
+ for (x = (w * h) / 2; --x >= 0;)
+ {
+ pt = *p1;
+ *p1 = *p2;
+ *p2 = pt;
+ p1++;
+ p2--;
+ }
+}
+
+static void
+_flip_horizontal(DATA32 *data, int w, int h)
+{
+ DATA32 *p1, *p2;
+ DATA32 pt;
+ int x, y;
+
+ for (y = 0; y < h; y++)
+ {
+ p1 = data + (y * w);
+ p2 = data + ((y + 1) * w) - 1;
+ for (x = 0; x < (w >> 1); x++)
+ {
+ pt = *p1;
+ *p1 = *p2;
+ *p2 = pt;
+ p1++;
+ p2--;
+ }
+ }
+}
+
+static void
+_flip_vertical(DATA32 *data, int w, int h)
+{
+ DATA32 *p1, *p2;
+ DATA32 pt;
+ int x, y;
+
+ for (y = 0; y < (h >> 1); y++)
+ {
+ p1 = data + (y * w);
+ p2 = data + ((h - 1 - y) * w);
+ for (x = 0; x < w; x++)
+ {
+ pt = *p1;
+ *p1 = *p2;
+ *p2 = pt;
+ p1++;
+ p2++;
+ }
+ }
+}
+
+static void
+_rotate_change_wh(DATA32 *to, DATA32 *from,
+ int w, int h,
+ int dx, int dy)
+{
+ int x, y;
+
+ for (x = h; --x >= 0;)
+ {
+ for (y = w; --y >= 0;)
+ {
+ *to = *from;
+ from++;
+ to += dy;
+ }
+ to += dx;
+ }
+}
+
+static Eina_Bool
+evas_image_load_file_data_jpeg_internal(Evas_Image_Load_Opts *opts,
+ Evas_Image_Property *prop,
+ void *pixels,
+ void *map, size_t size,
+ int *error)
+{
+ unsigned int w, h;
+ struct jpeg_decompress_struct cinfo;
+ struct _JPEG_error_mgr jerr;
+ DATA8 *ptr, *line[16], *data;
+ DATA32 *ptr2, *ptr_rotate = NULL;
+ unsigned int x, y, l, i, scans;
+ int region = 0;
+ /* rotation setting */
+ unsigned int ie_w = 0, ie_h = 0;
+ unsigned int load_region_x = 0, load_region_y = 0;
+ unsigned int load_region_w = 0, load_region_h = 0;
+ volatile int degree = 0;
+ volatile Eina_Bool change_wh = EINA_FALSE;
+ Eina_Bool line_done = EINA_FALSE;
+
+ memset(&cinfo, 0, sizeof(cinfo));
+ if (prop->rotated)
+ {
+ degree = opts->degree;
+ if (degree == 90 || degree == 270)
+ change_wh = EINA_TRUE;
+ }
+
+ cinfo.err = jpeg_std_error(&(jerr.pub));
+ jerr.pub.error_exit = _JPEGFatalErrorHandler;
+ jerr.pub.emit_message = _JPEGErrorHandler2;
+ jerr.pub.output_message = _JPEGErrorHandler;
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+ jpeg_create_decompress(&cinfo);
+
+ if (_evas_jpeg_membuf_src(&cinfo, map, size))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return 0;
+ }
+
+ jpeg_read_header(&cinfo, TRUE);
+ cinfo.do_fancy_upsampling = FALSE;
+ cinfo.do_block_smoothing = FALSE;
+ cinfo.dct_method = JDCT_ISLOW; // JDCT_FLOAT JDCT_IFAST(quality loss)
+ cinfo.dither_mode = JDITHER_ORDERED;
+
+ if (prop->scale > 1)
+ {
+ cinfo.scale_num = 1;
+ cinfo.scale_denom = prop->scale;
+ }
+
+ /* Colorspace conversion options */
+ /* libjpeg can do the following conversions: */
+ /* GRAYSCLAE => RGB YCbCr => RGB and YCCK => CMYK */
+ switch (cinfo.jpeg_color_space)
+ {
+ case JCS_UNKNOWN:
+ break;
+ case JCS_GRAYSCALE:
+ case JCS_RGB:
+ case JCS_YCbCr:
+ cinfo.out_color_space = JCS_RGB;
+ break;
+ case JCS_CMYK:
+ case JCS_YCCK:
+ cinfo.out_color_space = JCS_CMYK;
+ break;
+ default:
+ cinfo.out_color_space = JCS_RGB;
+ break;
+ }
+
+/* head decoding */
+ jpeg_calc_output_dimensions(&(cinfo));
+ jpeg_start_decompress(&cinfo);
+
+ w = cinfo.output_width;
+ h = cinfo.output_height;
+
+ if (change_wh)
+ {
+ ie_w = prop->h;
+ ie_h = prop->w;
+ }
+ else
+ {
+ ie_w = prop->w;
+ ie_h = prop->h;
+ }
+
+ if ((opts->region.w > 0) && (opts->region.h > 0))
+ {
+ region = 1;
+
+ if (prop->rotated)
+ {
+ load_region_x = opts->region.x;
+ load_region_y = opts->region.y;
+ load_region_w = opts->region.w;
+ load_region_h = opts->region.h;
+
+ _rotate_region(&opts->region.x, &opts->region.y, &opts->region.w, &opts->region.h,
+ load_region_x, load_region_y, load_region_w, load_region_h,
+ w, h, degree, prop->flipped);
+ }
+#ifdef BUILD_LOADER_JPEG_REGION
+ cinfo.region_x = opts->region.x;
+ cinfo.region_y = opts->region.y;
+ cinfo.region_w = opts->region.w;
+ cinfo.region_h = opts->region.h;
+#endif
+ }
+ if ((!region) && ((w != ie_w) || (h != ie_h)))
+ {
+ // race condition, the file could have change from when we call header
+ // this test will not solve the problem with region code.
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ return EINA_FALSE;
+ }
+ if ((region) &&
+ ((ie_w != opts->region.w) || (ie_h != opts->region.h)))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ return EINA_FALSE;
+ /* ie_w = opts->region.w; */
+ /* ie_h = opts->region.h; */
+ /* if (change_wh) */
+ /* { */
+ /* ie->w = ie_h; */
+ /* ie->h = ie_w; */
+ /* } */
+ /* else */
+ /* { */
+ /* ie->w = ie_w; */
+ /* ie->h = ie_h; */
+ /* } */
+ }
+
+ if (!(((cinfo.out_color_space == JCS_RGB) &&
+ ((cinfo.output_components == 3) || (cinfo.output_components == 1))) ||
+ ((cinfo.out_color_space == JCS_CMYK) && (cinfo.output_components == 4))))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+/* end head decoding */
+/* data decoding */
+ if (cinfo.rec_outbuf_height > 16)
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+ data = alloca(w * 16 * cinfo.output_components);
+ if ((prop->rotated) && change_wh)
+ {
+ ptr2 = malloc(w * h * sizeof(DATA32));
+ ptr_rotate = ptr2;
+ }
+ else
+ ptr2 = pixels;
+
+ if (!ptr2)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+
+ /* We handle first CMYK (4 components) */
+ if (cinfo.output_components == 4)
+ {
+ // FIXME: handle region
+ for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
+ line[i] = data + (i * w * 4);
+ for (l = 0; l < h; l += cinfo.rec_outbuf_height)
+ {
+ jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
+ scans = cinfo.rec_outbuf_height;
+ if ((h - l) < scans) scans = h - l;
+ ptr = data;
+ if (!region)
+ {
+ for (y = 0; y < scans; y++)
+ {
+ if (cinfo.saw_Adobe_marker)
+ {
+ for (x = 0; x < w; x++)
+ {
+ /* According to libjpeg doc, Photoshop inverse the values of C, M, Y and K, */
+ /* that is C is replaces by 255 - C, etc...*/
+ /* See the comment below for the computation of RGB values from CMYK ones. */
+ *ptr2 =
+ (0xff000000) |
+ ((ptr[0] * ptr[3] / 255) << 16) |
+ ((ptr[1] * ptr[3] / 255) << 8) |
+ ((ptr[2] * ptr[3] / 255));
+ ptr += 4;
+ ptr2++;
+ }
+ }
+ else
+ {
+ for (x = 0; x < w; x++)
+ {
+ /* Conversion from CMYK to RGB is done in 2 steps: */
+ /* CMYK => CMY => RGB (see http://www.easyrgb.com/index.php?X=MATH) */
+ /* after computation, if C, M, Y and K are between 0 and 1, we have: */
+ /* R = (1 - C) * (1 - K) * 255 */
+ /* G = (1 - M) * (1 - K) * 255 */
+ /* B = (1 - Y) * (1 - K) * 255 */
+ /* libjpeg stores CMYK values between 0 and 255, */
+ /* so we replace C by C * 255 / 255, etc... and we obtain: */
+ /* R = (255 - C) * (255 - K) / 255 */
+ /* G = (255 - M) * (255 - K) / 255 */
+ /* B = (255 - Y) * (255 - K) / 255 */
+ /* with C, M, Y and K between 0 and 255. */
+ *ptr2 =
+ (0xff000000) |
+ (((255 - ptr[0]) * (255 - ptr[3]) / 255) << 16) |
+ (((255 - ptr[1]) * (255 - ptr[3]) / 255) << 8) |
+ (((255 - ptr[2]) * (255 - ptr[3]) / 255));
+ ptr += 4;
+ ptr2++;
+ }
+ }
+ }
+ }
+ else
+ {
+ // if line # > region last line, break
+ if (l >= (opts->region.y + opts->region.h))
+ {
+ line_done = EINA_TRUE;
+ /* if rotation flag is set , we have to rotate image */
+ goto done;
+ /*jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_FALSE;*/
+ }
+ // els if scan block intersects region start or later
+ else if ((l + scans) >
+ (opts->region.y))
+ {
+ for (y = 0; y < scans; y++)
+ {
+ if (((y + l) >= opts->region.y) &&
+ ((y + l) < (opts->region.y + opts->region.h)))
+ {
+ ptr += opts->region.x;
+ if (cinfo.saw_Adobe_marker)
+ {
+ for (x = 0; x < opts->region.w; x++)
+ {
+ /* According to libjpeg doc, Photoshop inverse the values of C, M, Y and K, */
+ /* that is C is replaces by 255 - C, etc...*/
+ /* See the comment below for the computation of RGB values from CMYK ones. */
+ *ptr2 =
+ (0xff000000) |
+ ((ptr[0] * ptr[3] / 255) << 16) |
+ ((ptr[1] * ptr[3] / 255) << 8) |
+ ((ptr[2] * ptr[3] / 255));
+ ptr += 4;
+ ptr2++;
+ }
+ }
+ else
+ {
+ for (x = 0; x < opts->region.w; x++)
+ {
+ /* Conversion from CMYK to RGB is done in 2 steps: */
+ /* CMYK => CMY => RGB (see http://www.easyrgb.com/index.php?X=MATH) */
+ /* after computation, if C, M, Y and K are between 0 and 1, we have: */
+ /* R = (1 - C) * (1 - K) * 255 */
+ /* G = (1 - M) * (1 - K) * 255 */
+ /* B = (1 - Y) * (1 - K) * 255 */
+ /* libjpeg stores CMYK values between 0 and 255, */
+ /* so we replace C by C * 255 / 255, etc... and we obtain: */
+ /* R = (255 - C) * (255 - K) / 255 */
+ /* G = (255 - M) * (255 - K) / 255 */
+ /* B = (255 - Y) * (255 - K) / 255 */
+ /* with C, M, Y and K between 0 and 255. */
+ *ptr2 =
+ (0xff000000) |
+ (((255 - ptr[0]) * (255 - ptr[3]) / 255) << 16) |
+ (((255 - ptr[1]) * (255 - ptr[3]) / 255) << 8) |
+ (((255 - ptr[2]) * (255 - ptr[3]) / 255));
+ ptr += 4;
+ ptr2++;
+ }
+ }
+ ptr += (4 * (w - (opts->region.x + opts->region.w)));
+ }
+ else
+ ptr += (4 * w);
+ }
+ }
+ }
+ }
+ }
+ /* We handle then RGB with 3 components */
+ else if (cinfo.output_components == 3)
+ {
+/*
+ double t;
+ if (region)
+ {
+ // debug for now
+ printf("R| %p %5ix%5i %s: %5i %5i %5ix%5i - ",
+ ie,
+ ie->w, ie->h,
+ ie->file,
+ opts->region.x,
+ opts->region.y,
+ opts->region.w,
+ opts->region.h);
+ }
+ t = get_time();
+ */
+ for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
+ line[i] = data + (i * w * 3);
+ for (l = 0; l < h; l += cinfo.rec_outbuf_height)
+ {
+ jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
+ scans = cinfo.rec_outbuf_height;
+ if ((h - l) < scans) scans = h - l;
+ ptr = data;
+ if (!region)
+ {
+ for (y = 0; y < scans; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[1], ptr[2]);
+ ptr += 3;
+ ptr2++;
+ }
+ }
+ }
+ else
+ {
+ // if line # > region last line, break
+ // but not return immediately for rotation job
+ if (l >= (opts->region.y + opts->region.h))
+ {
+ line_done = EINA_TRUE;
+ /* if rotation flag is set , we have to rotate image */
+ goto done;
+ }
+ // else if scan block intersects region start or later
+ else if ((l + scans) >
+ (opts->region.y))
+ {
+ for (y = 0; y < scans; y++)
+ {
+ if (((y + l) >= opts->region.y) &&
+ ((y + l) < (opts->region.y + opts->region.h)))
+ {
+ ptr += (3 * opts->region.x);
+ for (x = 0; x < opts->region.w; x++)
+ {
+ *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[1], ptr[2]);
+ ptr += 3;
+ ptr2++;
+ }
+ ptr += (3 * (w - (opts->region.x + opts->region.w)));
+ }
+ else
+ ptr += (3 * w);
+ }
+ }
+ }
+ }
+/*
+ t = get_time() - t;
+ printf("%3.3f\n", t);
+ */
+ }
+ /* We finally handle RGB with 1 component */
+ else if (cinfo.output_components == 1)
+ {
+ for (i = 0; (int)i < cinfo.rec_outbuf_height; i++)
+ line[i] = data + (i * w);
+ for (l = 0; l < h; l += cinfo.rec_outbuf_height)
+ {
+ jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
+ scans = cinfo.rec_outbuf_height;
+ if ((h - l) < scans) scans = h - l;
+ ptr = data;
+ if (!region)
+ {
+ for (y = 0; y < scans; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[0], ptr[0]);
+ ptr++;
+ ptr2++;
+ }
+ }
+ }
+ else
+ {
+ // if line # > region last line, break
+ if (l >= (opts->region.y + opts->region.h))
+ {
+ line_done = EINA_TRUE;
+ /* if rotation flag is set , we have to rotate image */
+ goto done;
+ /*jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;*/
+ }
+ // els if scan block intersects region start or later
+ else if ((l + scans) >
+ (opts->region.y))
+ {
+ for (y = 0; y < scans; y++)
+ {
+ if (((y + l) >= opts->region.y) &&
+ ((y + l) < (opts->region.y + opts->region.h)))
+ {
+ ptr += opts->region.x;
+ for (x = 0; x < opts->region.w; x++)
+ {
+ *ptr2 = ARGB_JOIN(0xff, ptr[0], ptr[0], ptr[0]);
+ ptr++;
+ ptr2++;
+ }
+ ptr += w - (opts->region.x + opts->region.w);
+ }
+ else
+ ptr += w;
+ }
+ }
+ }
+ }
+ }
+ /* if rotation operation need, rotate it */
+done:
+
+ if (prop->rotated)
+ {
+ DATA32 *to;
+ int hw;
+
+ hw = w * h;
+ to = pixels;
+
+ switch (degree)
+ {
+ case 90:
+ if (prop->flipped)
+ _rotate_change_wh(to + hw - 1, ptr_rotate, w, h, hw - 1, -h);
+ else
+ _rotate_change_wh(to + h - 1, ptr_rotate, w, h, -hw - 1, h);
+ break;
+ case 180:
+ if (prop->flipped)
+ _flip_vertical(to, w, h);
+ else
+ _rotate_180(to, w, h);
+ break;
+ case 270:
+ if (prop->flipped)
+ _rotate_change_wh(to, ptr_rotate, w, h, -hw + 1, h);
+ else
+ _rotate_change_wh(to + hw - h, ptr_rotate, w, h, hw + 1, -h);
+ break;
+ default:
+ if (prop->flipped)
+ _flip_horizontal(to, w, h);
+ break;
+ }
+ if (ptr_rotate)
+ {
+ free(ptr_rotate);
+ ptr_rotate = NULL;
+ }
+ if (region)
+ {
+ opts->region.x = load_region_x;
+ opts->region.y = load_region_y;
+ opts->region.w = load_region_w;
+ opts->region.h = load_region_h;
+ }
+ }
+
+ if (line_done)
+ {
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_FALSE;
+ }
+ /* end data decoding */
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ _evas_jpeg_membuf_src_term(&cinfo);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+}
+
+#if 0 /* not used at the moment */
+static Eina_Bool
+evas_image_load_file_data_jpeg_alpha_internal(Image_Entry *ie, FILE *f, int *error)
+{
+ int w, h;
+ struct jpeg_decompress_struct cinfo;
+ struct _JPEG_error_mgr jerr;
+ DATA8 *ptr, *line[16], *data;
+ DATA32 *ptr2;
+ int x, y, l, i, scans, prevy;
+
+ if (!f)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+ cinfo.err = jpeg_std_error(&(jerr.pub));
+ jerr.pub.error_exit = _JPEGFatalErrorHandler;
+ jerr.pub.emit_message = _JPEGErrorHandler2;
+ jerr.pub.output_message = _JPEGErrorHandler;
+ if (setjmp(jerr.setjmp_buffer))
+ {
+ jpeg_destroy_decompress(&cinfo);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+ jpeg_create_decompress(&cinfo);
+ jpeg_stdio_src(&cinfo, f);
+ jpeg_read_header(&cinfo, TRUE);
+ cinfo.do_fancy_upsampling = FALSE;
+ cinfo.do_block_smoothing = FALSE;
+ jpeg_start_decompress(&cinfo);
+
+/* head decoding */
+ ie->w = w = cinfo.output_width;
+ ie->h = h = cinfo.output_height;
+/* end head decoding */
+/* data decoding */
+ if (cinfo.rec_outbuf_height > 16)
+ {
+ jpeg_destroy_decompress(&cinfo);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+ data = alloca(w * 16 * 3);
+ if (!ie->flags.loaded)
+ {
+ jpeg_destroy_decompress(&cinfo);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+ }
+ ptr2 = evas_cache_image_pixels(ie);
+ prevy = 0;
+ if (cinfo.output_components == 3)
+ {
+ for (i = 0; i < cinfo.rec_outbuf_height; i++)
+ line[i] = data + (i * w * 3);
+ for (l = 0; l < h; l += cinfo.rec_outbuf_height)
+ {
+ jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
+ scans = cinfo.rec_outbuf_height;
+ if ((h - l) < scans) scans = h - l;
+ ptr = data;
+ for (y = 0; y < scans; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ *ptr2 =
+ ((*ptr2) & 0x00ffffff) |
+ (((ptr[0] + ptr[1] + ptr[2]) / 3) << 24);
+ ptr += 3;
+ ptr2++;
+ }
+ }
+ }
+ }
+ else if (cinfo.output_components == 1)
+ {
+ for (i = 0; i < cinfo.rec_outbuf_height; i++)
+ line[i] = data + (i * w);
+ for (l = 0; l < h; l += cinfo.rec_outbuf_height)
+ {
+ jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height);
+ scans = cinfo.rec_outbuf_height;
+ if ((h - l) < scans) scans = h - l;
+ ptr = data;
+ for (y = 0; y < scans; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ *ptr2 =
+ ((*ptr2) & 0x00ffffff) |
+ ((ptr[0]) << 24);
+ ptr++;
+ ptr2++;
+ }
+ }
+ }
+ }
+/* end data decoding */
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+}
+#endif
+
+static void *
+evas_image_load_file_open_jpeg(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
+ Evas_Image_Load_Opts *opts,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error)
+{
+ Evas_Loader_Internal *loader;
+
+ loader = calloc(1, sizeof (Evas_Loader_Internal));
+ if (!loader)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return NULL;
+ }
+
+ loader->f = f;
+ loader->opts = opts;
+
+ return loader;
+}
+
+static void
+evas_image_load_file_close_jpeg(void *loader_data)
+{
+ free(loader_data);
+}
+
+static Eina_Bool
+evas_image_load_file_head_jpeg(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+ Evas_Image_Load_Opts *opts;
+ Eina_File *f;
+ void *map;
+ Eina_Bool val;
+
+ opts = loader->opts;
+ f = loader->f;
+
+ map = eina_file_map_all(f, EINA_FILE_RANDOM);
+ if (!map)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ val = evas_image_load_file_head_jpeg_internal(&prop->w, &prop->h,
+ &prop->scale, &prop->rotated,
+ &prop->flipped,
+ opts,
+ map, eina_file_size_get(f),
+ error);
+
+ eina_file_map_free(f, map);
+
+ return val;
+}
+
+static Eina_Bool
+evas_image_load_file_data_jpeg(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+ Evas_Image_Load_Opts *opts;
+ Eina_File *f;
+ void *map;
+ Eina_Bool val = EINA_FALSE;
+
+ f = loader->f;
+ opts = loader->opts;
+
+ map = eina_file_map_all(f, EINA_FILE_WILLNEED);
+ if (!map)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ goto on_error;
+ }
+
+ val = evas_image_load_file_data_jpeg_internal(opts, prop, pixels,
+ map, eina_file_size_get(f),
+ error);
+
+ eina_file_map_free(f, map);
+
+ on_error:
+ return val;
+}
+
+static Evas_Image_Load_Func evas_image_load_jpeg_func =
+{
+ evas_image_load_file_open_jpeg,
+ evas_image_load_file_close_jpeg,
+ evas_image_load_file_head_jpeg,
+ evas_image_load_file_data_jpeg,
+ NULL,
+ EINA_TRUE,
+ EINA_TRUE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ em->functions = (void *)(&evas_image_load_jpeg_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "jpeg",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, jpeg);
+
+#ifndef EVAS_STATIC_BUILD_JPEG
+EVAS_EINA_MODULE_DEFINE(image_loader, jpeg);
+#endif
+
diff --git a/src/modules/evas/image_loaders/pmaps/evas_image_load_pmaps.c b/src/modules/evas/image_loaders/pmaps/evas_image_load_pmaps.c
new file mode 100644
index 0000000000..0a15181089
--- /dev/null
+++ b/src/modules/evas/image_loaders/pmaps/evas_image_load_pmaps.c
@@ -0,0 +1,591 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_common_private.h"
+#include "evas_private.h"
+
+#define FILE_BUFFER_SIZE 1024 * 32
+#define FILE_BUFFER_UNREAD_SIZE 16
+
+/* The buffer to load pmaps images */
+typedef struct Pmaps_Buffer Pmaps_Buffer;
+
+struct Pmaps_Buffer
+{
+ Eina_File *file;
+ unsigned char *map;
+ size_t position;
+
+ /* the buffer */
+ DATA8 buffer[FILE_BUFFER_SIZE];
+ DATA8 unread[FILE_BUFFER_UNREAD_SIZE];
+ DATA8 *current;
+ DATA8 *end;
+ char type[3];
+ unsigned char unread_len:7;
+ unsigned char last_buffer:1;
+
+ /* image properties */
+ int w;
+ int h;
+ int max;
+
+ /* interface */
+ int (*int_get) (Pmaps_Buffer *b, int *val);
+ int (*color_get) (Pmaps_Buffer *b, DATA32 *color);
+};
+
+/* internal used functions */
+static Eina_Bool pmaps_buffer_open(Pmaps_Buffer *b, Eina_File *f, Eina_Bool header, int *error);
+static void pmaps_buffer_close(Pmaps_Buffer *b);
+static Eina_Bool pmaps_buffer_header_parse(Pmaps_Buffer *b, int *error);
+static int pmaps_buffer_plain_int_get(Pmaps_Buffer *b, int *val);
+static int pmaps_buffer_1byte_int_get(Pmaps_Buffer *b, int *val);
+static int pmaps_buffer_2byte_int_get(Pmaps_Buffer *b, int *val);
+static int pmaps_buffer_gray_get(Pmaps_Buffer *b, DATA32 *color);
+static int pmaps_buffer_rgb_get(Pmaps_Buffer *b, DATA32 *color);
+static int pmaps_buffer_plain_bw_get(Pmaps_Buffer *b, DATA32 *color);
+
+static size_t pmaps_buffer_plain_update(Pmaps_Buffer *b);
+static size_t pmaps_buffer_raw_update(Pmaps_Buffer *b);
+static int pmaps_buffer_comment_skip(Pmaps_Buffer *b);
+
+static void *
+evas_image_load_file_open_pmaps(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
+ Evas_Image_Load_Opts *opts EINA_UNUSED,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error EINA_UNUSED)
+{
+ return f;
+}
+
+static void
+evas_image_load_file_close_pmaps(void *loader_data EINA_UNUSED)
+{
+}
+
+static Eina_Bool
+evas_image_load_file_head_pmaps(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Eina_File *f = loader_data;
+ Pmaps_Buffer b;
+
+ if (!pmaps_buffer_open(&b, f, EINA_TRUE, error))
+ {
+ pmaps_buffer_close(&b);
+ return EINA_FALSE;
+ }
+
+ if (!pmaps_buffer_header_parse(&b, error))
+ {
+ pmaps_buffer_close(&b);
+ return EINA_FALSE;
+ }
+
+ prop->w = b.w;
+ prop->h = b.h;
+
+ pmaps_buffer_close(&b);
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+evas_image_load_file_data_pmaps(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Eina_File *f = loader_data;
+ Pmaps_Buffer b;
+ int size;
+ DATA32 *ptr;
+ Eina_Bool r = EINA_FALSE;
+
+ if (!pmaps_buffer_open(&b, f, EINA_FALSE, error))
+ goto on_error;
+
+ if (!pmaps_buffer_header_parse(&b, error))
+ goto on_error;
+
+ size = b.w * b.h;
+ if ((int) prop->w != b.w ||
+ (int) prop->h != b.h)
+ goto on_error;
+
+ ptr = pixels;
+ if (b.type[1] != '4')
+ {
+ while (size > 0 && b.color_get(&b, ptr))
+ {
+ size--;
+ ptr++;
+ }
+ }
+ else
+ {
+ while (size > 0
+ && (b.current != b.end || pmaps_buffer_raw_update(&b)))
+ {
+ int i;
+
+ for (i = 7; i >= 0 && size > 0; i--)
+ {
+ if (*b.current & (1 << i))
+ *ptr = 0xff000000;
+ else
+ *ptr = 0xffffffff;
+ ptr++;
+ size--;
+ }
+ b.current++;
+ }
+ }
+
+ /* if there are some pix missing, give them a proper default */
+ memset(ptr, 0xff, 4 * size);
+ *error = EVAS_LOAD_ERROR_NONE;
+ r = EINA_TRUE;
+
+ on_error:
+ pmaps_buffer_close(&b);
+ return r;
+}
+
+/* internal used functions */
+static Eina_Bool
+pmaps_buffer_open(Pmaps_Buffer *b, Eina_File *f, Eina_Bool header, int *error)
+{
+ size_t len;
+
+ b->file = f;
+ b->map = eina_file_map_all(b->file, header ? EINA_FILE_RANDOM : EINA_FILE_SEQUENTIAL);
+ if (!b->map)
+ {
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ b->position = 0;
+ *b->buffer = 0;
+ *b->unread = 0;
+ b->last_buffer = 0;
+ b->unread_len = 0;
+
+ len = pmaps_buffer_plain_update(b);
+
+ if (len < 3)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ eina_file_map_free(b->file, b->map);
+ b->map = NULL;
+ return EINA_FALSE;
+ }
+
+ /* copy the type */
+ b->type[0] = b->buffer[0];
+ b->type[1] = b->buffer[1];
+ b->type[2] = 0;
+ /* skip the PX */
+ b->current = b->buffer + 2;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+}
+
+static void
+pmaps_buffer_close(Pmaps_Buffer *b)
+{
+ if (b->file)
+ {
+ if (b->map) eina_file_map_free(b->file, b->map);
+ b->map = NULL;
+ b->file = NULL;
+ }
+}
+
+static Eina_Bool
+pmaps_buffer_header_parse(Pmaps_Buffer *b, int *error)
+{
+ /* if there is no P at the beginning it is not a file we can parse */
+ if (b->type[0] != 'P')
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ /* get the width */
+ if (!pmaps_buffer_plain_int_get(b, &(b->w)) || b->w < 1)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ /* get the height */
+ if (!pmaps_buffer_plain_int_get(b, &(b->h)) || b->h < 1)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ /* get the maximum value. P1 and P4 don't have a maximum value. */
+ if (!(b->type[1] == '1' || b->type[1] == '4')
+ && (!pmaps_buffer_plain_int_get(b, &(b->max)) || b->max < 1))
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ /* set up the color get callback */
+ switch (b->type[1])
+ {
+ /* Black and White */
+ case '1':
+ b->color_get = pmaps_buffer_plain_bw_get;
+ break;
+ case '4':
+ /* Binary black and white use another format */
+ b->color_get = NULL;
+ break;
+ case '2':
+ case '5':
+ b->color_get = pmaps_buffer_gray_get;
+ break;
+ case '3':
+ case '6':
+ b->color_get = pmaps_buffer_rgb_get;
+ break;
+ case '7':
+ /* XXX write me */
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ /* set up the int get callback */
+ switch (b->type[1])
+ {
+ /* RAW */
+ case '5':
+ case '6':
+ if (b->max < 256)
+ b->int_get = pmaps_buffer_1byte_int_get;
+ else
+ b->int_get = pmaps_buffer_2byte_int_get;
+
+ if (b->current == b->end && !pmaps_buffer_raw_update(b))
+ return 0;
+
+ b->current++;
+ break;
+ /* Plain */
+ case '2':
+ case '3':
+ b->int_get = pmaps_buffer_plain_int_get;
+ break;
+ /* Black and White Bitmaps don't use that callback */
+ case '1':
+ case '4':
+ b->int_get = NULL;
+ /* we need to skip the next character fpr P4 it
+ * doesn't hurt if we do it for the P1 as well */
+ b->current++;
+ break;
+ }
+ return 1;
+}
+
+static size_t
+pmaps_buffer_plain_update(Pmaps_Buffer *b)
+{
+ size_t r;
+ size_t max;
+
+ /* if we already are in the last buffer we can not update it */
+ if (b->last_buffer)
+ return 0;
+
+ /* if we have unread bytes we need to put them before the new read
+ * stuff */
+ if (b->unread_len)
+ memcpy(b->buffer, b->unread, b->unread_len);
+
+ max = FILE_BUFFER_SIZE - b->unread_len - 1;
+ if (b->position + max > eina_file_size_get(b->file))
+ max = eina_file_size_get(b->file) - b->position;
+
+ memcpy(&b->buffer[b->unread_len], b->map + b->position, max);
+ b->position += max;
+ r = max + b->unread_len;
+
+ /* we haven't read anything nor have we bytes in the unread buffer */
+ if (r == 0)
+ {
+ b->buffer[0] = '\0';
+ b->end = b->buffer;
+ b->last_buffer = 1;
+ return 0;
+ }
+
+ if (r < FILE_BUFFER_SIZE - 1)
+ {
+ /*we reached eof */ ;
+ b->last_buffer = 1;
+ }
+
+ b->buffer[r] = 0;
+
+ b->unread[0] = '\0';
+ b->unread_len = 0;
+
+ b->buffer[r] = '\0';
+ b->current = b->buffer;
+ b->end = b->buffer + r;
+
+ return r;
+}
+
+static size_t
+pmaps_buffer_raw_update(Pmaps_Buffer *b)
+{
+ size_t r;
+ size_t max;
+
+ if (b->last_buffer)
+ return 0;
+
+ if (b->unread_len)
+ memcpy(b->buffer, b->unread, b->unread_len);
+
+ max = FILE_BUFFER_SIZE - b->unread_len;
+ if (b->position + max > eina_file_size_get(b->file))
+ max = eina_file_size_get(b->file) - b->position;
+
+ memcpy(&b->buffer[b->unread_len], b->map + b->position, max);
+ b->position += max;
+ r = max + b->unread_len;
+
+ if (r < FILE_BUFFER_SIZE)
+ {
+ /*we reached eof */
+ b->last_buffer = 1;
+ }
+
+ b->end = b->buffer + r;
+ b->current = b->buffer;
+
+ if (b->unread_len)
+ {
+ /* the buffer is now read */
+ *b->unread = 0;
+ b->unread_len = 0;
+ }
+
+ return r;
+}
+
+static int
+pmaps_buffer_plain_int_get(Pmaps_Buffer *b, int *val)
+{
+ char *start;
+ DATA8 lastc;
+
+ /* first skip all white space
+ * Note: we are skipping here actually every character than is not
+ * a digit */
+ while (!isdigit(*b->current))
+ {
+ if (*b->current == '\0')
+ {
+ if (!pmaps_buffer_plain_update(b))
+ return 0;
+
+ continue;
+ }
+ if (*b->current == '#' && !pmaps_buffer_comment_skip(b))
+ return 0;
+ b->current++;
+ }
+
+ start = (char *)b->current;
+ /* now find the end of the number */
+ while (isdigit(*b->current))
+ b->current++;
+
+ lastc = *b->current;
+ *b->current = '\0';
+ *val = atoi(start);
+ *b->current = lastc;
+
+ return 1;
+}
+
+static int
+pmaps_buffer_1byte_int_get(Pmaps_Buffer *b, int *val)
+{
+ /* are we at the end of the buffer? */
+ if (b->current == b->end && !pmaps_buffer_raw_update(b))
+ return 0;
+
+ *val = *b->current;
+ b->current++;
+
+ return 1;
+}
+static int
+pmaps_buffer_2byte_int_get(Pmaps_Buffer *b, int *val)
+{
+ /* are we at the end of the buffer? */
+ if (b->current == b->end && !pmaps_buffer_raw_update(b))
+ return 0;
+
+ *val = (int)(*b->current << 8);
+ b->current++;
+
+ /* are we at the end of the buffer? */
+ if (b->current == b->end && !pmaps_buffer_raw_update(b))
+ return 0;
+
+ *val |= *b->current;
+ b->current++;
+
+ return 1;
+}
+
+static int
+pmaps_buffer_comment_skip(Pmaps_Buffer *b)
+{
+ while (*b->current != '\n')
+ {
+ if (*b->current == '\0')
+ {
+ if (!pmaps_buffer_plain_update(b))
+ return 0;
+
+ continue;
+ }
+ b->current++;
+ }
+ return 1;
+}
+
+static int
+pmaps_buffer_rgb_get(Pmaps_Buffer *b, DATA32 *color)
+{
+ int vr, vg, vb;
+
+ if (!b->int_get(b, &vr) || !b->int_get(b, &vg) || !b->int_get(b, &vb))
+ return 0;
+
+ if (b->max != 255)
+ {
+ vr = (vr * 255) / b->max;
+ vg = (vg * 255) / b->max;
+ vb = (vb * 255) / b->max;
+ }
+ if (vr > 255)
+ vr = 255;
+ if (vg > 255)
+ vg = 255;
+ if (vb > 255)
+ vb = 255;
+
+ *color = ARGB_JOIN(0xff, vr, vg, vb);
+
+ return 1;
+}
+
+static int
+pmaps_buffer_gray_get(Pmaps_Buffer *b, DATA32 *color)
+{
+ int val;
+
+ if (!b->int_get(b, &val))
+ return 0;
+
+ if (b->max != 255)
+ val = (val * 255) / b->max;
+ if (val > 255)
+ val = 255;
+ *color = ARGB_JOIN(0xff, val, val, val);
+
+ return 1;
+}
+
+static int
+pmaps_buffer_plain_bw_get(Pmaps_Buffer *b, DATA32 *val)
+{
+ /* first skip all white space
+ * Note: we are skipping here actually every character than is not
+ * a digit */
+ while (!isdigit(*b->current))
+ {
+ if (*b->current == '\0')
+ {
+ if (!pmaps_buffer_raw_update(b))
+ return 0;
+
+ continue;
+ }
+ if (*b->current == '#' && !pmaps_buffer_comment_skip(b))
+ return 0;
+ b->current++;
+ }
+
+ if (*b->current == '0')
+ *val = 0xffffffff;
+ else
+ *val = 0xff000000;
+
+ b->current++;
+
+ return 1;
+}
+
+/* external functions */
+Evas_Image_Load_Func evas_image_load_pmaps_func = {
+ evas_image_load_file_open_pmaps,
+ evas_image_load_file_close_pmaps,
+ evas_image_load_file_head_pmaps,
+ evas_image_load_file_data_pmaps,
+ NULL,
+ EINA_TRUE,
+ EINA_FALSE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em)
+ return 0;
+ em->functions = (void *)(&evas_image_load_pmaps_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+}
+
+static Evas_Module_Api evas_modapi = {
+ EVAS_MODULE_API_VERSION,
+ "pmaps",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, pmaps);
+
+#ifndef EVAS_STATIC_BUILD_PMAPS
+EVAS_EINA_MODULE_DEFINE(image_loader, pmaps);
+#endif
diff --git a/src/modules/evas/image_loaders/png/evas_image_load_png.c b/src/modules/evas/image_loaders/png/evas_image_load_png.c
new file mode 100644
index 0000000000..a8e9aa3288
--- /dev/null
+++ b/src/modules/evas/image_loaders/png/evas_image_load_png.c
@@ -0,0 +1,467 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <png.h>
+#include <setjmp.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_common_private.h"
+#include "evas_private.h"
+
+#define PNG_BYTES_TO_CHECK 4
+
+typedef struct _Evas_PNG_Info Evas_PNG_Info;
+struct _Evas_PNG_Info
+{
+ unsigned char *map;
+ size_t length;
+ size_t position;
+};
+
+typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
+struct _Evas_Loader_Internal
+{
+ Eina_File *f;
+ Evas_Image_Load_Opts *opts;
+};
+
+static const Evas_Colorspace cspace_grey[2] = {
+ EVAS_COLORSPACE_GRY8,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static const Evas_Colorspace cspace_grey_alpha[2] = {
+ EVAS_COLORSPACE_AGRY88,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static void
+_evas_image_png_read(png_structp png_ptr, png_bytep out, png_size_t count)
+{
+ Evas_PNG_Info *epi = png_get_io_ptr(png_ptr);
+
+ if (!epi) return;
+ if (epi->position == epi->length) return;
+
+ if (epi->position + count > epi->length) count = epi->length - epi->position;
+ memcpy(out, epi->map + epi->position, count);
+ epi->position += count;
+}
+
+static void *
+evas_image_load_file_open_png(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
+ Evas_Image_Load_Opts *opts,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error)
+{
+ Evas_Loader_Internal *loader;
+
+ loader = calloc(1, sizeof (Evas_Loader_Internal));
+ if (!loader)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return NULL;
+ }
+
+ loader->f = f;
+ loader->opts = opts;
+ return loader;
+}
+
+static void
+evas_image_load_file_close_png(void *loader_data)
+{
+ free(loader_data);
+}
+
+static Eina_Bool
+evas_image_load_file_head_png(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+ Evas_Image_Load_Opts *opts;
+ Eina_File *f;
+
+ Evas_PNG_Info epi;
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ png_uint_32 w32, h32;
+ int bit_depth, color_type, interlace_type;
+ char hasa;
+ Eina_Bool r = EINA_FALSE;
+
+ opts = loader->opts;
+ f = loader->f;
+
+ hasa = 0;
+ epi.map = eina_file_map_all(f, EINA_FILE_RANDOM);
+ if (!epi.map)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto close_file;
+ }
+ epi.length = eina_file_size_get(f);
+ epi.position = 0;
+
+ if (epi.length < PNG_BYTES_TO_CHECK)
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto close_file;
+ }
+
+ if (png_sig_cmp(epi.map, 0, PNG_BYTES_TO_CHECK))
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto close_file;
+ }
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+
+ png_set_read_fn(png_ptr, &epi, _evas_image_png_read);
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto close_file;
+ }
+
+ png_read_info(png_ptr, info_ptr);
+ png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32),
+ (png_uint_32 *) (&h32), &bit_depth, &color_type,
+ &interlace_type, NULL, NULL);
+ if ((w32 < 1) || (h32 < 1) || (w32 > IMG_MAX_SIZE) || (h32 > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(w32, h32))
+ {
+ if (IMG_TOO_BIG(w32, h32))
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ else
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+ if (opts->scale_down_by > 1)
+ {
+ prop->w = (int) w32 / opts->scale_down_by;
+ prop->h = (int) h32 / opts->scale_down_by;
+ if ((prop->w < 1) || (prop->h < 1))
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+ }
+ else
+ {
+ prop->w = (int) w32;
+ prop->h = (int) h32;
+ }
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) hasa = 1;
+ switch (color_type)
+ {
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ hasa = 1;
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ hasa = 1;
+ prop->cspaces = cspace_grey_alpha;
+ break;
+ case PNG_COLOR_TYPE_GRAY:
+ if (!hasa) prop->cspaces = cspace_grey;
+ break;
+ }
+ if (hasa) prop->alpha = 1;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ r = EINA_TRUE;
+
+ close_file:
+ if (png_ptr) png_destroy_read_struct(&png_ptr,
+ info_ptr ? &info_ptr : NULL,
+ NULL);
+ if (epi.map) eina_file_map_free(f, epi. map);
+
+ return r;
+}
+
+static Eina_Bool
+evas_image_load_file_data_png(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+ Evas_Image_Load_Opts *opts;
+ Eina_File *f;
+
+ unsigned char *surface;
+ unsigned char *tmp_line;
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ Evas_PNG_Info epi;
+ png_uint_32 w32, h32;
+ unsigned int pack_offset;
+ int w, h;
+ int bit_depth, color_type, interlace_type;
+ char hasa, passes;
+ int i, j, p, k;
+ int scale_ratio = 1, image_w = 0, image_h = 0;
+ Eina_Bool r = EINA_FALSE;
+
+ opts = loader->opts;
+ f = loader->f;
+
+ hasa = 0;
+
+ epi.map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (!epi.map)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto close_file;
+ }
+ epi.length = eina_file_size_get(f);
+ epi.position = 0;
+
+ if (epi.length < PNG_BYTES_TO_CHECK)
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto close_file;
+ }
+
+ /* if we havent read the header before, set the header data */
+ if (png_sig_cmp(epi.map, 0, PNG_BYTES_TO_CHECK))
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto close_file;
+ }
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto close_file;
+ }
+
+ png_set_read_fn(png_ptr, &epi, _evas_image_png_read);
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto close_file;
+ }
+
+ png_read_info(png_ptr, info_ptr);
+ png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32),
+ (png_uint_32 *) (&h32), &bit_depth, &color_type,
+ &interlace_type, NULL, NULL);
+ image_w = w32;
+ image_h = h32;
+ if (opts->scale_down_by > 1)
+ {
+ scale_ratio = opts->scale_down_by;
+ w32 /= scale_ratio;
+ h32 /= scale_ratio;
+ }
+ if (prop->w != w32 ||
+ prop->h != h32)
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+
+ surface = pixels;
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ {
+ /* expand transparency entry -> alpha channel if present */
+ png_set_tRNS_to_alpha(png_ptr);
+ hasa = 1;
+ }
+ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) hasa = 1;
+ if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) hasa = 1;
+ if (hasa) prop->alpha = 1;
+
+ /* Prep for transformations... ultimately we want ARGB */
+ /* expand palette -> RGB if necessary */
+ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr);
+ /* expand gray (w/reduced bits) -> 8-bit RGB if necessary */
+ if ((color_type == PNG_COLOR_TYPE_GRAY) ||
+ (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
+ {
+ if (prop->cspace == EVAS_COLORSPACE_ARGB8888)
+ png_set_gray_to_rgb(png_ptr);
+ if (bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr);
+ }
+ /* reduce 16bit color -> 8bit color if necessary */
+ if (bit_depth > 8) png_set_strip_16(png_ptr);
+ /* pack all pixels to byte boundaries */
+ png_set_packing(png_ptr);
+
+ w = w32;
+ h = h32;
+
+ switch (prop->cspace)
+ {
+ case EVAS_COLORSPACE_ARGB8888:
+ /* we want ARGB */
+#ifdef WORDS_BIGENDIAN
+ png_set_swap_alpha(png_ptr);
+ if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE);
+#else
+ png_set_bgr(png_ptr);
+ if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+#endif
+ pack_offset = sizeof(DATA32);
+ break;
+ case EVAS_COLORSPACE_AGRY88:
+ /* we want AGRY */
+#ifdef WORDS_BIGENDIAN
+ png_set_swap_alpha(png_ptr);
+ if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE);
+#else
+ if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+#endif
+ pack_offset = sizeof(DATA16);
+ break;
+ case EVAS_COLORSPACE_GRY8: pack_offset = sizeof(DATA8); break;
+ default: abort();
+ }
+
+ passes = png_set_interlace_handling(png_ptr);
+
+ /* we read image line by line if scale down was set */
+ if (scale_ratio == 1)
+ {
+ for (p = 0; p < passes; p++)
+ {
+ for (i = 0; i < h; i++)
+ png_read_row(png_ptr, surface + (i * w * pack_offset), NULL);
+ }
+ png_read_end(png_ptr, info_ptr);
+ }
+ else
+ {
+ unsigned char *src_ptr, *dst_ptr;
+
+ dst_ptr = surface;
+ if (passes == 1)
+ {
+ tmp_line = (unsigned char *) alloca(image_w * pack_offset);
+ for (i = 0; i < h; i++)
+ {
+ png_read_row(png_ptr, tmp_line, NULL);
+ src_ptr = tmp_line;
+ for (j = 0; j < w; j++)
+ {
+ for (k = 0; k < (int)pack_offset; k++)
+ dst_ptr[k] = src_ptr[k];
+ dst_ptr += pack_offset;
+ src_ptr += scale_ratio * pack_offset;
+ }
+ for (j = 0; j < (scale_ratio - 1); j++)
+ png_read_row(png_ptr, tmp_line, NULL);
+ }
+ }
+ else
+ {
+ unsigned char *pixels2 = malloc(image_w * image_h * pack_offset);
+
+ if (pixels2)
+ {
+ for (p = 0; p < passes; p++)
+ {
+ for (i = 0; i < image_h; i++)
+ png_read_row(png_ptr, pixels2 + (i * image_w * pack_offset), NULL);
+ }
+
+ for (i = 0; i < h; i++)
+ {
+ src_ptr = pixels2 + (i * scale_ratio * image_w * pack_offset);
+ for (j = 0; j < w; j++)
+ {
+ for (k = 0; k < (int)pack_offset; k++)
+ dst_ptr[k] = src_ptr[k];
+ src_ptr += scale_ratio * pack_offset;
+ dst_ptr += pack_offset;
+ }
+ }
+ free(pixels2);
+ }
+ }
+ }
+
+ prop->premul = EINA_TRUE;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ r = EINA_TRUE;
+
+ close_file:
+ if (png_ptr) png_destroy_read_struct(&png_ptr,
+ info_ptr ? &info_ptr : NULL,
+ NULL);
+ if (epi.map) eina_file_map_free(f, epi.map);
+ return r;
+}
+
+static Evas_Image_Load_Func evas_image_load_png_func =
+{
+ evas_image_load_file_open_png,
+ evas_image_load_file_close_png,
+ evas_image_load_file_head_png,
+ evas_image_load_file_data_png,
+ NULL,
+ EINA_TRUE,
+ EINA_FALSE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ em->functions = (void *)(&evas_image_load_png_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "png",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, png);
+
+#ifndef EVAS_STATIC_BUILD_PNG
+EVAS_EINA_MODULE_DEFINE(image_loader, png);
+#endif
diff --git a/src/modules/evas/image_loaders/psd/evas_image_load_psd.c b/src/modules/evas/image_loaders/psd/evas_image_load_psd.c
new file mode 100644
index 0000000000..1554e18821
--- /dev/null
+++ b/src/modules/evas/image_loaders/psd/evas_image_load_psd.c
@@ -0,0 +1,937 @@
+#define _XOPEN_SOURCE 600
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_common_private.h"
+#include "evas_private.h"
+
+typedef struct _PSD_Header PSD_Header;
+
+typedef enum _PSD_Mode
+ {
+ PSD_GREYSCALE = 1,
+ PSD_INDEXED = 2,
+ PSD_RGB = 3,
+ PSD_CMYK = 4
+ } PSD_Mode;
+
+struct _PSD_Header
+{
+ unsigned char signature[4];
+ unsigned short version;
+ unsigned char reserved[9];
+ unsigned short channels;
+ unsigned int height;
+ unsigned int width;
+ unsigned short depth;
+
+ unsigned short channel_num;
+
+ PSD_Mode mode;
+};
+
+enum {
+ READ_COMPRESSED_SUCCESS,
+ READ_COMPRESSED_ERROR_FILE_CORRUPT,
+ READ_COMPRESSED_ERROR_FILE_READ_ERROR
+};
+
+static Eina_Bool get_compressed_channels_length(PSD_Header *Head,
+ const unsigned char *map, size_t length, size_t *position,
+ unsigned short *rle_table,
+ unsigned int *chanlen);
+
+static int
+read_ushort(const unsigned char *map, size_t length, size_t *position, unsigned short *ret)
+{
+ if (*position + 2 > length) return 0;
+ // FIXME: need to check order
+ *ret = (map[(*position) + 0] << 8) | map[(*position) + 1];
+ *position += 2;
+ return 1;
+}
+
+static int
+read_uint(const unsigned char *map, size_t length, size_t *position, unsigned int *ret)
+{
+ if (*position + 4 > length) return 0;
+ // FIXME: need to check order
+ *ret = ARGB_JOIN(map[(*position) + 0], map[(*position) + 1], map[(*position) + 2], map[(*position) + 3]);
+ *position += 4;
+ return 1;
+}
+
+static int
+read_block(const unsigned char *map, size_t length, size_t *position, void *target, size_t size)
+{
+ if (*position + size > length) return 0;
+ memcpy(target, map + *position, size);
+ *position += size;
+ return 1;
+}
+
+// Internal function used to get the Psd header from the current file.
+Eina_Bool
+psd_get_header(PSD_Header *header, const unsigned char *map, size_t length, size_t *position)
+{
+ unsigned short tmp;
+
+#define CHECK_RET(Call) \
+ if (!Call) return EINA_FALSE;
+
+ CHECK_RET(read_block(map, length, position, header->signature, 4));
+ CHECK_RET(read_ushort(map, length, position, &header->version));
+ CHECK_RET(read_block(map, length, position, header->reserved, 6));
+ CHECK_RET(read_ushort(map, length, position, &header->channels));
+ CHECK_RET(read_uint(map, length, position, &header->height));
+ CHECK_RET(read_uint(map, length, position, &header->width));
+ CHECK_RET(read_ushort(map, length, position, &header->depth));
+
+ CHECK_RET(read_ushort(map, length, position, &tmp));
+ header->mode = tmp;
+
+#undef CHECK_RET
+
+ /* fprintf(stderr, "<<<<<<<<<<<\nsignature : %c%c%c%c\n", */
+ /* header->signature[0], */
+ /* header->signature[1], */
+ /* header->signature[2], */
+ /* header->signature[3]); */
+ /* fprintf(stderr, "version : %i\n", header->version); */
+ /* fprintf(stderr, "channels : %i\n", header->channels); */
+ /* fprintf(stderr, "width x height : %dx%d\n", header->width, header->height); */
+ /* fprintf(stderr, "depth : %i\n", header->depth); */
+ /* fprintf(stderr, "mode : %i\n>>>>>>>>>>>>\n", header->mode); */
+
+ return EINA_TRUE;
+}
+
+
+// Internal function used to check if the HEADER is a valid Psd header.
+Eina_Bool
+is_psd(PSD_Header *header)
+{
+ if (strncmp((char*)header->signature, "8BPS", 4))
+ return EINA_FALSE;
+ if (header->version != 1)
+ return EINA_FALSE;
+ if (header->channels < 1 || header->channels > 24)
+ return EINA_FALSE;
+ if (header->height < 1 || header->width < 1)
+ return EINA_FALSE;
+ if (header->depth != 1 && header->depth != 8 && header->depth != 16)
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+}
+
+static void *
+evas_image_load_file_open_psd(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
+ Evas_Image_Load_Opts *opts EINA_UNUSED,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error EINA_UNUSED)
+{
+ return f;
+}
+
+static void
+evas_image_load_file_close_psd(void *loader_data EINA_UNUSED)
+{
+}
+
+static Eina_Bool
+evas_image_load_file_head_psd(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Eina_File *f = loader_data;
+ void *map;
+ size_t length;
+ size_t position;
+ PSD_Header header;
+ Eina_Bool correct;
+ Eina_Bool r = EINA_FALSE;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+
+ map = eina_file_map_all(f, EINA_FILE_RANDOM);
+ length = eina_file_size_get(f);
+ position = 0;
+ if (!map || length < 1)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error;
+ }
+
+ correct = psd_get_header(&header, map, length, &position);
+ if (!correct || !is_psd(&header))
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto on_error;
+ }
+
+ prop->w = header.width;
+ prop->h = header.height;
+ if (header.channels != 3)
+ prop->alpha = 1;
+
+ r = EINA_TRUE;
+
+ on_error:
+ eina_file_map_free(f, map);
+ return r;
+}
+
+static unsigned int
+read_compressed_channel(const unsigned char *map, size_t length, size_t *position,
+ const unsigned int channel_length EINA_UNUSED,
+ unsigned int size,
+ unsigned char* channel)
+{
+ // FIXME: what does channel_length means, and why is it not used
+ unsigned int i;
+ char headbyte, c;
+
+#define CHECK_RET(Call) \
+ if (!Call) return READ_COMPRESSED_ERROR_FILE_READ_ERROR; \
+
+ for (i = 0; i < size; )
+ {
+ CHECK_RET(read_block(map, length, position, &headbyte, 1));
+
+ if (headbyte >= 0)
+ {
+ if (i + headbyte > size)
+ return READ_COMPRESSED_ERROR_FILE_CORRUPT;
+ CHECK_RET(read_block(map, length, position, channel + i, headbyte + 1));
+
+ i += headbyte + 1;
+ }
+ else if (headbyte >= -127 && headbyte <= -1)
+ {
+ int run;
+
+ CHECK_RET(read_block(map, length, position, &c, 1));
+
+ run = c;
+ /* if (run == -1) */
+ /* return READ_COMPRESSED_ERROR_FILE_READ_ERROR; */
+
+ if (i + (-headbyte + 1) > size)
+ return READ_COMPRESSED_ERROR_FILE_CORRUPT;
+
+ memset(channel + i, run, -headbyte + 1);
+ i += -headbyte + 1;
+ }
+ }
+
+#undef CHECK_RET
+
+ return READ_COMPRESSED_SUCCESS;
+}
+
+
+Eina_Bool
+psd_get_data(PSD_Header *head,
+ const unsigned char *map, size_t length, size_t *position,
+ unsigned char *buffer, Eina_Bool compressed,
+ int *error)
+{
+ unsigned int c, x, y, numchan, bps, bpc, bpp;
+ unsigned int pixels_count;
+ unsigned char *channel = NULL;
+ unsigned char *data = NULL;
+
+ // Added 01-07-2009: This is needed to correctly load greyscale and
+ // paletted images.
+ switch (head->mode)
+ {
+ case PSD_GREYSCALE:
+ case PSD_INDEXED:
+ numchan = 1;
+ break;
+ default:
+ numchan = 3;
+ }
+
+ bpp = head->channels;
+ bpc = head->depth / 8;
+ pixels_count = head->width * head->height;
+
+ data = malloc(sizeof (unsigned char) * pixels_count * bpp);
+ if (!data) return EINA_FALSE;
+
+ channel = malloc(sizeof (unsigned char) * pixels_count * bpc);
+ if (!channel)
+ {
+ free(data);
+ return EINA_FALSE;
+ }
+
+ bps = head->width * head->channels * bpc;
+ // @TODO: Add support for this in, though I have yet to run across a .psd
+ // file that uses this.
+ if (compressed && bpc == 2)
+ {
+ free(data);
+ free(channel);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+#define CHECK_RET(Call) \
+ if (!Call) \
+ { \
+ free(data); \
+ free(channel); \
+ return EINA_FALSE; \
+ }
+
+ if (!compressed)
+ {
+ if (bpc == 1)
+ {
+ for (c = 0; c < numchan; c++)
+ {
+ unsigned char *tmp = channel;
+
+ CHECK_RET(read_block(map, length, position, tmp, pixels_count));
+
+ for (y = 0; y < head->height * bps; y += bps)
+ {
+ for (x = 0; x < bps; x += bpp, tmp++)
+ {
+ data[y + x + c] = *tmp;
+ }
+ }
+ }
+
+ // Accumulate any remaining channels into a single alpha channel
+ //@TODO: This needs to be changed for greyscale images.
+ for (; c < head->channels; c++)
+ {
+ unsigned char *tmp = channel;
+
+ CHECK_RET(read_block(map, length, position, channel, pixels_count));
+
+ for (y = 0; y < head->height * bps; y += bps)
+ {
+ for (x = 0; x < bps; x += bpp, tmp++)
+ {
+ unsigned short newval;
+
+ // previous formula was : (old / 255 * new / 255) * 255
+ newval = (*tmp) * data[y + x + 3];
+
+ data[y + x + 3] = newval >> 8;
+ }
+ }
+ }
+ }
+ else
+ {
+ int bps2;
+
+ bps2 = bps / 2;
+
+ // iCurImage->Bpc == 2
+ for (c = 0; c < numchan; c++)
+ {
+ unsigned short *shortptr = (unsigned short*) channel;
+
+ CHECK_RET(read_block(map, length, position, channel, pixels_count * 2));
+
+ for (y = 0; y < head->height * bps2; y += bps2)
+ {
+ for (x = 0; x < (unsigned int)bps2; x += bpp, shortptr++)
+ {
+ ((unsigned short*)data)[y + x + c] = *shortptr;
+ }
+ }
+ }
+
+ // Accumulate any remaining channels into a single alpha channel
+ //@TODO: This needs to be changed for greyscale images.
+ for (; c < head->channels; c++)
+ {
+ unsigned short *shortptr = (unsigned short*) channel;
+
+ CHECK_RET(read_block(map, length, position, channel, pixels_count * 2));
+
+ for (y = 0; y < head->height * bps2; y += bps2)
+ {
+ for (x = 0; x < (unsigned int)bps2; x += bpp, shortptr++)
+ {
+ unsigned int newval;
+
+ newval = *shortptr * ((unsigned short*)data)[y + x + 3];
+
+ ((unsigned short*)data)[y + x + 3] = newval >> 16;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ unsigned short *rle_table;
+ unsigned int *chanlen;
+
+ rle_table = alloca(head->height * head->channel_num * sizeof (unsigned short));
+ chanlen = alloca(head->channel_num * sizeof (unsigned int));
+ if (!get_compressed_channels_length(head, map, length, position, rle_table, chanlen))
+ goto file_read_error;
+
+ for (c = 0; c < numchan; c++)
+ {
+ unsigned char *tmp = channel;
+ int err;
+
+ err = read_compressed_channel(map, length, position,
+ chanlen[c],
+ pixels_count,
+ channel);
+ if (err == READ_COMPRESSED_ERROR_FILE_CORRUPT)
+ goto file_corrupt;
+ else if (err == READ_COMPRESSED_ERROR_FILE_READ_ERROR)
+ goto file_read_error;
+
+ for (y = 0; y < head->height * bps; y += bps)
+ {
+ for (x = 0; x < bps; x += bpp, tmp++)
+ {
+ data[y + x + c] = *tmp;
+ }
+ }
+ }
+
+ // Initialize the alpha channel to solid
+ //@TODO: This needs to be changed for greyscale images.
+ if (head->channels >= 4)
+ {
+ for (y = 0; y < head->height * bps; y += bps)
+ {
+ for (x = 0; x < bps; x += bpp)
+ {
+ data[y + x + 3] = 255;
+ }
+ }
+
+ for (; c < head->channels; c++)
+ {
+ unsigned char *tmp = channel;
+ int err;
+
+ err = read_compressed_channel(map, length, position,
+ chanlen[c],
+ pixels_count,
+ channel);
+ if (err == READ_COMPRESSED_ERROR_FILE_CORRUPT)
+ goto file_corrupt;
+ else if (err == READ_COMPRESSED_ERROR_FILE_READ_ERROR)
+ goto file_read_error;
+
+ for (y = 0; y < head->height * bps; y += bps)
+ {
+ for (x = 0; x < bps; x += bpp, tmp++)
+ {
+ unsigned short newval;
+
+ newval = *tmp * data[y + x + 3];
+
+ data[y + x + 3] = newval >> 8;
+ }
+ }
+ }
+ }
+ }
+
+ if (bpp == 3)
+ {
+ for (x = 0; x < pixels_count; x++)
+ {
+ buffer[x * 4 + 0] = data[x * 3 + 2];
+ buffer[x * 4 + 1] = data[x * 3 + 1];
+ buffer[x * 4 + 2] = data[x * 3 + 0];
+ buffer[x * 4 + 3] = 255;
+ }
+ }
+ else
+ {
+ // BRGA to RGBA
+ for (x= 0; x < pixels_count; x++)
+ {
+ buffer[x * 4 + 0] = data[x * 4 + 2];
+ buffer[x * 4 + 1] = data[x * 4 + 1];
+ buffer[x * 4 + 2] = data[x * 4 + 0];
+ buffer[x * 4 + 3] = data[x * 4 + 3];
+ }
+ }
+
+ free(channel);
+ free(data);
+ return EINA_TRUE;
+
+#undef CHECK_RET
+
+ file_corrupt:
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+ file_read_error:
+ free(channel);
+ free(data);
+
+ return EINA_FALSE;
+}
+
+
+Eina_Bool
+get_single_channel(PSD_Header *head,
+ const unsigned char *map, size_t length, size_t *position,
+ unsigned char *buffer,
+ Eina_Bool compressed)
+{
+ unsigned int i, bpc;
+ char headbyte;
+ int c;
+ int pixels_count;
+
+ bpc = (head->depth / 8);
+ pixels_count = head->width * head->height;
+
+#define CHECK_RET(Call) \
+ if (!Call) return EINA_FALSE;
+
+ if (!compressed)
+ {
+ if (bpc == 1)
+ {
+ CHECK_RET(read_block(map, length, position, buffer, pixels_count));
+ }
+ else
+ { // Bpc == 2
+ CHECK_RET(read_block(map, length, position, buffer, pixels_count * 2));
+ }
+ }
+ else
+ {
+ for (i = 0; i < (unsigned int)pixels_count; )
+ {
+ CHECK_RET(read_block(map, length, position, &headbyte, 1));
+
+ if (headbyte >= 0)
+ { // && HeadByte <= 127
+ CHECK_RET(read_block(map, length, position, buffer + i, headbyte + 1));
+
+ i += headbyte + 1;
+ }
+ if (headbyte >= -127 && headbyte <= -1)
+ {
+ int run;
+
+ CHECK_RET(read_block(map, length, position, &c, 1));
+
+ run = c;
+ if (run == -1) return EINA_FALSE;
+
+ memset(buffer + i, run, -headbyte + 1);
+ i += -headbyte + 1;
+ }
+ }
+ }
+
+#undef CHECK_RET
+
+ return EINA_TRUE;
+}
+
+Eina_Bool
+read_psd_grey(void *pixels, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
+{
+ unsigned int color_mode, resource_size, misc_info;
+ unsigned short compressed;
+
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+#define CHECK_RET(Call) \
+ if (!Call) return EINA_FALSE;
+
+ CHECK_RET(read_uint(map, length, position, &color_mode));
+ // Skip over the 'color mode data section'
+ *position += color_mode;
+
+ CHECK_RET(read_uint(map, length, position, &resource_size));
+ // Read the 'image resources section'
+ *position += resource_size;
+
+ CHECK_RET(read_uint(map, length, position, &misc_info));
+ *position += misc_info;
+
+ CHECK_RET(read_ushort(map, length, position, &compressed));
+
+ head->channel_num = head->channels;
+ // Temporary to read only one channel...some greyscale .psd files have 2.
+ head->channels = 1;
+
+ switch (head->depth)
+ {
+ case 8:
+ case 16:
+ break;
+ default:
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ if (!psd_get_data(head, map, length, position, pixels, compressed, error))
+ goto cleanup_error;
+
+ return EINA_TRUE;
+
+#undef CHECK_RET
+
+ cleanup_error:
+ return EINA_FALSE;
+}
+
+
+Eina_Bool
+read_psd_indexed(void *pixels, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
+{
+ unsigned int color_mode, resource_size, misc_info;
+ unsigned short compressed;
+
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+#define CHECK_RET(Call) \
+ if (!(Call)) return EINA_FALSE;
+
+ CHECK_RET(read_uint(map, length, position, &color_mode));
+ CHECK_RET(!(color_mode % 3));
+ /*
+ Palette = (unsigned char*)malloc(Colormode);
+ if (Palette == NULL)
+ return EINA_FALSE;
+ if (fread(&Palette, 1, Colormode, file) != Colormode)
+ goto cleanup_error;
+ */
+ // Skip over the 'color mode data section'
+ *position += color_mode;
+
+ // Read the 'image resources section'
+ CHECK_RET(read_uint(map, length, position, &resource_size));
+ *position += resource_size;
+
+ CHECK_RET(read_uint(map, length, position, &misc_info));
+ *position += misc_info;
+
+ CHECK_RET(read_ushort(map, length, position, &compressed));
+
+ if (head->channels != 1 || head->depth != 8)
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+ head->channel_num = head->channels;
+
+ if (!psd_get_data(head, map, length, position, pixels, compressed, error))
+ return EINA_FALSE;
+ return EINA_TRUE;
+
+#undef CHECK_RET
+}
+
+Eina_Bool
+read_psd_rgb(void *pixels, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
+{
+ unsigned int color_mode, resource_size, misc_info;
+ unsigned short compressed;
+
+#define CHECK_RET(Call) \
+ if (!Call) return EINA_FALSE;
+
+ CHECK_RET(read_uint(map, length, position, &color_mode));
+ // Skip over the 'color mode data section'
+ *position += color_mode;
+
+ // Read the 'image resources section'
+ CHECK_RET(read_uint(map, length, position, &resource_size));
+ *position += resource_size;
+
+ CHECK_RET(read_uint(map, length, position, &misc_info));
+ *position += misc_info;
+
+ CHECK_RET(read_ushort(map, length, position, &compressed));
+
+ head->channel_num = head->channels;
+
+ switch (head->depth)
+ {
+ case 8:
+ case 16:
+ break;
+ default:
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ if (!psd_get_data(head, map, length, position, pixels, compressed, error))
+ return EINA_FALSE;
+
+ return EINA_TRUE;
+
+#undef CHECK_RET
+}
+
+Eina_Bool
+read_psd_cmyk(Evas_Image_Property *prop, void *pixels, PSD_Header *head, const unsigned char *map, size_t length, size_t *position, int *error)
+{
+ unsigned int color_mode, resource_size, misc_info, size, j, data_size;
+ unsigned short compressed;
+ unsigned int format, type;
+ unsigned char *kchannel = NULL;
+ Eina_Bool r = EINA_FALSE;
+
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+#define CHECK_RET(Call) \
+ if (!Call) return EINA_FALSE;
+
+ CHECK_RET(read_uint(map, length, position, &color_mode));
+ // Skip over the 'color mode data section'
+ *position += color_mode;
+
+ CHECK_RET(read_uint(map, length, position, &resource_size));
+ // Read the 'image resources section'
+ *position += resource_size;
+
+ CHECK_RET(read_uint(map, length, position, &misc_info));
+ *position += misc_info;
+
+ CHECK_RET(read_ushort(map, length, position, &compressed));
+
+ switch (head->channels)
+ {
+ case 4:
+ format = 0x1907;
+ head->channel_num = 4;
+ head->channels = 3;
+ break;
+ case 5:
+ format = 0x1908;
+ head->channel_num = 5;
+ head->channels = 4;
+ break;
+ default:
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ switch (head->depth)
+ {
+ case 8:
+ type = 1;
+ break;
+ case 16:
+ type = 2;
+ break;
+ default:
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ if (!psd_get_data(head, map, length, position, pixels, compressed, error))
+ goto cleanup_error;
+
+ size = type * prop->w * prop->h;
+ kchannel = malloc(size);
+ if (kchannel == NULL)
+ goto cleanup_error;
+ if (!get_single_channel(head, map, length, position, kchannel, compressed))
+ goto cleanup_error;
+
+ data_size = head->channels * type * prop->w * prop->h;
+ if (format == 0x1907)
+ {
+ unsigned char *tmp = pixels;
+ const unsigned char *limit = tmp + data_size;
+
+ for (j = 0; tmp < limit; tmp++, j++)
+ {
+ int k;
+
+ for (k = 0; k < 3; k++)
+ *tmp = (*tmp * kchannel[j]) >> 8;
+
+ // FIXME: tmp[i+3] = 255;
+ }
+ }
+ else
+ { // RGBA
+ unsigned char *tmp = pixels;
+ const unsigned char *limit = tmp + data_size;
+
+ // The KChannel array really holds the alpha channel on this one.
+ for (j = 0; tmp < limit; tmp += 4, j++)
+ {
+ tmp[0] = (tmp[0] * tmp[3]) >> 8;
+ tmp[1] = (tmp[1] * tmp[3]) >> 8;
+ tmp[2] = (tmp[2] * tmp[3]) >> 8;
+ tmp[3] = kchannel[j]; // Swap 'K' with alpha channel.
+ }
+ }
+
+ r = EINA_TRUE;
+
+ cleanup_error:
+ free(kchannel);
+ return r;
+}
+
+static Eina_Bool
+evas_image_load_file_data_psd(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Eina_File *f = loader_data;
+
+ void *map;
+ size_t length;
+ size_t position;
+ PSD_Header header;
+ Eina_Bool bpsd = EINA_FALSE;
+
+ map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ length = eina_file_size_get(f);
+ position = 0;
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ if (!map || length < 1)
+ goto on_error;
+
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ if (!psd_get_header(&header, map, length, &position) || !is_psd(&header))
+ goto on_error;
+
+ if (header.width != prop->w ||
+ header.height != prop->h)
+ goto on_error;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+
+ switch (header.mode)
+ {
+ case PSD_GREYSCALE: // Greyscale
+ bpsd = read_psd_grey(pixels, &header, map, length, &position, error);
+ break;
+ case PSD_INDEXED: // Indexed
+ bpsd = read_psd_indexed(pixels, &header, map, length, &position, error);
+ break;
+ case PSD_RGB: // RGB
+ bpsd = read_psd_rgb(pixels, &header, map, length, &position, error);
+ prop->premul = EINA_TRUE;
+ break;
+ case PSD_CMYK: // CMYK
+ bpsd = read_psd_cmyk(prop, pixels, &header, map, length, &position, error);
+ prop->premul = EINA_TRUE;
+ break;
+ default :
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ bpsd = EINA_FALSE;
+ }
+
+ on_error:
+ if (map) eina_file_map_free(f, map);
+
+ return bpsd;
+}
+
+static Eina_Bool
+get_compressed_channels_length(PSD_Header *head,
+ const unsigned char *map, size_t length, size_t *position,
+ unsigned short *rle_table,
+ unsigned int *chanlen)
+{
+ unsigned int j;
+ unsigned int c;
+
+ if (!read_block(map, length, position, rle_table,
+ sizeof (unsigned short) * head->height * head->channel_num))
+ return EINA_FALSE;
+
+ memset(chanlen, 0, head->channel_num * sizeof(unsigned int));
+ for (c = 0; c < head->channel_num; c++)
+ {
+ unsigned int i;
+
+ j = c * head->height;
+ for (i = 0; i < head->height; i++)
+ {
+ chanlen[c] += rle_table[i + j];
+ }
+ }
+
+ return EINA_TRUE;
+}
+
+static const Evas_Image_Load_Func evas_image_load_psd_func = {
+ evas_image_load_file_open_psd,
+ evas_image_load_file_close_psd,
+ evas_image_load_file_head_psd,
+ evas_image_load_file_data_psd,
+ NULL,
+ EINA_TRUE,
+ EINA_FALSE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ em->functions = (void *)(&evas_image_load_psd_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+}
+
+static Evas_Module_Api evas_modapi =
+ {
+ EVAS_MODULE_API_VERSION,
+ "psd",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+ };
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, psd);
+
+
+#ifndef EVAS_STATIC_BUILD_PSD
+EVAS_EINA_MODULE_DEFINE(image_loader, psd);
+#endif
diff --git a/src/modules/evas/image_loaders/tga/evas_image_load_tga.c b/src/modules/evas/image_loaders/tga/evas_image_load_tga.c
new file mode 100644
index 0000000000..74d2c620af
--- /dev/null
+++ b/src/modules/evas/image_loaders/tga/evas_image_load_tga.c
@@ -0,0 +1,593 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_common_private.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 _tga_header tga_header;
+typedef struct _tga_footer tga_footer;
+
+struct _tga_header
+{
+ 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;
+} __attribute__((packed));
+
+struct _tga_footer
+{
+ unsigned int extensionAreaOffset;
+ unsigned int developerDirectoryOffset;
+ char signature[16];
+ char dot;
+ char null;
+} __attribute__((packed));
+
+static void *
+evas_image_load_file_open_tga(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
+ Evas_Image_Load_Opts *opts EINA_UNUSED,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error EINA_UNUSED)
+{
+ return f;
+}
+
+static void
+evas_image_load_file_close_tga(void *loader_data EINA_UNUSED)
+{
+}
+
+static Eina_Bool
+evas_image_load_file_head_tga(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Eina_File *f = loader_data;
+ unsigned char *seg = NULL, *filedata;
+ tga_header *header;
+ tga_footer *footer, tfooter;
+ char hasa = 0;
+ int w, h, bpp;
+ int x, y;
+ Eina_Bool r = EINA_FALSE;
+
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ if (eina_file_size_get(f) < (off_t)(sizeof(tga_header) + sizeof(tga_footer)))
+ goto close_file;
+ seg = eina_file_map_all(f, EINA_FILE_RANDOM);
+ if (seg == NULL) goto close_file;
+ filedata = seg;
+
+ header = (tga_header *)filedata;
+ // no unaligned data accessed, so ok
+ footer = (tga_footer *)(filedata + (eina_file_size_get(f) - sizeof(tga_footer)));
+ memcpy((unsigned char *)(&tfooter),
+ (unsigned char *)footer,
+ sizeof(tga_footer));
+ //printf("0\n");
+ if (!memcmp(tfooter.signature, TGA_SIGNATURE, sizeof(tfooter.signature)))
+ {
+ if ((tfooter.dot == '.') && (tfooter.null == 0))
+ {
+ // footer is there and matches. this is a tga file - any problems now
+ // are a corrupt file
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ }
+ }
+// else goto close_file;
+ //printf("1\n");
+
+ filedata = (unsigned char *)filedata + sizeof(tga_header);
+ 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;
+ if ((bpp == 16) && (header->descriptor & TGA_DESC_ABITS)) hasa = 1;
+ // don't handle colormapped images
+ if ((header->colorMapType) != 0)
+ goto close_file;
+ // if colormap size is anything other than legal sizes or 0 - not real tga
+ if (!((header->colorMapSize == 0) ||
+ (header->colorMapSize == 15) ||
+ (header->colorMapSize == 16) ||
+ (header->colorMapSize == 24) ||
+ (header->colorMapSize == 32)))
+ goto close_file;
+ x = (header->xOriginHi << 8) | (header->xOriginLo);
+ y = (header->yOriginHi << 8) | (header->yOriginLo);
+ w = (header->widthHi << 8) | header->widthLo;
+ h = (header->heightHi << 8) | header->heightLo;
+ // x origin gerater that width, y origin greater than height - wrong file
+ if ((x >= w) || (y >= h))
+ goto close_file;
+ // if descriptor has either of the top 2 bits set... not tga
+ if (header->descriptor & 0xc0)
+ goto close_file;
+
+ if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(w, h))
+ goto close_file;
+
+ prop->w = w;
+ prop->h = h;
+ if (hasa) prop->alpha = 1;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ r = EINA_TRUE;
+
+close_file:
+ if (seg != NULL) eina_file_map_free(f, seg);
+ return r;
+}
+
+static Eina_Bool
+evas_image_load_file_data_tga(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Eina_File *f = loader_data;
+ unsigned char *seg = NULL, *filedata;
+ tga_header *header;
+ tga_footer *footer, tfooter;
+ char hasa = 0, footer_present = 0, vinverted = 0, rle = 0;
+ int w = 0, h = 0, x, y, bpp;
+ off_t size;
+ unsigned int *surface, *dataptr;
+ unsigned int datasize;
+ unsigned char *bufptr, *bufend;
+ int abits;
+ Eina_Bool res = EINA_FALSE;
+
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ if (eina_file_size_get(f) < (off_t)(sizeof(tga_header) + sizeof(tga_footer)))
+ goto close_file;
+ seg = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (seg == NULL) goto close_file;
+ filedata = seg;
+ size = eina_file_size_get(f);
+
+ header = (tga_header *)filedata;
+ // no unaligned data accessed, so ok
+ footer = (tga_footer *)(filedata + (size - sizeof(tga_footer)));
+ memcpy((unsigned char *)&tfooter,
+ (unsigned char *)footer,
+ sizeof(tga_footer));
+ if (!memcmp(tfooter.signature, TGA_SIGNATURE, sizeof(tfooter.signature)))
+ {
+ if ((tfooter.dot == '.') && (tfooter.null == 0))
+ {
+ // footer is there and matches. this is a tga file - any problems now
+ // are a corrupt file
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ footer_present = 1;
+ }
+ }
+
+ filedata = (unsigned 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;
+ if ((bpp == 16) && (header->descriptor & TGA_DESC_ABITS)) hasa = 1;
+ abits = header->descriptor & TGA_DESC_ABITS;
+ // don't handle colormapped images
+ if ((header->colorMapType) != 0)
+ goto close_file;
+ // if colormap size is anything other than legal sizes or 0 - not real tga
+ if (!((header->colorMapSize == 0) ||
+ (header->colorMapSize == 15) ||
+ (header->colorMapSize == 16) ||
+ (header->colorMapSize == 24) ||
+ (header->colorMapSize == 32)))
+ goto close_file;
+ x = (header->xOriginHi << 8) | (header->xOriginLo);
+ y = (header->yOriginHi << 8) | (header->yOriginLo);
+ w = (header->widthHi << 8) | header->widthLo;
+ h = (header->heightHi << 8) | header->heightLo;
+ // x origin gerater that width, y origin greater than height - wrong file
+ if ((x >= w) || (y >= h))
+ goto close_file;
+ // if descriptor has either of the top 2 bits set... not tga
+ if (header->descriptor & 0xc0)
+ goto close_file;
+
+ if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(w, h))
+ goto close_file;
+
+ if ((w != (int)prop->w) || (h != (int)prop->h))
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+ surface = pixels;
+
+ datasize = size - sizeof(tga_header) - header->idLength;
+ if (footer_present)
+ datasize -= sizeof(tga_footer);
+
+ bufptr = filedata + header->idLength;
+ bufend = filedata + datasize;
+
+ 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)
+ {
+ int a = bufptr[3];
+
+ switch (abits)
+ {
+ case 1:
+ a = (a << 7) | (a << 6) | (a << 5) | (a << 4) | (a << 3) | (a << 2) | (a << 1) | (a);
+ case 2:
+ a = (a << 6) | (a << 4) | (a << 2) | (a);
+ case 3:
+ a = (a << 5) | (a << 2) | (a >> 1);
+ case 4:
+ a = (a << 4) | (a);
+ case 5:
+ a = (a << 3) | (a >> 2);
+ case 6:
+ a = (a << 2) | (a >> 4);
+ case 7:
+ a = (a << 1) | (a >> 6);
+ default:
+ break;
+ }
+ *dataptr = ARGB_JOIN(a, bufptr[2], bufptr[1], bufptr[0]);
+ }
+ else
+ *dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
+ dataptr++;
+ bufptr += 4;
+ }
+ break;
+ case 24:
+ for (x = 0; (x < w) && ((bufptr + 3) <= bufend); x++)
+ {
+ *dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], 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 = ARGB_JOIN(a, r, g, b);
+ dataptr++;
+ bufptr += 2;
+ }
+ break;
+ case 8:
+ for (x = 0; (x < w) && ((bufptr + 1) <= bufend); x++)
+ {
+ *dataptr = ARGB_JOIN(0xff, bufptr[0], bufptr[0], 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;
+ int a = bufptr[3];
+
+ switch (abits)
+ {
+ case 1:
+ a = (a << 7) | (a << 6) | (a << 5) | (a << 4) | (a << 3) | (a << 2) | (a << 1) | (a);
+ case 2:
+ a = (a << 6) | (a << 4) | (a << 2) | (a);
+ case 3:
+ a = (a << 5) | (a << 2) | (a >> 1);
+ case 4:
+ a = (a << 4) | (a);
+ case 5:
+ a = (a << 3) | (a >> 2);
+ case 6:
+ a = (a << 2) | (a >> 4);
+ case 7:
+ a = (a << 1) | (a >> 6);
+ default:
+ break;
+ }
+ r = bufptr[2];
+ g = bufptr[1];
+ b = bufptr[0];
+ if (!hasa) a = 0xff;
+ bufptr += 4;
+ for (i = 0; (i < count) && (dataptr < dataend); i++)
+ {
+ *dataptr = ARGB_JOIN(a, r, g, 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 = ARGB_JOIN(0xff, r, g, 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 = ARGB_JOIN(a, r, g, 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 = ARGB_JOIN(0xff, g, g, 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 = ARGB_JOIN(255 - bufptr[3], bufptr[2], bufptr[1], bufptr[0]);
+ *dataptr = ARGB_JOIN(bufptr[3], bufptr[2], bufptr[1], bufptr[0]);
+ else
+ *dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
+ dataptr++;
+ bufptr += 4;
+ }
+ break;
+ case 24:
+ for (i = 0; (i < count) && (bufptr < (bufend - 3)) && (dataptr < dataend); i++)
+ {
+ *dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], 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 = ARGB_JOIN(a, r, g, b);
+ dataptr++;
+ bufptr += 2;
+ }
+ break;
+ case 8:
+ for (i = 0; (i < count) && (bufptr < (bufend - 1)) && (dataptr < dataend); i++)
+ {
+ *dataptr = ARGB_JOIN(0xff, bufptr[0], bufptr[0], 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;
+ }
+ }
+ }
+
+ prop->premul = EINA_TRUE;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ res = EINA_TRUE;
+
+ close_file:
+ if (seg != NULL) eina_file_map_free(f, seg);
+ return res;
+}
+
+static Evas_Image_Load_Func evas_image_load_tga_func =
+{
+ evas_image_load_file_open_tga,
+ evas_image_load_file_close_tga,
+ evas_image_load_file_head_tga,
+ evas_image_load_file_data_tga,
+ NULL,
+ EINA_TRUE,
+ 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 EINA_UNUSED)
+{
+}
+
+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
diff --git a/src/modules/evas/image_loaders/tgv/evas_image_load_tgv.c b/src/modules/evas/image_loaders/tgv/evas_image_load_tgv.c
new file mode 100644
index 0000000000..b715017831
--- /dev/null
+++ b/src/modules/evas/image_loaders/tgv/evas_image_load_tgv.c
@@ -0,0 +1,587 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#ifdef _WIN32
+# include <winsock2.h>
+#endif /* ifdef _WIN32 */
+
+#ifdef ENABLE_LIBLZ4
+# include <lz4.h>
+#else
+# include "lz4.h"
+#endif
+
+#include "rg_etc1.h"
+#include "Evas_Loader.h"
+
+#ifdef BUILD_NEON
+#include <arm_neon.h>
+#endif
+
+#ifndef WORDS_BIGENDIAN
+/* x86 */
+#define A_VAL(p) (((uint8_t *)(p))[3])
+#define R_VAL(p) (((uint8_t *)(p))[2])
+#define G_VAL(p) (((uint8_t *)(p))[1])
+#define B_VAL(p) (((uint8_t *)(p))[0])
+#else
+/* ppc */
+#define A_VAL(p) (((uint8_t *)(p))[0])
+#define R_VAL(p) (((uint8_t *)(p))[1])
+#define G_VAL(p) (((uint8_t *)(p))[2])
+#define B_VAL(p) (((uint8_t *)(p))[3])
+#endif
+
+/**************************************************************
+ * The TGV file format is oriented around compression mecanism
+ * that hardware are good at decompressing. We do still provide
+ * a fully software implementation in case your hardware doesn't
+ * handle it. As OpenGL is pretty bad at handling border of
+ * texture, we do duplicate the first pixels of every border.
+ *
+ * This file format is designed to compress/decompress things
+ * in block area. Giving opportunity to store really huge file
+ * and only decompress/compress them as we need. Note that region
+ * only work with software decompression as we don't have a sane
+ * way to duplicate border to avoid artifact when scaling texture.
+ *
+ * The file format is as follow :
+ * - char magic[4]: "TGV1"
+ * - uint8_t block_size (real block size = (4 << bits[0-3], 4 << bits[4-7])
+ * - uint8_t algorithm (0 -> ETC1, 1 -> ETC2 RGB, 2 -> ETC2 RGBA, 3 -> ETC1+Alpha)
+ * - uint8_t options[2] (bitmask: 1 -> lz4, 2 for block-less, 4 -> unpremultiplied)
+ * - uint32_t width
+ * - uint32_t height
+ * - blocks[]
+ * - 0 length encoded compress size (if length == 64 * block_size => no compression)
+ * - lzma encoded etc1 block
+ *
+ * If the format is ETC1+Alpha (algo = 3), then a second image is encoded
+ * in ETC1 right after the first one, and it contains grey-scale alpha
+ * values.
+ **************************************************************/
+
+// FIXME: wondering if we should support mipmap
+// TODO: support ETC1+ETC2 images (RGB only)
+
+typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
+struct _Evas_Loader_Internal
+{
+ Eina_File *f;
+
+ Eina_Rectangle region;
+
+ struct {
+ unsigned int width;
+ unsigned int height;
+ } block;
+ struct {
+ unsigned int width;
+ unsigned int height;
+ } size;
+
+ Evas_Colorspace cspace;
+
+ Eina_Bool compress : 1;
+ Eina_Bool blockless : 1; // Special mode used when copying data directly
+ Eina_Bool unpremul : 1;
+};
+
+static const Evas_Colorspace cspaces_etc1[2] = {
+ EVAS_COLORSPACE_ETC1,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static const Evas_Colorspace cspaces_rgb8_etc2[2] = {
+ EVAS_COLORSPACE_RGB8_ETC2,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static const Evas_Colorspace cspaces_rgba8_etc2_eac[2] = {
+ EVAS_COLORSPACE_RGBA8_ETC2_EAC,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static const Evas_Colorspace cspaces_etc1_alpha[2] = {
+ EVAS_COLORSPACE_ETC1_ALPHA,
+ EVAS_COLORSPACE_ARGB8888
+};
+
+static void *
+evas_image_load_file_open_tgv(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
+ Evas_Image_Load_Opts *opts,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error)
+{
+ Evas_Loader_Internal *loader;
+
+ if (eina_file_size_get(f) <= 16)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return NULL;
+ }
+
+ loader = calloc(1, sizeof (Evas_Loader_Internal));
+ if (!loader)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return NULL;
+ }
+
+ loader->f = eina_file_dup(f);
+ if (!loader->f)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ free(loader);
+ return NULL;
+ }
+
+ if (opts && (opts->region.w > 0) && (opts->region.h > 0))
+ {
+ EINA_RECTANGLE_SET(&loader->region,
+ opts->region.x,
+ opts->region.y,
+ opts->region.w,
+ opts->region.h);
+ }
+ else
+ {
+ EINA_RECTANGLE_SET(&loader->region,
+ 0, 0,
+ -1, -1);
+ }
+
+ return loader;
+}
+
+
+static void
+evas_image_load_file_close_tgv(void *loader_data)
+{
+ Evas_Loader_Internal *loader = loader_data;
+
+ eina_file_close(loader->f);
+ free(loader);
+}
+
+static int
+roundup(int val, int rup)
+{
+ if (val >= 0 && rup > 0)
+ return (val + rup - 1) - ((val + rup - 1) % rup);
+ return 0;
+}
+
+#define OFFSET_BLOCK_SIZE 4
+#define OFFSET_ALGORITHM 5
+#define OFFSET_OPTIONS 6
+#define OFFSET_WIDTH 8
+#define OFFSET_HEIGHT 12
+#define OFFSET_BLOCKS 16
+
+static Eina_Bool
+evas_image_load_file_head_tgv(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+ Eina_Bool ret = EINA_FALSE;
+ char *m;
+
+ m = eina_file_map_all(loader->f, EINA_FILE_SEQUENTIAL);
+ if (!m)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ if (strncmp(m, "TGV1", 4) != 0)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error;
+ }
+
+ switch (m[OFFSET_ALGORITHM] & 0xFF)
+ {
+ case 0:
+ prop->cspaces = cspaces_etc1;
+ loader->cspace = EVAS_COLORSPACE_ETC1;
+ prop->alpha = EINA_FALSE;
+ break;
+ case 1:
+ prop->cspaces = cspaces_rgb8_etc2;
+ loader->cspace = EVAS_COLORSPACE_RGB8_ETC2;
+ prop->alpha = EINA_FALSE;
+ break;
+ case 2:
+ prop->cspaces = cspaces_rgba8_etc2_eac;
+ loader->cspace = EVAS_COLORSPACE_RGBA8_ETC2_EAC;
+ prop->alpha = EINA_TRUE;
+ break;
+ case 3:
+ prop->cspaces = cspaces_etc1_alpha;
+ loader->cspace = EVAS_COLORSPACE_ETC1_ALPHA;
+ loader->unpremul = !!(m[OFFSET_OPTIONS] & 0x4);
+ prop->alpha = EINA_TRUE;
+ prop->premul = loader->unpremul;
+ break;
+ default:
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error;
+ }
+
+ loader->compress = m[OFFSET_OPTIONS] & 0x1;
+ loader->blockless = (m[OFFSET_OPTIONS] & 0x2) != 0;
+
+ loader->size.width = ntohl(*((unsigned int*) &(m[OFFSET_WIDTH])));
+ loader->size.height = ntohl(*((unsigned int*) &(m[OFFSET_HEIGHT])));
+
+ if (loader->blockless)
+ {
+ loader->block.width = roundup(loader->size.width + 2, 4);
+ loader->block.height = roundup(loader->size.height + 2, 4);
+ }
+ else
+ {
+ loader->block.width = 4 << (m[OFFSET_BLOCK_SIZE] & 0x0f);
+ loader->block.height = 4 << ((m[OFFSET_BLOCK_SIZE] & 0xf0) >> 4);
+ }
+
+ if (loader->region.w == -1 && loader->region.h == -1)
+ {
+ loader->region.w = loader->size.width;
+ loader->region.h = loader->size.height;
+ }
+ else
+ {
+ Eina_Rectangle r;
+
+ // ETC1 colorspace doesn't work with region
+ prop->cspaces = NULL;
+
+ EINA_RECTANGLE_SET(&r, 0, 0, loader->size.width, loader->size.height);
+ if (!eina_rectangle_intersection(&loader->region, &r))
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto on_error;
+ }
+ }
+
+ prop->w = loader->size.width;
+ prop->h = loader->size.height;
+ prop->borders.l = 1;
+ prop->borders.t = 1;
+ prop->borders.r = roundup(prop->w + 2, 4) - prop->w - 1;
+ prop->borders.b = roundup(prop->h + 2, 4) - prop->h - 1;
+
+ ret = EINA_TRUE;
+
+on_error:
+ eina_file_map_free(loader->f, m);
+ return ret;
+}
+
+static inline unsigned int
+_tgv_length_get(const char *m, unsigned int length, unsigned int *offset)
+{
+ unsigned int r = 0;
+ unsigned int shift = 0;
+
+ while (*offset < length && ((*m) & 0x80))
+ {
+ r = r | (((*m) & 0x7F) << shift);
+ shift += 7;
+ m++;
+ (*offset)++;
+ }
+ if (*offset < length)
+ {
+ r = r | (((*m) & 0x7F) << shift);
+ (*offset)++;
+ }
+
+ return r;
+}
+
+Eina_Bool
+evas_image_load_file_data_tgv(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Evas_Loader_Internal *loader = loader_data;
+ const char *m;
+ unsigned int *p = pixels;
+ unsigned char *p_etc = pixels;
+ char *buffer = NULL;
+ Eina_Rectangle master;
+ unsigned int block_length;
+ unsigned int length, offset;
+ unsigned int x, y;
+ unsigned int block_count;
+ unsigned int etc_width = 0;
+ unsigned int etc_block_size;
+ Eina_Bool r = EINA_FALSE;
+ int num_planes = 1, plane, alpha_offset = 0;
+
+ length = eina_file_size_get(loader->f);
+ offset = OFFSET_BLOCKS;
+
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+
+ m = eina_file_map_all(loader->f, EINA_FILE_WILLNEED);
+ if (!m) return EINA_FALSE;
+
+ // By definition, prop{.w, .h} == region{.w, .h}
+ EINA_RECTANGLE_SET(&master,
+ loader->region.x, loader->region.y,
+ prop->w, prop->h);
+
+ switch (loader->cspace)
+ {
+ case EVAS_COLORSPACE_ETC1:
+ case EVAS_COLORSPACE_RGB8_ETC2:
+ etc_block_size = 8;
+ break;
+ case EVAS_COLORSPACE_RGBA8_ETC2_EAC:
+ etc_block_size = 16;
+ break;
+ case EVAS_COLORSPACE_ETC1_ALPHA:
+ etc_block_size = 8;
+ num_planes = 2;
+ alpha_offset = ((prop->w + 2 + 3) / 4) * ((prop->h + 2 + 3) / 4) * 8 / sizeof(*p_etc);
+ break;
+ default: abort();
+ }
+ etc_width = ((prop->w + 2 + 3) / 4) * etc_block_size;
+
+ switch (prop->cspace)
+ {
+ case EVAS_COLORSPACE_ETC1:
+ case EVAS_COLORSPACE_RGB8_ETC2:
+ case EVAS_COLORSPACE_RGBA8_ETC2_EAC:
+ case EVAS_COLORSPACE_ETC1_ALPHA:
+ if (master.x % 4 || master.y % 4)
+ abort();
+ break;
+ case EVAS_COLORSPACE_ARGB8888:
+ // Offset to take duplicated pixels into account
+ master.x += 1;
+ master.y += 1;
+ break;
+ default: abort();
+ }
+
+ if (prop->cspace != EVAS_COLORSPACE_ARGB8888 && prop->cspace != loader->cspace)
+ {
+ if (!((prop->cspace == EVAS_COLORSPACE_RGB8_ETC2) &&
+ (loader->cspace == EVAS_COLORSPACE_ETC1)))
+ goto on_error;
+ // else: ETC2 is compatible with ETC1 and is preferred
+ }
+
+ // Allocate space for each ETC block (8 or 16 bytes per 4 * 4 pixels group)
+ block_count = loader->block.width * loader->block.height / (4 * 4);
+ if (loader->compress)
+ buffer = alloca(etc_block_size * block_count);
+
+ for (plane = 0; plane < num_planes; plane++)
+ for (y = 0; y < loader->size.height + 2; y += loader->block.height)
+ for (x = 0; x < loader->size.width + 2; x += loader->block.width)
+ {
+ Eina_Rectangle current;
+ const char *data_start;
+ const char *it;
+ unsigned int expand_length;
+ unsigned int i, j;
+
+ block_length = _tgv_length_get(m + offset, length, &offset);
+
+ if (block_length == 0) goto on_error;
+
+ data_start = m + offset;
+ offset += block_length;
+
+ EINA_RECTANGLE_SET(&current, x, y,
+ loader->block.width, loader->block.height);
+
+ if (!eina_rectangle_intersection(&current, &master))
+ continue;
+
+ if (loader->compress)
+ {
+ expand_length = LZ4_decompress_fast(data_start, buffer,
+ block_count * etc_block_size);
+ // That's an overhead for now, need to be fixed
+ if (expand_length != block_length)
+ goto on_error;
+ }
+ else
+ {
+ buffer = (void*) data_start;
+ if (block_count * etc_block_size != block_length)
+ goto on_error;
+ }
+ it = buffer;
+
+ for (i = 0; i < loader->block.height; i += 4)
+ for (j = 0; j < loader->block.width; j += 4, it += etc_block_size)
+ {
+ Eina_Rectangle current_etc;
+ unsigned int temporary[4 * 4];
+ unsigned int offset_x, offset_y;
+ int k, l;
+
+ EINA_RECTANGLE_SET(&current_etc, x + j, y + i, 4, 4);
+
+ if (!eina_rectangle_intersection(&current_etc, &current))
+ continue;
+
+ switch (prop->cspace)
+ {
+ case EVAS_COLORSPACE_ARGB8888:
+ switch (loader->cspace)
+ {
+ case EVAS_COLORSPACE_ETC1:
+ case EVAS_COLORSPACE_ETC1_ALPHA:
+ if (!rg_etc1_unpack_block(it, temporary, 0))
+ {
+ // TODO: Should we decode as RGB8_ETC2?
+ fprintf(stderr, "ETC1: Block starting at {%i, %i} is corrupted!\n", x + j, y + i);
+ continue;
+ }
+ break;
+ case EVAS_COLORSPACE_RGB8_ETC2:
+ rg_etc2_rgb8_decode_block((uint8_t *) it, temporary);
+ break;
+ case EVAS_COLORSPACE_RGBA8_ETC2_EAC:
+ rg_etc2_rgba8_decode_block((uint8_t *) it, temporary);
+ break;
+ default: abort();
+ }
+
+ offset_x = current_etc.x - x - j;
+ offset_y = current_etc.y - y - i;
+
+ if (!plane)
+ {
+#ifdef BUILD_NEON
+ if (eina_cpu_features_get() & EINA_CPU_NEON)
+ {
+ uint32_t *dst = &p[current_etc.x - 1 + (current_etc.y - 1) * master.w];
+ uint32_t *src = &temporary[offset_x + offset_y * 4];
+ for (k = 0; k < current_etc.h; k++)
+ {
+ if (current_etc.w == 4)
+ vst1q_u32(dst, vld1q_u32(src));
+ else if (current_etc.w == 3)
+ {
+ vst1_u32(dst, vld1_u32(src));
+ *(dst + 2) = *(src + 2);
+ }
+ else if (current_etc.w == 2)
+ vst1_u32(dst, vld1_u32(src));
+ else
+ *dst = *src;
+ dst += master.w;
+ src += 4;
+ }
+ }
+ else
+#endif
+ for (k = 0; k < current_etc.h; k++)
+ {
+ memcpy(&p[current_etc.x - 1 + (current_etc.y - 1 + k) * master.w],
+ &temporary[offset_x + (offset_y + k) * 4],
+ current_etc.w * sizeof (unsigned int));
+ }
+ }
+ else
+ {
+ for (k = 0; k < current_etc.h; k++)
+ for (l = 0; l < current_etc.w; l++)
+ {
+ unsigned int *rgbdata =
+ &p[current_etc.x - 1 + (current_etc.y - 1 + k) * master.w + l];
+ unsigned int *adata =
+ &temporary[offset_x + (offset_y + k) * 4 + l];
+ A_VAL(rgbdata) = G_VAL(adata);
+ }
+ }
+ break;
+ case EVAS_COLORSPACE_ETC1:
+ case EVAS_COLORSPACE_RGB8_ETC2:
+ case EVAS_COLORSPACE_RGBA8_ETC2_EAC:
+ memcpy(&p_etc[(current_etc.x / 4) * etc_block_size +
+ (current_etc.y / 4) * etc_width],
+ it, etc_block_size);
+ break;
+ case EVAS_COLORSPACE_ETC1_ALPHA:
+ memcpy(&p_etc[(current_etc.x / 4) * etc_block_size +
+ (current_etc.y / 4) * etc_width +
+ plane * alpha_offset],
+ it, etc_block_size);
+ break;
+ default:
+ abort();
+ }
+ } // bx,by inside blocks
+ } // x,y macroblocks
+
+ // TODO: Add support for more unpremultiplied modes (ETC2)
+ if (prop->cspace == EVAS_COLORSPACE_ARGB8888)
+ prop->premul = loader->unpremul; // call premul if unpremul data
+
+ r = EINA_TRUE;
+ *error = EVAS_LOAD_ERROR_NONE;
+
+ on_error:
+ eina_file_map_free(loader->f, (void*) m);
+ return r;
+}
+
+Evas_Image_Load_Func evas_image_load_tgv_func =
+{
+ evas_image_load_file_open_tgv,
+ evas_image_load_file_close_tgv,
+ evas_image_load_file_head_tgv,
+ evas_image_load_file_data_tgv,
+ NULL,
+ EINA_TRUE,
+ EINA_FALSE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ em->functions = (void *)(&evas_image_load_tgv_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "tgv",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, tgv);
+
+#ifndef EVAS_STATIC_BUILD_TGV
+EVAS_EINA_MODULE_DEFINE(image_loader, tgv);
+#endif
diff --git a/src/modules/evas/image_loaders/tiff/evas_image_load_tiff.c b/src/modules/evas/image_loaders/tiff/evas_image_load_tiff.c
new file mode 100644
index 0000000000..943c3e74b2
--- /dev/null
+++ b/src/modules/evas/image_loaders/tiff/evas_image_load_tiff.c
@@ -0,0 +1,380 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <tiffio.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_common_private.h"
+#include "evas_private.h"
+
+static int _evas_loader_tiff_log_dom = -1;
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_evas_loader_tiff_log_dom, __VA_ARGS__)
+
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_evas_loader_tiff_log_dom, __VA_ARGS__)
+
+typedef struct TIFFRGBAImage_Extra TIFFRGBAImage_Extra;
+typedef struct TIFFRGBAMap TIFFRGBAMap;
+
+struct TIFFRGBAImage_Extra {
+ TIFFRGBAImage rgba;
+ char pper;
+ uint32 num_pixels;
+ uint32 py;
+};
+
+struct TIFFRGBAMap {
+ tdata_t mem;
+ toff_t size;
+};
+
+static tsize_t
+_evas_tiff_RWProc(thandle_t handle EINA_UNUSED,
+ tdata_t data EINA_UNUSED,
+ tsize_t size EINA_UNUSED)
+{
+ return 0;
+}
+
+static toff_t
+_evas_tiff_SeekProc(thandle_t handle EINA_UNUSED,
+ toff_t size EINA_UNUSED,
+ int origin EINA_UNUSED)
+{
+ return 0;
+}
+
+static int
+_evas_tiff_CloseProc(thandle_t handle EINA_UNUSED)
+{
+ return 0;
+}
+
+static toff_t
+_evas_tiff_SizeProc(thandle_t handle)
+{
+ TIFFRGBAMap *map = (TIFFRGBAMap*) handle;
+
+ return map->size;
+}
+
+static int
+_evas_tiff_MapProc(thandle_t handle, tdata_t *mem, toff_t *size)
+{
+ TIFFRGBAMap *map = (TIFFRGBAMap*) handle;
+
+ *mem = map->mem;
+ *size = map->size;
+
+ return 1;
+}
+
+static void
+_evas_tiff_UnmapProc(thandle_t handle EINA_UNUSED, tdata_t data EINA_UNUSED, toff_t size EINA_UNUSED)
+{
+}
+
+static void *
+evas_image_load_file_open_tiff(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
+ Evas_Image_Load_Opts *opts EINA_UNUSED,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error EINA_UNUSED)
+{
+ return f;
+}
+
+static void
+evas_image_load_file_close_tiff(void *loader_data EINA_UNUSED)
+{
+}
+
+static Eina_Bool
+evas_image_load_file_head_tiff(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Eina_File *f = loader_data;
+ char txt[1024];
+ TIFFRGBAImage tiff_image;
+ TIFFRGBAMap tiff_map;
+ TIFF *tif = NULL;
+ unsigned char *map;
+ uint16 magic_number;
+ Eina_Bool r = EINA_FALSE;
+
+ map = eina_file_map_all(f, EINA_FILE_RANDOM);
+ if (!map || eina_file_size_get(f) < 3)
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto on_error;
+ }
+
+ magic_number = *((uint16*) map);
+
+ if ((magic_number != TIFF_BIGENDIAN) /* Checks if actually tiff file */
+ && (magic_number != TIFF_LITTLEENDIAN))
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto on_error;
+ }
+
+ tiff_map.mem = map;
+ tiff_map.size = eina_file_size_get(f);
+
+ tif = TIFFClientOpen("evas", "rM", &tiff_map,
+ _evas_tiff_RWProc, _evas_tiff_RWProc,
+ _evas_tiff_SeekProc, _evas_tiff_CloseProc,
+ _evas_tiff_SizeProc,
+ _evas_tiff_MapProc, _evas_tiff_UnmapProc);
+ if (!tif)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error;
+ }
+
+ strcpy(txt, "Evas Tiff loader: cannot be processed by libtiff");
+ if (!TIFFRGBAImageOK(tif, txt))
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error;
+ }
+ strcpy(txt, "Evas Tiff loader: cannot begin reading tiff");
+ if (!TIFFRGBAImageBegin(& tiff_image, tif, 1, txt))
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error;
+ }
+
+ if (tiff_image.alpha != EXTRASAMPLE_UNSPECIFIED)
+ prop->alpha = 1;
+ if ((tiff_image.width < 1) || (tiff_image.height < 1) ||
+ (tiff_image.width > IMG_MAX_SIZE) || (tiff_image.height > IMG_MAX_SIZE) ||
+ IMG_TOO_BIG(tiff_image.width, tiff_image.height))
+ {
+ if (IMG_TOO_BIG(tiff_image.width, tiff_image.height))
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ else
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto on_error_end;
+ }
+ prop->w = tiff_image.width;
+ prop->h = tiff_image.height;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ r = EINA_TRUE;
+
+ on_error_end:
+ TIFFRGBAImageEnd(&tiff_image);
+ on_error:
+ if (tif) TIFFClose(tif);
+ if (map) eina_file_map_free(f, map);
+ return r;
+}
+
+static Eina_Bool
+evas_image_load_file_data_tiff(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Eina_File *f = loader_data;
+ char txt[1024];
+ TIFFRGBAImage_Extra rgba_image;
+ TIFFRGBAMap rgba_map;
+ TIFF *tif = NULL;
+ unsigned char *map;
+ uint32 *rast = NULL;
+ uint32 num_pixels;
+ int x, y;
+ uint16 magic_number;
+ Eina_Bool res = EINA_FALSE;
+
+ map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (!map || eina_file_size_get(f) < 3)
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto on_error;
+ }
+
+ magic_number = *((uint16*) map);
+
+ if ((magic_number != TIFF_BIGENDIAN) /* Checks if actually tiff file */
+ && (magic_number != TIFF_LITTLEENDIAN))
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error;
+ }
+
+ rgba_map.mem = map;
+ rgba_map.size = eina_file_size_get(f);
+
+ tif = TIFFClientOpen("evas", "rM", &rgba_map,
+ _evas_tiff_RWProc, _evas_tiff_RWProc,
+ _evas_tiff_SeekProc, _evas_tiff_CloseProc,
+ _evas_tiff_SizeProc,
+ _evas_tiff_MapProc, _evas_tiff_UnmapProc);
+ if (!tif)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error;
+ }
+
+ strcpy(txt, "Evas Tiff loader: cannot be processed by libtiff");
+ if (!TIFFRGBAImageOK(tif, txt))
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error;
+ }
+ strcpy(txt, "Evas Tiff loader: cannot begin reading tiff");
+ if (!TIFFRGBAImageBegin((TIFFRGBAImage *) & rgba_image, tif, 0, txt))
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error;
+ }
+
+ if (rgba_image.rgba.alpha != EXTRASAMPLE_UNSPECIFIED)
+ prop->alpha = 1;
+ if ((rgba_image.rgba.width != prop->w) ||
+ (rgba_image.rgba.height != prop->h))
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto on_error_end;
+ }
+
+ rgba_image.num_pixels = num_pixels = prop->w * prop->h;
+
+ rgba_image.pper = rgba_image.py = 0;
+ rast = (uint32 *) _TIFFmalloc(sizeof(uint32) * num_pixels);
+
+ if (!rast)
+ {
+ ERR("Evas Tiff loader: out of memory");
+
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto on_error_end;
+ }
+ if (rgba_image.rgba.bitspersample == 8)
+ {
+ if (!TIFFRGBAImageGet((TIFFRGBAImage *) &rgba_image, rast,
+ rgba_image.rgba.width, rgba_image.rgba.height))
+ {
+ _TIFFfree(rast);
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error_end;
+ }
+ }
+ else
+ {
+ INF("channel bits == %i", (int)rgba_image.rgba.samplesperpixel);
+ }
+ /* process rast -> image rgba. really same as prior code anyway just simpler */
+ for (y = 0; y < (int)prop->h; y++)
+ {
+ DATA32 *pix, *pd;
+ uint32 *ps, pixel;
+ unsigned int a, r, g, b;
+ unsigned int nas = 0;
+
+ pix = pixels;
+ pd = pix + ((prop->h - y - 1) * prop->w);
+ ps = rast + (y * prop->w);
+ for (x = 0; x < (int)prop->w; x++)
+ {
+ pixel = *ps;
+ a = TIFFGetA(pixel);
+ r = TIFFGetR(pixel);
+ g = TIFFGetG(pixel);
+ b = TIFFGetB(pixel);
+ if (!prop->alpha) a = 255;
+ if ((rgba_image.rgba.alpha == EXTRASAMPLE_UNASSALPHA) &&
+ (a < 255))
+ {
+ r = (r * (a + 1)) >> 8;
+ g = (g * (a + 1)) >> 8;
+ b = (b * (a + 1)) >> 8;
+ }
+ *pd = ARGB_JOIN(a, r, g, b);
+
+ if (a == 0xff) nas++;
+ ps++;
+ pd++;
+ }
+
+ if ((ALPHA_SPARSE_INV_FRACTION * nas) >= (prop->w * prop->h))
+ prop->alpha_sparse = EINA_TRUE;
+ }
+
+ _TIFFfree(rast);
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ res = EINA_TRUE;
+
+ on_error_end:
+ TIFFRGBAImageEnd((TIFFRGBAImage *) & rgba_image);
+ on_error:
+ if (tif) TIFFClose(tif);
+ if (map) eina_file_map_free(f, map);
+ return res;
+}
+
+static Evas_Image_Load_Func evas_image_load_tiff_func =
+{
+ evas_image_load_file_open_tiff,
+ evas_image_load_file_close_tiff,
+ evas_image_load_file_head_tiff,
+ evas_image_load_file_data_tiff,
+ NULL,
+ EINA_TRUE,
+ EINA_FALSE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ _evas_loader_tiff_log_dom = eina_log_domain_register
+ ("evas-tiff", EVAS_DEFAULT_LOG_COLOR);
+ if (_evas_loader_tiff_log_dom < 0)
+ {
+ EINA_LOG_ERR("Can not create a module log domain.");
+ return 0;
+ }
+ em->functions = (void *)(&evas_image_load_tiff_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+ eina_log_domain_unregister(_evas_loader_tiff_log_dom);
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "tiff",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, tiff);
+
+#ifndef EVAS_STATIC_BUILD_TIFF
+EVAS_EINA_MODULE_DEFINE(image_loader, tiff);
+#endif
diff --git a/src/modules/evas/image_loaders/wbmp/evas_image_load_wbmp.c b/src/modules/evas/image_loaders/wbmp/evas_image_load_wbmp.c
new file mode 100644
index 0000000000..70c507824b
--- /dev/null
+++ b/src/modules/evas/image_loaders/wbmp/evas_image_load_wbmp.c
@@ -0,0 +1,208 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_common_private.h"
+#include "evas_private.h"
+
+static int
+read_mb(unsigned int *data, void *map, size_t length, size_t *position)
+{
+ int ac = 0, ct;
+ unsigned char buf;
+
+ for (ct = 0;;)
+ {
+ if ((ct++) == 5) return -1;
+ if (*position > length) return -1;
+ buf = ((unsigned char *) map)[(*position)++];
+ ac = (ac << 7) | (buf & 0x7f);
+ if ((buf & 0x80) == 0) break;
+ }
+ *data = ac;
+ return 0;
+}
+
+static void *
+evas_image_load_file_open_wbmp(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
+ Evas_Image_Load_Opts *opts EINA_UNUSED,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error EINA_UNUSED)
+{
+ return f;
+}
+
+static void
+evas_image_load_file_close_wbmp(void *loader_data EINA_UNUSED)
+{
+}
+
+static Eina_Bool
+evas_image_load_file_head_wbmp(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Eina_File *f = loader_data;
+ void *map = NULL;
+ size_t position = 0;
+ size_t length;
+ unsigned int type, w, h;
+ Eina_Bool r = EINA_FALSE;
+
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ length = eina_file_size_get(f);
+ if (length <= 4) goto bail;
+
+ map = eina_file_map_all(f, EINA_FILE_RANDOM);
+ if (!map) goto bail;
+
+ if (read_mb(&type, map, length, &position) < 0) goto bail;
+
+ if (type != 0)
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto bail;
+ }
+
+ position++; /* skipping one byte */
+ if (read_mb(&w, map, length, &position) < 0) goto bail;
+ if (read_mb(&h, map, length, &position) < 0) goto bail;
+ 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 bail;
+ }
+
+ prop->w = w;
+ prop->h = h;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ r = EINA_TRUE;
+
+ bail:
+ if (map) eina_file_map_free(f, map);
+ return r;
+}
+
+static Eina_Bool
+evas_image_load_file_data_wbmp(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Eina_File *f = loader_data;
+ void *map = NULL;
+ size_t position = 0;
+ size_t length;
+ unsigned int type, w, h;
+ unsigned int line_length;
+ unsigned char *line = NULL;
+ int cur = 0, x, y;
+ DATA32 *dst_data;
+ Eina_Bool r = EINA_FALSE;
+
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ length = eina_file_size_get(f);
+ if (length <= 4) goto bail;
+
+ map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ if (!map) goto bail;
+
+ if (read_mb(&type, map, length, &position) < 0) goto bail;
+ position++; /* skipping one byte */
+ if (read_mb(&w, map, length, &position) < 0) goto bail;
+ if (read_mb(&h, map, length, &position) < 0) goto bail;
+
+ if (type != 0)
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto bail;
+ }
+
+ 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 bail;
+ }
+
+ if (prop->w != w || prop->h != h)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto bail;
+ }
+
+ dst_data = pixels;
+
+ line_length = (prop->w + 7) >> 3;
+
+ for (y = 0; y < (int)prop->h; y++)
+ {
+ if (position + line_length > length) goto bail;
+ line = ((unsigned char*) map) + position;
+ position += line_length;
+ for (x = 0; x < (int)prop->w; x++)
+ {
+ int idx = x >> 3;
+ int offset = 1 << (0x07 - (x & 0x07));
+ if (line[idx] & offset) dst_data[cur] = 0xffffffff;
+ else dst_data[cur] = 0xff000000;
+ cur++;
+ }
+ }
+
+ *error = EVAS_LOAD_ERROR_NONE;
+ r = EINA_TRUE;
+
+ bail:
+ if (map) eina_file_map_free(f, map);
+ return r;
+}
+
+static Evas_Image_Load_Func evas_image_load_wbmp_func =
+{
+ evas_image_load_file_open_wbmp,
+ evas_image_load_file_close_wbmp,
+ evas_image_load_file_head_wbmp,
+ evas_image_load_file_data_wbmp,
+ NULL,
+ EINA_TRUE,
+ EINA_FALSE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ em->functions = (void *)(&evas_image_load_wbmp_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "wbmp",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, wbmp);
+
+#ifndef EVAS_STATIC_BUILD_WBMP
+EVAS_EINA_MODULE_DEFINE(image_loader, wbmp);
+#endif
diff --git a/src/modules/evas/image_loaders/webp/evas_image_load_webp.c b/src/modules/evas/image_loaders/webp/evas_image_load_webp.c
new file mode 100644
index 0000000000..50f52d0e25
--- /dev/null
+++ b/src/modules/evas/image_loaders/webp/evas_image_load_webp.c
@@ -0,0 +1,156 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <webp/decode.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_common_private.h"
+#include "evas_private.h"
+
+static Eina_Bool
+evas_image_load_file_check(Eina_File *f, void *map,
+ unsigned int *w, unsigned int *h, Eina_Bool *alpha,
+ int *error)
+{
+ WebPDecoderConfig config;
+
+ if (eina_file_size_get(f) < 30) return EINA_FALSE;
+
+ if (!WebPInitDecoderConfig(&config))
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+ if (WebPGetFeatures(map, 30, &config.input) != VP8_STATUS_OK)
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ return EINA_FALSE;
+ }
+
+ *w = config.input.width;
+ *h = config.input.height;
+ *alpha = config.input.has_alpha;
+
+ return EINA_TRUE;
+}
+
+static void *
+evas_image_load_file_open_webp(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
+ Evas_Image_Load_Opts *opts EINA_UNUSED,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error EINA_UNUSED)
+{
+ return f;
+}
+
+static void
+evas_image_load_file_close_webp(void *loader_data EINA_UNUSED)
+{
+}
+
+static Eina_Bool
+evas_image_load_file_head_webp(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Eina_File *f = loader_data;
+ Eina_Bool r;
+ void *data;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+
+ data = eina_file_map_all(f, EINA_FILE_RANDOM);
+
+ r = evas_image_load_file_check(f, data,
+ &prop->w, &prop->h, &prop->alpha,
+ error);
+
+ if (data) eina_file_map_free(f, data);
+ return r;
+}
+
+static Eina_Bool
+evas_image_load_file_data_webp(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Eina_File *f = loader_data;
+ void *data = NULL;
+ void *decoded = NULL;
+ void *surface = NULL;
+ int width, height;
+
+ data = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+
+ surface = pixels;
+
+ decoded = WebPDecodeBGRA(data, eina_file_size_get(f), &width, &height);
+ if (!decoded)
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto free_data;
+ }
+ *error = EVAS_LOAD_ERROR_NONE;
+
+ if ((int) prop->w != width ||
+ (int) prop->h != height)
+ goto free_data;
+
+ // XXX: this copy of the surface is inefficient
+ memcpy(surface, decoded, width * height * 4);
+ prop->premul = EINA_TRUE;
+
+ free_data:
+ if (data) eina_file_map_free(f, data);
+ free(decoded);
+
+ return EINA_TRUE;
+}
+
+static Evas_Image_Load_Func evas_image_load_webp_func =
+{
+ evas_image_load_file_open_webp,
+ evas_image_load_file_close_webp,
+ evas_image_load_file_head_webp,
+ evas_image_load_file_data_webp,
+ NULL,
+ EINA_TRUE,
+ EINA_FALSE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ em->functions = (void *)(&evas_image_load_webp_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "webp",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, webp);
+
+#ifndef EVAS_STATIC_BUILD_WEBP
+EVAS_EINA_MODULE_DEFINE(image_loader, webp);
+#endif
diff --git a/src/modules/evas/image_loaders/xpm/evas_image_load_xpm.c b/src/modules/evas/image_loaders/xpm/evas_image_load_xpm.c
new file mode 100644
index 0000000000..cf9b9df075
--- /dev/null
+++ b/src/modules/evas/image_loaders/xpm/evas_image_load_xpm.c
@@ -0,0 +1,747 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "evas_common_private.h"
+#include "evas_private.h"
+
+static int _evas_loader_xpm_log_dom = -1;
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_evas_loader_xpm_log_dom, __VA_ARGS__)
+
+static Eina_File *rgb_txt;
+static void *rgb_txt_map;
+
+static int
+_xpm_hexa_int(const char *s, int len)
+{
+ const char *hexa = "0123456789abcdef";
+ const char *lookup;
+ int i, c, r;
+
+ for (r = 0, i = 0; i < len; i++)
+ {
+ c = s[i];
+ lookup = strchr(hexa, tolower(c));
+ r = (r << 4) | (lookup ? lookup - hexa : 0);
+ }
+
+ return r;
+}
+
+static void
+xpm_parse_color(char *color, int *r, int *g, int *b)
+{
+ char *tmp;
+ char *max;
+ char *endline;
+ char buf[4096];
+
+ /* is a #ff00ff like color */
+ if (color[0] == '#')
+ {
+ int len;
+
+ len = strlen(color) - 1;
+ if (len < 13)
+ {
+
+ len /= 3;
+ *r = _xpm_hexa_int(&(color[1 + (0 * len)]), len);
+ *g = _xpm_hexa_int(&(color[1 + (1 * len)]), len);
+ *b = _xpm_hexa_int(&(color[1 + (2 * len)]), len);
+ if (len == 1)
+ {
+ *r = (*r << 4) | *r;
+ *g = (*g << 4) | *g;
+ *b = (*b << 4) | *b;
+ }
+ else if (len > 2)
+ {
+ *r >>= (len - 2) * 4;
+ *g >>= (len - 2) * 4;
+ *b >>= (len - 2) * 4;
+ }
+ }
+ return;
+ }
+ /* look in rgb txt database */
+ if (!rgb_txt) return;
+ tmp = rgb_txt_map;
+ max = tmp + eina_file_size_get(rgb_txt);
+
+ while (tmp < max)
+ {
+ endline = memchr(tmp, '\n', max - tmp);
+ if (!endline) endline = max;
+ if ((*tmp != '!') && ((endline - tmp) < (int) (sizeof(buf) - 1)))
+ {
+ int rr, gg, bb;
+ char name[4096];
+
+ /* FIXME: not really efficient, should be loaded once in memory with a lookup table */
+ memcpy(buf, tmp, endline - tmp);
+ buf[endline - tmp + 1] = '\0';
+
+ if (sscanf(buf, "%i %i %i %[^\n]", &rr, &gg, &bb, name) == 4)
+ {
+ if (!strcasecmp(name, color))
+ {
+ *r = rr;
+ *g = gg;
+ *b = bb;
+ return;
+ }
+ }
+ }
+ tmp = endline + 1;
+ }
+}
+
+typedef struct _CMap CMap;
+struct _CMap {
+ EINA_RBTREE;
+ short r, g, b;
+ char str[6];
+ unsigned char transp;
+};
+
+Eina_Rbtree_Direction
+_cmap_cmp_node_cb(const Eina_Rbtree *left, const Eina_Rbtree *right, void *data EINA_UNUSED)
+{
+ CMap *lcm;
+ CMap *rcm;
+
+ lcm = EINA_RBTREE_CONTAINER_GET(left, CMap);
+ rcm = EINA_RBTREE_CONTAINER_GET(right, CMap);
+
+ if (strcmp(lcm->str, rcm->str) < 0)
+ return EINA_RBTREE_LEFT;
+ return EINA_RBTREE_RIGHT;
+}
+
+int
+_cmap_cmp_key_cb(const Eina_Rbtree *node, const void *key, int length EINA_UNUSED, void *data EINA_UNUSED)
+{
+ CMap *root = EINA_RBTREE_CONTAINER_GET(node, CMap);
+
+ return strcmp(root->str, key);
+}
+
+/** FIXME: clean this up and make more efficient **/
+static Eina_Bool
+evas_image_load_file_xpm(Eina_File *f, Evas_Image_Property *prop, void *pixels, int load_data, int *error)
+{
+ DATA32 *ptr, *end, *head = NULL;
+ const char *map = NULL;
+ size_t length;
+ size_t position;
+
+ int pc, c, i, j, k, w, h, ncolors, cpp, comment, transp,
+ quote, context, len, done, r, g, b, backslash, lu1, lu2;
+ char *line = NULL;
+ char s[256], tok[256], col[256], *tl;
+ int lsz = 256;
+ CMap *cmap = NULL;
+ Eina_Rbtree *root = NULL;
+
+ short lookup[128 - 32][128 - 32];
+ int count, size;
+ Eina_Bool res = EINA_FALSE;
+
+ done = 0;
+// transp = -1;
+ transp = 1;
+
+ /* if immediate_load is 1, then dont delay image laoding as below, or */
+ /* already data in this image - dont load it again */
+
+ length = eina_file_size_get(f);
+ position = 0;
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ if (length < 9)
+ {
+// ERR("XPM ERROR: file size, %zd, is to small", length);
+ goto on_error;
+ }
+
+ map = eina_file_map_all(f, load_data ? EINA_FILE_WILLNEED : EINA_FILE_RANDOM);
+ if (!map)
+ {
+ ERR("XPM ERROR: file failed to mmap");
+ goto on_error;
+ }
+
+ if (strncmp("/* XPM */", map, 9))
+ {
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto on_error;
+ }
+
+ i = 0;
+ j = 0;
+ cmap = NULL;
+ w = 10;
+ h = 10;
+ ptr = NULL;
+ end = NULL;
+ c = ' ';
+ comment = 0;
+ quote = 0;
+ context = 0;
+ size = 0;
+ count = 0;
+ line = malloc(lsz);
+ if (!line)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto on_error;
+ }
+
+ backslash = 0;
+ memset(lookup, 0, sizeof(lookup));
+ while (!done)
+ {
+ pc = c;
+ if (position == length) break ;
+ c = (char) map[position++];
+ if (!quote)
+ {
+ if ((pc == '/') && (c == '*'))
+ comment = 1;
+ else if ((pc == '*') && (c == '/') && (comment))
+ comment = 0;
+ }
+ if (!comment)
+ {
+ if ((!quote) && (c == '"'))
+ {
+ quote = 1;
+ i = 0;
+ }
+ else if ((quote) && (c == '"'))
+ {
+ line[i] = 0;
+ quote = 0;
+ if (context == 0)
+ {
+ /* Header */
+ if (sscanf(line, "%i %i %i %i", &w, &h, &ncolors, &cpp) != 4)
+ {
+// ERR("XPM ERROR: XPM file malformed header");
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto on_error;
+ }
+ if ((ncolors > 32766) || (ncolors < 1))
+ {
+ ERR("XPM ERROR: XPM files with colors > 32766 or < 1 not supported");
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto on_error;
+ }
+ if ((cpp > 5) || (cpp < 1))
+ {
+ ERR("XPM ERROR: XPM files with characters per pixel > 5 or < 1not supported");
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ goto on_error;
+ }
+ if ((w > IMG_MAX_SIZE) || (w < 1))
+ {
+ ERR("XPM ERROR: Image width > IMG_MAX_SIZE or < 1 pixels for file");
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto on_error;
+ }
+ if ((h > IMG_MAX_SIZE) || (h < 1))
+ {
+ ERR("XPM ERROR: Image height > IMG_MAX_SIZE or < 1 pixels for file");
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto on_error;
+ }
+ if (IMG_TOO_BIG(w, h))
+ {
+ ERR("XPM ERROR: Image just too big to ever allocate");
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto on_error;
+ }
+
+ if (!cmap)
+ {
+ cmap = malloc(sizeof(CMap) * ncolors);
+ if (!cmap)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto on_error;
+ }
+ }
+
+ if (!load_data)
+ {
+ prop->w = w;
+ prop->h = h;
+ }
+ else if ((int) prop->w != w ||
+ (int) prop->h != h)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto on_error;
+ }
+
+
+ j = 0;
+ context++;
+ }
+ else if (context == 1)
+ {
+ /* Color Table */
+ if (j < ncolors)
+ {
+ int slen;
+ int hascolor, iscolor;
+
+ iscolor = 0;
+ hascolor = 0;
+ tok[0] = 0;
+ col[0] = 0;
+ s[0] = 0;
+ len = strlen(line);
+ strncpy(cmap[j].str, line, cpp);
+ cmap[j].str[cpp] = 0;
+ if (load_data) root = eina_rbtree_inline_insert(root, EINA_RBTREE_GET(&cmap[j]), _cmap_cmp_node_cb, NULL);
+ for (slen = 0; slen < cpp; slen++)
+ {
+ /* fix the ascii of the color string - if its < 32 - just limit to 32 */
+ if (cmap[j].str[slen] < 32) cmap[j].str[slen] = 0;
+ }
+ cmap[j].r = -1;
+ cmap[j].transp = 0;
+ for (k = cpp; k < len; k++)
+ {
+ if (line[k] != ' ')
+ {
+ const char *tmp = strchr(&line[k], ' ');
+ slen = tmp ? tmp - &line[k]: 255;
+
+ strncpy(s, &line[k], slen);
+ s[slen] = 0;
+ k += slen;
+ if (slen == 1 && *s == 'c') iscolor = 1;
+ if ((slen == 1 && ((s[0] == 'm') || (s[0] == 's') || (s[0] == 'g') || (s[0] == 'c'))) ||
+ (slen == 2 && (s[0] == 'g') && (s[1] == '4')) ||
+ (k >= len))
+ {
+ if (k >= len)
+ {
+ if (col[0])
+ {
+ if (strlen(col) < (sizeof(col) - 2))
+ strcat(col, " ");
+ else
+ done = 1;
+ }
+ if ((strlen(col) + strlen(s)) < (sizeof(col) - 1))
+ strcat(col, s);
+ }
+ if (col[0])
+ {
+ if (!strcasecmp(col, "none"))
+ {
+ transp = 1;
+ cmap[j].transp = 1;
+ cmap[j].r = 0;
+ cmap[j].g = 0;
+ cmap[j].b = 0;
+ }
+ else
+ {
+ if ((((cmap[j].r < 0) || (!strcmp(tok, "c"))) && (!hascolor)))
+ {
+ r = g = b = 0;
+ xpm_parse_color(col, &r, &g, &b);
+ cmap[j].r = r;
+ cmap[j].g = g;
+ cmap[j].b = b;
+ if (iscolor) hascolor = 1;
+ }
+ }
+ }
+ strcpy(tok, s);
+ col[0] = 0;
+ }
+ else
+ {
+ if (col[0])
+ {
+ if (strlen(col) < ( sizeof(col) - 2))
+ strcat(col, " ");
+ else
+ done = 1;
+ }
+ if ((strlen(col) + strlen(s)) < (sizeof(col) - 1))
+ strcat(col, s);
+ }
+ }
+ }
+ }
+ j++;
+ if (load_data && j >= ncolors)
+ {
+ if (cpp == 1)
+ {
+ for (i = 0; i < ncolors; i++)
+ lookup[(int)cmap[i].str[0] - 32][0] = i;
+ }
+ if (cpp == 2)
+ {
+ for (i = 0; i < ncolors; i++)
+ lookup[(int)cmap[i].str[0] - 32][(int)cmap[i].str[1] - 32] = i;
+ }
+ context++;
+ }
+
+ if (transp) prop->alpha = 1;
+
+ if (load_data)
+ {
+ ptr = pixels;
+ head = ptr;
+ if (!ptr)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto on_error;
+ }
+ size = w * h;
+ end = ptr + size;
+ }
+ else
+ {
+ *error = EVAS_LOAD_ERROR_NONE;
+ goto on_success;
+ }
+ }
+ else
+ {
+ /* Image Data */
+ i = 0;
+ if (cpp == 0)
+ {
+ /* Chars per pixel = 0? well u never know */
+ }
+ /* it's xpm - don't care about speed too much. still faster
+ * that most xpm loaders anyway */
+ else if (cpp == 1)
+ {
+ if (transp)
+ {
+ for (i = 0;
+ ((i < 65536) && (ptr < end) && (line[i]));
+ i++)
+ {
+ lu1 = (int)line[i] - 32;
+ if (lu1 < 0) continue;
+ if (cmap[lookup[lu1][0]].transp)
+ {
+ r = (unsigned char)cmap[lookup[lu1][0]].r;
+ g = (unsigned char)cmap[lookup[lu1][0]].g;
+ b = (unsigned char)cmap[lookup[lu1][0]].b;
+ *ptr = RGB_JOIN(r, g, b);
+ ptr++;
+ count++;
+ }
+ else
+ {
+ r = (unsigned char)cmap[lookup[lu1][0]].r;
+ g = (unsigned char)cmap[lookup[lu1][0]].g;
+ b = (unsigned char)cmap[lookup[lu1][0]].b;
+ *ptr = ARGB_JOIN(0xff, r, g, b);
+ ptr++;
+ count++;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0;
+ ((i < 65536) && (ptr < end) && (line[i]));
+ i++)
+ {
+ lu1 = (int)line[i] - 32;
+ if (lu1 < 0) continue;
+ r = (unsigned char)cmap[lookup[lu1][0]].r;
+ g = (unsigned char)cmap[lookup[lu1][0]].g;
+ b = (unsigned char)cmap[lookup[lu1][0]].b;
+ *ptr = ARGB_JOIN(0xff, r, g, b);
+ ptr++;
+ count++;
+ }
+ }
+ }
+ else if (cpp == 2)
+ {
+ if (transp)
+ {
+ for (i = 0;
+ ((i < 65536) && (ptr < end) && (line[i]));
+ i++)
+ {
+ lu1 = (int)line[i] - 32;
+ i++;
+ lu2 = (int)line[i] - 32;
+ if (lu1 < 0) continue;
+ if (lu2 < 0) continue;
+ if (cmap[lookup[lu1][lu2]].transp)
+ {
+ r = (unsigned char)cmap[lookup[lu1][lu2]].r;
+ g = (unsigned char)cmap[lookup[lu1][lu2]].g;
+ b = (unsigned char)cmap[lookup[lu1][lu2]].b;
+ *ptr = RGB_JOIN(r, g, b);
+ ptr++;
+ count++;
+ }
+ else
+ {
+ r = (unsigned char)cmap[lookup[lu1][lu2]].r;
+ g = (unsigned char)cmap[lookup[lu1][lu2]].g;
+ b = (unsigned char)cmap[lookup[lu1][lu2]].b;
+ *ptr = ARGB_JOIN(0xff, r, g, b);
+ ptr++;
+ count++;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0;
+ ((i < 65536) && (ptr < end) && (line[i]));
+ i++)
+ {
+ lu1 = (int)line[i] - 32;
+ i++;
+ lu2 = (int)line[i] - 32;
+ if (lu1 < 0) continue;
+ if (lu2 < 0) continue;
+ r = (unsigned char)cmap[lookup[lu1][lu2]].r;
+ g = (unsigned char)cmap[lookup[lu1][lu2]].g;
+ b = (unsigned char)cmap[lookup[lu1][lu2]].b;
+ *ptr = ARGB_JOIN(0xff, r, g, b);
+ ptr++;
+ count++;
+ }
+ }
+ }
+ else
+ {
+ if (transp)
+ {
+ for (i = 0;
+ ((i < 65536) && (ptr < end) && (line[i]));
+ i++)
+ {
+ Eina_Rbtree *l;
+
+ for (j = 0; j < cpp; j++, i++)
+ {
+ col[j] = line[i];
+ if (col[j] < 32) col[j] = 32;
+ }
+ col[j] = 0;
+ i--;
+
+ l = eina_rbtree_inline_lookup(root, col, j, _cmap_cmp_key_cb, NULL);
+ if (l)
+ {
+ CMap *cm = EINA_RBTREE_CONTAINER_GET(l, CMap);
+
+ r = (unsigned char)cm->r;
+ g = (unsigned char)cm->g;
+ b = (unsigned char)cm->b;
+ if (cm->transp)
+ {
+ *ptr = RGB_JOIN(r, g, b);
+ }
+ else
+ {
+ *ptr = ARGB_JOIN(0xff, r, g, b);
+ }
+
+ ptr++;
+ count++;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0;
+ ((i < 65536) && (ptr < end) && (line[i]));
+ i++)
+ {
+ Eina_Rbtree *l;
+
+ for (j = 0; j < cpp; j++, i++)
+ {
+ col[j] = line[i];
+ }
+ col[j] = 0;
+ i--;
+
+ l = eina_rbtree_inline_lookup(root, col, 0, _cmap_cmp_key_cb, NULL);
+ if (l)
+ {
+ CMap *cm = EINA_RBTREE_CONTAINER_GET(l, CMap);
+
+ r = (unsigned char)cm->r;
+ g = (unsigned char)cm->g;
+ b = (unsigned char)cm->b;
+ *ptr = ARGB_JOIN(0xff, r, g, b);
+ ptr++;
+ count++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ /* Scan in line from XPM file */
+ if ((!comment) && (quote) && (c != '"'))
+ {
+ if (c < 32) c = 32;
+ else if (c > 127) c = 127;
+ if (c =='\\')
+ {
+ if (++backslash < 2)
+ line[i++] = c;
+ else
+ backslash = 0;
+ }
+ else
+ {
+ backslash = 0;
+ line[i++] = c;
+ }
+ }
+ if (i >= lsz)
+ {
+ lsz += 256;
+ tl = realloc(line, lsz);
+ if (!tl) break;
+ line = tl;
+ }
+ if (((ptr) && ((ptr - head) >= (w * h))) ||
+ ((context > 1) && (count >= size)))
+ break;
+ }
+
+ on_success:
+ *error = EVAS_LOAD_ERROR_NONE;
+ res = EINA_TRUE;
+
+ on_error:
+ if (map) eina_file_map_free(f, (void*) map);
+ free(cmap);
+ free(line);
+ return res;
+}
+
+static void *
+evas_image_load_file_open_xpm(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
+ Evas_Image_Load_Opts *opts EINA_UNUSED,
+ Evas_Image_Animated *animated EINA_UNUSED,
+ int *error EINA_UNUSED)
+{
+ return f;
+}
+
+static void
+evas_image_load_file_close_xpm(void *loader_data EINA_UNUSED)
+{
+}
+
+static Eina_Bool
+evas_image_load_file_head_xpm(void *loader_data,
+ Evas_Image_Property *prop,
+ int *error)
+{
+ Eina_File *f = loader_data;
+
+ return evas_image_load_file_xpm(f, prop, NULL, 0, error);
+}
+
+static Eina_Bool
+evas_image_load_file_data_xpm(void *loader_data,
+ Evas_Image_Property *prop,
+ void *pixels,
+ int *error)
+{
+ Eina_File *f = loader_data;
+
+ return evas_image_load_file_xpm(f, prop, pixels, 1, error);
+}
+
+static Evas_Image_Load_Func evas_image_load_xpm_func =
+{
+ evas_image_load_file_open_xpm,
+ evas_image_load_file_close_xpm,
+ evas_image_load_file_head_xpm,
+ evas_image_load_file_data_xpm,
+ NULL,
+ EINA_FALSE,
+ EINA_FALSE
+};
+
+static int
+module_open(Evas_Module *em)
+{
+ if (!em) return 0;
+ _evas_loader_xpm_log_dom = eina_log_domain_register
+ ("evas-xpm", EVAS_DEFAULT_LOG_COLOR);
+ if (_evas_loader_xpm_log_dom < 0)
+ {
+ EINA_LOG_ERR("Can not create a module log domain.");
+ return 0;
+ }
+
+ /* Shouldn't we make that PATH configurable ? */
+ rgb_txt = eina_file_open("/usr/lib/X11/rgb.txt", 0);
+ if (!rgb_txt) rgb_txt = eina_file_open("/usr/X11/lib/X11/rgb.txt", 0);
+ if (!rgb_txt) rgb_txt = eina_file_open("/usr/X11R6/lib/X11/rgb.txt", 0);
+ if (!rgb_txt) rgb_txt = eina_file_open("/usr/openwin/lib/X11/rgb.txt", 0);
+ if (rgb_txt)
+ rgb_txt_map = eina_file_map_all(rgb_txt, EINA_FILE_WILLNEED);
+ em->functions = (void *)(&evas_image_load_xpm_func);
+ return 1;
+}
+
+static void
+module_close(Evas_Module *em EINA_UNUSED)
+{
+ if (rgb_txt)
+ {
+ eina_file_map_free(rgb_txt, rgb_txt_map);
+ eina_file_close(rgb_txt);
+ rgb_txt = NULL;
+ }
+ eina_log_domain_unregister(_evas_loader_xpm_log_dom);
+}
+
+static Evas_Module_Api evas_modapi =
+{
+ EVAS_MODULE_API_VERSION,
+ "xpm",
+ "none",
+ {
+ module_open,
+ module_close
+ }
+};
+
+EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, xpm);
+
+#ifndef EVAS_STATIC_BUILD_XPM
+EVAS_EINA_MODULE_DEFINE(image_loader, xpm);
+#endif