evas: add JPEG 2000 loader.

This add finally support for JPEG 2000, but be aware that libopenjpeg
is very badly managed. There is currently only version 1.5.x that does
provide the right files, is usable by a third party and portable. You
can seriously forget any other version.
This commit is contained in:
Vincent Torri 2013-09-28 14:28:41 +02:00 committed by Cedric Bail
parent 83eaf14f32
commit 3b8b2ac66c
8 changed files with 513 additions and 0 deletions

View File

@ -1,3 +1,7 @@
2013-10-01 Vincent Torri
* Evas: add JPEG 2000 support.
2013-09-25 Tom Hacohen
* Evas font: Make the evas_font_path_* functions apply to fontconfig searches.

1
NEWS
View File

@ -68,6 +68,7 @@ Additions:
- Add interceptor for focus_set.
- Evas font: Use our own fontconfig configuration so we don't get affected by changes made to the default fontconfig configuration.
- Evas font: Make the evas_font_path_* functions apply to fontconfig searches.
- Add JPEG 2000 loader.
* Ecore_X:
- Add window profile support.
ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED

View File

@ -1241,6 +1241,7 @@ ARG_ENABLE_EVAS_IMAGE_LOADER(Generic, static)
ARG_ENABLE_EVAS_IMAGE_LOADER(Gif, yes)
ARG_ENABLE_EVAS_IMAGE_LOADER(ICO, static)
ARG_ENABLE_EVAS_IMAGE_LOADER(JPEG, static)
ARG_ENABLE_EVAS_IMAGE_LOADER(JP2K, auto)
ARG_ENABLE_EVAS_IMAGE_LOADER(PMAPS, static)
ARG_ENABLE_EVAS_IMAGE_LOADER(PNG, static)
ARG_ENABLE_EVAS_IMAGE_LOADER(PSD, static)
@ -1522,6 +1523,7 @@ EVAS_CHECK_IMAGE_LOADER([Generic], [${want_evas_image_loader_generic}])
EVAS_CHECK_IMAGE_LOADER([Gif], [${want_evas_image_loader_gif}])
EVAS_CHECK_IMAGE_LOADER([ICO], [${want_evas_image_loader_ico}])
EVAS_CHECK_IMAGE_LOADER([JPEG], [${want_evas_image_loader_jpeg}])
EVAS_CHECK_IMAGE_LOADER([JP2K], [${want_evas_image_loader_jp2k}])
EVAS_CHECK_IMAGE_LOADER([PMAPS], [${want_evas_image_loader_pmaps}])
EVAS_CHECK_IMAGE_LOADER([PNG], [${want_evas_image_loader_png}])
EVAS_CHECK_IMAGE_LOADER([PSD], [${want_evas_image_loader_psd}])

View File

@ -184,6 +184,68 @@ AS_IF([test "x${have_dep}" = "xyes"], [$3], [$4])
])
dnl use: EVAS_CHECK_LOADER_DEP_JP2K(loader, want_static[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
AC_DEFUN([EVAS_CHECK_LOADER_DEP_JP2K],
[
have_dep="no"
have_dep_pc="no"
evas_image_loader_[]$1[]_cflags=""
evas_image_loader_[]$1[]_libs=""
AC_CHECK_HEADER([openjpeg.h], [have_dep="yes"])
if test "x${have_dep}" = "xyes" ; then
AC_CHECK_LIB([openjp2],
[opj_set_default_decoder_parameters],
[
evas_image_loader_[]$1[]_libs="-lopenjp2"
have_dep="yes"
],
[have_dep="no"])
fi
if test "x${have_dep}" = "xno" ; then
PKG_CHECK_EXISTS([libopenjpeg1 >= 1.5],
[
have_dep="yes"
have_dep_pc="yes"
requirement="libopenjpeg1 >= 1.5"
],
[have_dep="no"])
fi
if test "x${have_dep}" = "xno" ; then
PKG_CHECK_EXISTS([libopenjpeg >= 1.5],
[
have_dep="yes"
have_dep_pc="yes"
requirement="libopenjpeg >= 1.5"
],
[have_dep="no"])
fi
if test "x${have_dep}" = "xyes" ; then
if test "x$2" = "xstatic" ; then
requirements_pc_evas="${requirement} ${requirements_pc_evas}"
requirements_pc_deps_evas="${requirement} ${requirements_pc_deps_evas}"
requirements_libs_evas="${evas_image_loader_[]$1[]_libs} ${requirements_libs_evas}"
fi
if test "x${have_dep_pc}" = "xyes" ; then
PKG_CHECK_MODULES([JP2K], [${requirement}])
evas_image_loader_[]$1[]_cflags="${JP2K_CFLAGS}"
evas_image_loader_[]$1[]_libs="${JP2K_LIBS}"
fi
fi
AC_SUBST([evas_image_loader_$1_cflags])
AC_SUBST([evas_image_loader_$1_libs])
AS_IF([test "x${have_dep}" = "xyes"], [$3], [$4])
])
dnl use: EVAS_CHECK_LOADER_DEP_PMAPS(loader, want_static[[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
AC_DEFUN([EVAS_CHECK_LOADER_DEP_PMAPS],

View File

@ -1275,6 +1275,33 @@ endif
endif
endif
if BUILD_LOADER_JP2K
if EVAS_STATIC_BUILD_JP2K
lib_evas_libevas_la_SOURCES += modules/evas/loaders/jp2k/evas_image_load_jp2k.c
lib_evas_libevas_la_CPPFLAGS += @evas_image_loader_jp2k_cflags@
lib_evas_libevas_la_LIBADD += @evas_image_loader_jp2k_libs@
if EVAS_CSERVE2
bin_evas_evas_cserve2_slave_SOURCES += modules/evas/loaders/jp2k/evas_image_load_jp2k.c
bin_evas_evas_cserve2_slave_CPPFLAGS += @evas_image_loader_jp2k_cflags@
bin_evas_evas_cserve2_slave_LDADD += @evas_image_loader_jp2k_libs@
endif
else
loaderjp2kpkgdir = $(libdir)/evas/modules/loaders/jp2k/$(MODULE_ARCH)
loaderjp2kpkg_LTLIBRARIES = modules/evas/loaders/jp2k/module.la
modules_evas_loaders_jp2k_module_la_SOURCES = modules/evas/loaders/jp2k/evas_image_load_jp2k.c
modules_evas_loaders_jp2k_module_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
-I$(top_srcdir)/src/lib/evas/include \
@EVAS_CFLAGS@ \
@evas_image_loader_jp2k_cflags@
modules_evas_loaders_jp2k_module_la_LIBADD = \
@USE_EVAS_LIBS@ \
@evas_image_loader_jp2k_libs@
modules_evas_loaders_jp2k_module_la_DEPENDENCIES = @USE_EVAS_INTERNAL_LIBS@
modules_evas_loaders_jp2k_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
modules_evas_loaders_jp2k_module_la_LIBTOOLFLAGS = --tag=disable-static
endif
endif
if BUILD_LOADER_PMAPS
if EVAS_STATIC_BUILD_PMAPS
lib_evas_libevas_la_SOURCES += modules/evas/loaders/pmaps/evas_image_load_pmaps.c

View File

@ -29,6 +29,10 @@ static const struct ext_loader_s loaders[] =
MATCHING(".jpg", "jpeg"),
MATCHING(".jpeg", "jpeg"),
MATCHING(".jfif", "jpeg"),
MATCHING(".j2k", "jp2k"),
MATCHING(".jp2", "jp2k"),
MATCHING(".jpx", "jp2k"),
MATCHING(".jpf", "jp2k"),
MATCHING(".eet", "eet"),
MATCHING(".edj", "eet"),
MATCHING(".eap", "eet"),

View File

@ -136,6 +136,7 @@ EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, generic);
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, gif);
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, ico);
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, jpeg);
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, jp2k);
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, pmaps);
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, png);
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, psd);
@ -207,6 +208,9 @@ static const struct {
#ifdef EVAS_STATIC_BUILD_JPEG
EVAS_EINA_STATIC_MODULE_USE(image_loader, jpeg),
#endif
#ifdef EVAS_STATIC_BUILD_JP2K
EVAS_EINA_STATIC_MODULE_USE(image_loader, jp2k),
#endif
#ifdef EVAS_STATIC_BUILD_PMAPS
EVAS_EINA_STATIC_MODULE_USE(image_loader, pmaps),
#endif

View File

@ -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, void *data EINA_UNUSED)
{
ERR("OpenJPEG internal error: '%s'.", msg);
}
static void
_jp2k_warning_cb(const char *msg, void *data EINA_UNUSED)
{
WRN("OpenJPEG internal warning: '%s'.", msg);
}
static void
_jp2k_info_cb(const char *msg, 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