summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--m4/evas_check_loader.m416
-rw-r--r--src/Makefile_Evas.am52
-rw-r--r--src/lib/evas/common/evas_image_load.c3
-rw-r--r--src/lib/evas/file/evas_module.c4
-rw-r--r--src/modules/evas/loaders/tgv/evas_image_load_tgv.c359
6 files changed, 436 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 3642b96a65..a848345bda 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1419,6 +1419,7 @@ ARG_ENABLE_EVAS_IMAGE_LOADER(Tiff, yes)
1419ARG_ENABLE_EVAS_IMAGE_LOADER(WBMP, static) 1419ARG_ENABLE_EVAS_IMAGE_LOADER(WBMP, static)
1420ARG_ENABLE_EVAS_IMAGE_LOADER(WEBP, no) 1420ARG_ENABLE_EVAS_IMAGE_LOADER(WEBP, no)
1421ARG_ENABLE_EVAS_IMAGE_LOADER(XPM, static) 1421ARG_ENABLE_EVAS_IMAGE_LOADER(XPM, static)
1422ARG_ENABLE_EVAS_IMAGE_LOADER(TGV, static)
1422 1423
1423### Default values 1424### Default values
1424 1425
@@ -1700,6 +1701,7 @@ EVAS_CHECK_IMAGE_LOADER([Tiff], [${want_evas_image_loader_tiff}])
1700EVAS_CHECK_IMAGE_LOADER([WBMP], [${want_evas_image_loader_wbmp}]) 1701EVAS_CHECK_IMAGE_LOADER([WBMP], [${want_evas_image_loader_wbmp}])
1701EVAS_CHECK_IMAGE_LOADER([WEBP], [${want_evas_image_loader_webp}]) 1702EVAS_CHECK_IMAGE_LOADER([WEBP], [${want_evas_image_loader_webp}])
1702EVAS_CHECK_IMAGE_LOADER([XPM], [${want_evas_image_loader_xpm}]) 1703EVAS_CHECK_IMAGE_LOADER([XPM], [${want_evas_image_loader_xpm}])
1704EVAS_CHECK_IMAGE_LOADER([TGV], [${want_evas_image_loader_tgv}])
1703 1705
1704dnl Windows has no sigsetjmp function, nor equivalent. 1706dnl Windows has no sigsetjmp function, nor equivalent.
1705dnl So we disable the jpeg saver. 1707dnl So we disable the jpeg saver.
diff --git a/m4/evas_check_loader.m4 b/m4/evas_check_loader.m4
index b34c28fc05..07d9cdd87e 100644
--- a/m4/evas_check_loader.m4
+++ b/m4/evas_check_loader.m4
@@ -341,6 +341,22 @@ AS_IF([test "x${have_dep}" = "xyes"], [$3], [$4])
341 341
342]) 342])
343 343
344dnl use: EVAS_CHECK_LOADER_DEP_TGV(loader, want_static[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
345
346AC_DEFUN([EVAS_CHECK_LOADER_DEP_TGV],
347[
348
349have_dep="yes"
350evas_image_loader_[]$1[]_cflags=""
351evas_image_loader_[]$1[]_libs=""
352
353AC_SUBST([evas_image_loader_$1_cflags])
354AC_SUBST([evas_image_loader_$1_libs])
355
356AS_IF([test "x${have_dep}" = "xyes"], [$3], [$4])
357
358])
359
344dnl use: EVAS_CHECK_LOADER_DEP_SVG(loader, want_static[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) 360dnl use: EVAS_CHECK_LOADER_DEP_SVG(loader, want_static[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
345 361
346AC_DEFUN([EVAS_CHECK_LOADER_DEP_SVG], 362AC_DEFUN([EVAS_CHECK_LOADER_DEP_SVG],
diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am
index 6132592ceb..5f07710a67 100644
--- a/src/Makefile_Evas.am
+++ b/src/Makefile_Evas.am
@@ -1712,6 +1712,58 @@ modules_evas_loaders_xpm_module_la_LIBTOOLFLAGS = --tag=disable-static
1712endif 1712endif
1713endif 1713endif
1714 1714
1715if BUILD_LOADER_TGV
1716if EVAS_STATIC_BUILD_TGV
1717lib_evas_libevas_la_SOURCES += \
1718modules/evas/loaders/tgv/evas_image_load_tgv.c \
1719static_libs/rg_etc/rg_etc1.c \
1720static_libs/rg_etc/rg_etc1.h \
1721static_libs/lz4/lz4.c \
1722static_libs/lz4/lz4.h
1723lib_evas_libevas_la_CPPFLAGS += \
1724-I$(top_srcdir)/src/static_libs/lz4 \
1725-I$(top_srcdir)/src/static_libs/rg_etc \
1726@evas_image_loader_tgv_cflags@
1727lib_evas_libevas_la_LIBADD += @evas_image_loader_tgv_libs@
1728if EVAS_CSERVE2
1729bin_evas_evas_cserve2_slave_SOURCES += \
1730modules/evas/loaders/tgv/evas_image_load_tgv.c \
1731static_libs/rg_etc/rg_etc1.c \
1732static_libs/rg_etc/rg_etc1.h \
1733static_libs/lz4/lz4.c \
1734static_libs/lz4/lz4.h
1735bin_evas_evas_cserve2_slave_CPPFLAGS += \
1736-I$(top_builddir)/src/lib/efl \
1737-I$(top_srcdir)/src/static_libs/lz4 \
1738-I$(top_srcdir)/src/static_libs/rg_etc \
1739-I$(top_srcdir)/src/lib/evas/ \
1740@evas_image_loader_tgv_cflags@
1741bin_evas_evas_cserve2_slave_LDADD += @evas_image_loader_tgv_libs@
1742endif
1743else
1744loadertgvpkgdir = $(libdir)/evas/modules/loaders/tgv/$(MODULE_ARCH)
1745loadertgvpkg_LTLIBRARIES = modules/evas/loaders/tgv/module.la
1746modules_evas_loaders_tgv_module_la_SOURCES = \
1747modules/evas/loaders/tgv/evas_image_load_tgv.c \
1748static_libs/rg_etc/rg_etc1.c \
1749static_libs/rg_etc/rg_etc1.h \
1750static_libs/lz4/lz4.c \
1751static_libs/lz4/lz4.h
1752modules_evas_loaders_tgv_module_la_CPPFLAGS = \
1753-I$(top_builddir)/src/lib/efl \
1754-I$(top_srcdir)/src/static_libs/lz4 \
1755-I$(top_srcdir)/src/static_libs/rg_etc \
1756-I$(top_srcdir)/src/lib/evas/ \
1757@EVAS_CFLAGS@ \
1758@evas_image_loader_tgv_cflags@
1759modules_evas_loaders_tgv_module_la_LIBADD = \
1760@USE_EVAS_LIBS@ \
1761@evas_image_loader_tgv_libs@
1762modules_evas_loaders_tgv_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@
1763modules_evas_loaders_tgv_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
1764modules_evas_loaders_tgv_module_la_LIBTOOLFLAGS = --tag=disable-static
1765endif
1766endif
1715 1767
1716### Unit tests 1768### Unit tests
1717 1769
diff --git a/src/lib/evas/common/evas_image_load.c b/src/lib/evas/common/evas_image_load.c
index 92c6402f8c..52d3295ec4 100644
--- a/src/lib/evas/common/evas_image_load.c
+++ b/src/lib/evas/common/evas_image_load.c
@@ -64,6 +64,9 @@ static const struct ext_loader_s loaders[] =
64 MATCHING(".cur", "ico"), 64 MATCHING(".cur", "ico"),
65 65
66 MATCHING(".psd", "psd"), 66 MATCHING(".psd", "psd"),
67
68 MATCHING(".tgv", "tgv"),
69
67 /* xcf - gefenric */ 70 /* xcf - gefenric */
68 MATCHING(".xcf", "generic"), 71 MATCHING(".xcf", "generic"),
69 MATCHING(".xcf.gz", "generic"), 72 MATCHING(".xcf.gz", "generic"),
diff --git a/src/lib/evas/file/evas_module.c b/src/lib/evas/file/evas_module.c
index 28b4243cdd..6cb5dc66bd 100644
--- a/src/lib/evas/file/evas_module.c
+++ b/src/lib/evas/file/evas_module.c
@@ -140,6 +140,7 @@ EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, tiff);
140EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, wbmp); 140EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, wbmp);
141EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, webp); 141EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, webp);
142EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, xpm); 142EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, xpm);
143EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, tgv);
143#endif 144#endif
144 145
145#if !EVAS_MODULE_NO_IMAGE_SAVERS 146#if !EVAS_MODULE_NO_IMAGE_SAVERS
@@ -232,6 +233,9 @@ static const struct {
232#ifdef EVAS_STATIC_BUILD_XPM 233#ifdef EVAS_STATIC_BUILD_XPM
233 EVAS_EINA_STATIC_MODULE_USE(image_loader, xpm), 234 EVAS_EINA_STATIC_MODULE_USE(image_loader, xpm),
234#endif 235#endif
236#ifdef EVAS_STATIC_BUILD_TGV
237 EVAS_EINA_STATIC_MODULE_USE(image_loader, tgv),
238#endif
235#endif 239#endif
236#if !EVAS_MODULE_NO_IMAGE_SAVERS 240#if !EVAS_MODULE_NO_IMAGE_SAVERS
237#ifdef EVAS_STATIC_BUILD_EET 241#ifdef EVAS_STATIC_BUILD_EET
diff --git a/src/modules/evas/loaders/tgv/evas_image_load_tgv.c b/src/modules/evas/loaders/tgv/evas_image_load_tgv.c
new file mode 100644
index 0000000000..308d0b6f22
--- /dev/null
+++ b/src/modules/evas/loaders/tgv/evas_image_load_tgv.c
@@ -0,0 +1,359 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#ifdef HAVE_NETINET_IN_H
6# include <netinet/in.h>
7#endif
8
9#ifdef _WIN32
10# include <winsock2.h>
11#endif /* ifdef _WIN32 */
12
13#include "lz4.h"
14#include "rg_etc1.h"
15#include "Evas_Loader.h"
16
17/**************************************************************
18 * The TGV file format is oriented around compression mecanism
19 * that hardware are good at decompressing. We do still provide
20 * a fully software implementation in case your hardware doesn't
21 * handle it.
22 *
23 * This file format is designed to compress/decompress things
24 * in block area. Giving opportunity to store really huge file
25 * and only decompress/compress them as we need.
26 *
27 * The file format is as follow :
28 * - char magic[4]: "TGV1"
29 * - uint8_t block_size (real block size = (4 << bits[0-3], 4 << bits[4-7])
30 * - uint8_t algorithm (0 -> ETC1)
31 * - uint8_t options[2] (1 -> lz4)
32 * - uint32_t width
33 * - uint32_t height
34 * - blocks[]
35 * - 0 length encoded compress size (if length == 64 * block_size => no compression)
36 * - lzma encoded etc1 block
37 **************************************************************/
38
39// FIXME: wondering if we should support mipmap
40// FIXME: instead of the complete size, maybe just the usefull left over byte + number of block.
41
42typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
43struct _Evas_Loader_Internal
44{
45 Eina_File *f;
46
47 Eina_Rectangle region;
48
49 struct {
50 unsigned int width;
51 unsigned int height;
52 } block;
53 struct {
54 unsigned int width;
55 unsigned int height;
56 } size;
57
58 Eina_Bool compress;
59};
60
61
62static void *
63evas_image_load_file_open_tgv(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
64 Evas_Image_Load_Opts *opts,
65 Evas_Image_Animated *animated EINA_UNUSED,
66 int *error)
67{
68 Evas_Loader_Internal *loader;
69
70 loader = calloc(1, sizeof (Evas_Loader_Internal));
71 if (!loader)
72 {
73 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
74 return NULL;
75 }
76
77 if (eina_file_size_get(f) <= 16)
78 {
79 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
80 return NULL;
81 }
82
83 loader->f = eina_file_dup(f);
84 if (!loader->f)
85 {
86 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
87 return NULL;
88 }
89
90 if (opts && (opts->region.w > 0) && (opts->region.h > 0))
91 {
92 EINA_RECTANGLE_SET(&loader->region,
93 opts->region.x,
94 opts->region.y,
95 opts->region.w,
96 opts->region.h);
97 }
98 else
99 {
100 EINA_RECTANGLE_SET(&loader->region,
101 0, 0,
102 -1, -1);
103 }
104
105 return loader;
106}
107
108
109static void
110evas_image_load_file_close_tgv(void *loader_data)
111{
112 Evas_Loader_Internal *loader = loader_data;
113
114 eina_file_close(loader->f);
115 free(loader);
116}
117
118#define OFFSET_BLOCK_SIZE 4
119#define OFFSET_ALGORITHN 5
120#define OFFSET_OPTIONS 6
121#define OFFSET_WIDTH 8
122#define OFFSET_HEIGHT 12
123#define OFFSET_BLOCKS 16
124
125static Eina_Bool
126evas_image_load_file_head_tgv(void *loader_data,
127 Evas_Image_Property *prop,
128 int *error)
129{
130 Evas_Loader_Internal *loader = loader_data;
131 const char *m;
132
133 m = eina_file_map_all(loader->f, EINA_FILE_SEQUENTIAL);
134 if (!m)
135 {
136 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
137 return EINA_FALSE;
138 }
139
140 if (strncmp(m, "TGV1", 4) != 0)
141 {
142 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
143 return EINA_FALSE;
144 }
145
146 loader->block.width = 4 << (m[OFFSET_BLOCK_SIZE] & 0x0f);
147 loader->block.height = 4 << ((m[OFFSET_BLOCK_SIZE] & 0xf0) >> 4);
148
149 if (m[OFFSET_ALGORITHN] != 0)
150 {
151 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
152 return EINA_FALSE;
153 }
154
155 loader->compress = m[OFFSET_OPTIONS] & 0x1;
156
157 loader->size.width = ntohl(*((unsigned int*) &(m[OFFSET_WIDTH])));
158 loader->size.height = ntohl(*((unsigned int*) &(m[OFFSET_HEIGHT])));
159
160 if (loader->region.w == -1 &&
161 loader->region.h == -1)
162 {
163 loader->region.w = loader->size.width;
164 loader->region.h = loader->size.height;
165 }
166 else
167 {
168 Eina_Rectangle r;
169
170 EINA_RECTANGLE_SET(&r, 0, 0, loader->size.width, loader->size.height);
171 if (!eina_rectangle_intersection(&loader->region, &r))
172 {
173 *error = EVAS_LOAD_ERROR_GENERIC;
174 return EINA_FALSE;
175 }
176 }
177
178 prop->w = loader->size.width;
179 prop->h = loader->size.height;
180
181 return EINA_TRUE;
182}
183
184static inline unsigned int
185_tgv_length_get(const char *m, unsigned int length, unsigned int *offset)
186{
187 unsigned int r = 0;
188 unsigned int shift = 0;
189
190 while (*offset < length && ((*m) & 0x80))
191 {
192 r = r | (((*m) & 0x7F) << shift);
193 shift += 7;
194 m++;
195 (*offset)++;
196 }
197 if (*offset < length)
198 {
199 r = r | (((*m) & 0x7F) << shift);
200 (*offset)++;
201 }
202
203 return r;
204}
205
206Eina_Bool
207evas_image_load_file_data_tgv(void *loader_data,
208 Evas_Image_Property *prop,
209 void *pixels,
210 int *error)
211{
212 Evas_Loader_Internal *loader = loader_data;
213 const char *m;
214 unsigned int *p = pixels;
215 char *buffer;
216 Eina_Rectangle master;
217 unsigned int block_length;
218 unsigned int length, offset;
219 unsigned int x, y;
220 unsigned int block_count;
221 Eina_Bool r = EINA_FALSE;
222
223 length = eina_file_size_get(loader->f);
224 offset = OFFSET_BLOCKS;
225
226 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
227
228 m = eina_file_map_all(loader->f, EINA_FILE_WILLNEED);
229 if (!m) return EINA_FALSE;
230
231 // By definition, prop{.w, .h} == region{.w, .h}
232 EINA_RECTANGLE_SET(&master,
233 loader->region.x, loader->region.y,
234 prop->w, prop->h);
235
236 // Allocate space for each ETC1 block (64bytes per 4 * 4 pixels group)
237 block_count = loader->block.width * loader->block.height / (4 * 4);
238 if (loader->compress)
239 buffer = alloca(8 * block_count);
240 else
241 buffer = NULL;
242
243 for (y = 0; y < loader->size.height; y += loader->block.height)
244 for (x = 0; x < loader->size.width; x += loader->block.width)
245 {
246 Eina_Rectangle current;
247 const char *data_start;
248 const char *it;
249 unsigned int expand_length;
250 unsigned int i, j;
251
252 block_length = _tgv_length_get(m + offset, length, &offset);
253
254 if (block_length == 0) goto on_error;
255
256 data_start = m + offset;
257 offset += block_length;
258
259 EINA_RECTANGLE_SET(&current, x, y,
260 loader->block.width, loader->block.height);
261
262 if (!eina_rectangle_intersection(&current, &master))
263 continue ;
264
265 if (loader->compress)
266 {
267 expand_length = LZ4_uncompress(data_start,
268 buffer, block_count * 8);
269 // That's an overhead for now, need to be fixed
270 if (expand_length != block_length)
271 goto on_error;
272 }
273 else
274 {
275 buffer = (void*) data_start;
276 if (block_count * 8 != block_length)
277 goto on_error;
278 }
279 it = buffer;
280
281 for (i = 0; i < loader->block.height; i += 4)
282 for (j = 0; j < loader->block.width; j += 4, it += 8)
283 {
284 Eina_Rectangle current_etc;
285 unsigned int temporary[4 * 4] = { 0 };
286 unsigned int offset_x, offset_y;
287 int k;
288
289 EINA_RECTANGLE_SET(&current_etc, x + j, y + i, 4, 4);
290
291 if (!eina_rectangle_intersection(&current_etc, &current))
292 continue ;
293
294 if (!rg_etc1_unpack_block(it, temporary, 0))
295 {
296 fprintf(stderr, "HOUSTON WE HAVE A PROBLEM ! Block starting at {%i, %i} is corrupted !\n", x + j, y + i);
297 continue ;
298 }
299
300 offset_x = current_etc.x - x - j;
301 offset_y = current_etc.y - y - i;
302 for (k = 0; k < current_etc.h; k++)
303 {
304 memcpy(&p[current_etc.x +
305 (current_etc.y + k) * loader->region.w],
306 &temporary[offset_x + (offset_y + k) * 4],
307 current_etc.w * sizeof (unsigned int));
308 }
309 }
310 }
311
312 r = EINA_TRUE;
313 *error = EVAS_LOAD_ERROR_NONE;
314
315 on_error:
316 eina_file_map_free(loader->f, (void*) m);
317 return r;
318}
319
320Evas_Image_Load_Func evas_image_load_tgv_func =
321{
322 evas_image_load_file_open_tgv,
323 evas_image_load_file_close_tgv,
324 evas_image_load_file_head_tgv,
325 evas_image_load_file_data_tgv,
326 NULL,
327 EINA_TRUE,
328 EINA_FALSE
329};
330
331static int
332module_open(Evas_Module *em)
333{
334 if (!em) return 0;
335 em->functions = (void *)(&evas_image_load_tgv_func);
336 return 1;
337}
338
339static void
340module_close(Evas_Module *em EINA_UNUSED)
341{
342}
343
344static Evas_Module_Api evas_modapi =
345{
346 EVAS_MODULE_API_VERSION,
347 "tgv",
348 "none",
349 {
350 module_open,
351 module_close
352 }
353};
354
355EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, tgv);
356
357#ifndef EVAS_STATIC_BUILD_TGV
358EVAS_EINA_MODULE_DEFINE(image_loader, tgv);
359#endif