forked from old/legacy-imlib2
Add J2K (JPEG 2000) loader using openjpeg2 library
This commit is contained in:
parent
e8b564f141
commit
9ebd8399d2
|
@ -196,6 +196,7 @@ loader_check_gif() {
|
|||
EC_LOADER_CHECK(GIF, auto, , loader_check_gif)
|
||||
EC_LOADER_CHECK(HEIF, auto, libheif)
|
||||
EC_LOADER_CHECK(JPEG, auto, libjpeg)
|
||||
EC_LOADER_CHECK(J2K, auto, libopenjp2)
|
||||
EC_LOADER_CHECK(JXL, auto, libjxl libjxl_threads)
|
||||
EC_LOADER_CHECK(PNG, auto, libpng)
|
||||
EC_LOADER_CHECK(SVG, auto, librsvg-2.0 >= 2.46)
|
||||
|
@ -284,6 +285,7 @@ echo " Regular image loaders"
|
|||
echo " GIF.....................: $gif_ok"
|
||||
echo " HEIF....................: $heif_ok"
|
||||
echo " JPEG....................: $jpeg_ok"
|
||||
echo " J2K.....................: $j2k_ok"
|
||||
echo " JXL.....................: $jxl_ok"
|
||||
echo " PNG.....................: $png_ok"
|
||||
echo " SVG.....................: $svg_ok"
|
||||
|
|
|
@ -36,6 +36,9 @@ static const char *const ext_ico[] = { "ico", NULL };
|
|||
#ifdef BUILD_JPEG_LOADER
|
||||
static const char *const ext_jpeg[] = { "jpg", "jpeg", "jfif", "jfi", NULL };
|
||||
#endif
|
||||
#ifdef BUILD_J2K_LOADER
|
||||
static const char *const ext_j2k[] = { "jp2", "j2k", NULL };
|
||||
#endif
|
||||
#ifdef BUILD_JXL_LOADER
|
||||
static const char *const ext_jxl[] = { "jxl", NULL };
|
||||
#endif
|
||||
|
@ -86,6 +89,9 @@ static const KnownLoader loaders_known[] = {
|
|||
#ifdef BUILD_JPEG_LOADER
|
||||
{"jpeg", ext_jpeg},
|
||||
#endif
|
||||
#ifdef BUILD_J2K_LOADER
|
||||
{"j2k", ext_j2k},
|
||||
#endif
|
||||
#ifdef BUILD_JXL_LOADER
|
||||
{"jxl", ext_jxl},
|
||||
#endif
|
||||
|
|
|
@ -23,6 +23,9 @@ endif
|
|||
if BUILD_JPEG_LOADER
|
||||
pkg_LTLIBRARIES += jpeg.la
|
||||
endif
|
||||
if BUILD_J2K_LOADER
|
||||
pkg_LTLIBRARIES += j2k.la
|
||||
endif
|
||||
if BUILD_JXL_LOADER
|
||||
pkg_LTLIBRARIES += jxl.la
|
||||
endif
|
||||
|
@ -92,6 +95,12 @@ jpeg_la_LDFLAGS = -module -avoid-version
|
|||
jpeg_la_LIBADD = $(JPEG_LIBS) $(top_builddir)/src/lib/libImlib2.la
|
||||
jpeg_la_LIBTOOLFLAGS = --tag=disable-static
|
||||
|
||||
j2k_la_SOURCES = loader_j2k.c
|
||||
j2k_la_CPPFLAGS = $(J2K_CFLAGS) $(AM_CPPFLAGS)
|
||||
j2k_la_LDFLAGS = -module -avoid-version
|
||||
j2k_la_LIBADD = $(J2K_LIBS) $(top_builddir)/src/lib/libImlib2.la
|
||||
j2k_la_LIBTOOLFLAGS = --tag=disable-static
|
||||
|
||||
jxl_la_SOURCES = loader_jxl.c
|
||||
jxl_la_CPPFLAGS = $(JXL_CFLAGS) $(AM_CPPFLAGS)
|
||||
jxl_la_LDFLAGS = -module -avoid-version
|
||||
|
|
|
@ -0,0 +1,287 @@
|
|||
#include "loader_common.h"
|
||||
|
||||
#include <openjpeg.h>
|
||||
|
||||
#define DBG_PFX "LDR-j2k"
|
||||
|
||||
#define JP2_RFC3745_MAGIC "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a"
|
||||
#define JP2_MAGIC "\x0d\x0a\x87\x0a"
|
||||
/* position 45: "\xff\x52" */
|
||||
#define J2K_CODESTREAM_MAGIC "\xff\x4f\xff\x51"
|
||||
|
||||
#if IMLIB2_DEBUG
|
||||
static void
|
||||
_j2k_cb(const char *type, const char *msg, void *data)
|
||||
{
|
||||
DL("%s: %p: %s: %s", __func__, data, type, msg);
|
||||
}
|
||||
|
||||
static void
|
||||
_j2k_cb_info(const char *msg, void *data)
|
||||
{
|
||||
_j2k_cb("info", msg, data);
|
||||
}
|
||||
|
||||
static void
|
||||
_j2k_cb_warn(const char *msg, void *data)
|
||||
{
|
||||
_j2k_cb("warn", msg, data);
|
||||
}
|
||||
|
||||
static void
|
||||
_j2k_cb_err(const char *msg, void *data)
|
||||
{
|
||||
_j2k_cb("err", msg, data);
|
||||
}
|
||||
#endif /*IMLIB2_DEBUG */
|
||||
|
||||
static struct {
|
||||
const unsigned char *data, *dptr;
|
||||
unsigned int size;
|
||||
} mdata;
|
||||
|
||||
static void
|
||||
mm_init(const void *src, unsigned int size)
|
||||
{
|
||||
mdata.data = mdata.dptr = src;
|
||||
mdata.size = size;
|
||||
}
|
||||
|
||||
static OPJ_SIZE_T
|
||||
mm_read(void *dst, OPJ_SIZE_T len, void *data)
|
||||
{
|
||||
DL("%s: len=%ld\n", __func__, len);
|
||||
|
||||
if (mdata.dptr >= mdata.data + mdata.size)
|
||||
return -1; /* Out of data */
|
||||
if (mdata.dptr + len > mdata.data + mdata.size)
|
||||
len = mdata.data + mdata.size - mdata.dptr;
|
||||
|
||||
memcpy(dst, mdata.dptr, len);
|
||||
mdata.dptr += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static OPJ_OFF_T
|
||||
mm_seek_cur(OPJ_OFF_T offs, void *data)
|
||||
{
|
||||
DL("%s: offs=%ld\n", __func__, offs);
|
||||
|
||||
if (mdata.dptr + offs > mdata.data + mdata.size)
|
||||
return 0; /* Out of data */
|
||||
|
||||
mdata.dptr += offs;
|
||||
|
||||
return mdata.dptr - mdata.data;
|
||||
}
|
||||
|
||||
static OPJ_BOOL
|
||||
mm_seek_set(OPJ_OFF_T offs, void *data)
|
||||
{
|
||||
DL("%s: offs=%ld\n", __func__, offs);
|
||||
|
||||
if (offs > mdata.size)
|
||||
return OPJ_FALSE; /* Out of data */
|
||||
|
||||
mdata.dptr = mdata.data + offs;
|
||||
|
||||
return OPJ_TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
load2(ImlibImage * im, int load_data)
|
||||
{
|
||||
int rc;
|
||||
void *fdata;
|
||||
int ok;
|
||||
opj_dparameters_t jparam;
|
||||
opj_codec_t *jcodec;
|
||||
opj_stream_t *jstream;
|
||||
opj_image_t *jimage;
|
||||
OPJ_CODEC_FORMAT jfmt;
|
||||
int i, j;
|
||||
uint32_t *dst;
|
||||
OPJ_INT32 *pa, *pr, *pg, *pb;
|
||||
unsigned char a, r, g, b;
|
||||
|
||||
fdata = mmap(NULL, im->fsize, PROT_READ, MAP_SHARED, fileno(im->fp), 0);
|
||||
if (fdata == MAP_FAILED)
|
||||
return LOAD_BADFILE;
|
||||
|
||||
rc = LOAD_FAIL;
|
||||
jcodec = NULL;
|
||||
jstream = NULL;
|
||||
jimage = NULL;
|
||||
|
||||
/* Signature check */
|
||||
if (im->fsize < 12)
|
||||
goto quit;
|
||||
|
||||
if (memcmp(fdata, JP2_MAGIC, 4) == 0 ||
|
||||
memcmp(fdata, JP2_RFC3745_MAGIC, 12) == 0)
|
||||
jfmt = OPJ_CODEC_JP2;
|
||||
else if (memcmp(fdata, J2K_CODESTREAM_MAGIC, 4) == 0)
|
||||
jfmt = OPJ_CODEC_J2K;
|
||||
else
|
||||
goto quit;
|
||||
|
||||
DL("format=%d\n", jfmt);
|
||||
|
||||
memset(&jparam, 0, sizeof(opj_dparameters_t));
|
||||
opj_set_default_decoder_parameters(&jparam);
|
||||
|
||||
jcodec = opj_create_decompress(jfmt);
|
||||
if (!jcodec)
|
||||
goto quit;
|
||||
|
||||
rc = LOAD_BADIMAGE; /* Format accepted */
|
||||
|
||||
#if IMLIB2_DEBUG
|
||||
opj_set_info_handler(jcodec, _j2k_cb_info, NULL);
|
||||
opj_set_warning_handler(jcodec, _j2k_cb_warn, NULL);
|
||||
opj_set_error_handler(jcodec, _j2k_cb_err, NULL);
|
||||
#endif
|
||||
|
||||
ok = opj_setup_decoder(jcodec, &jparam);
|
||||
if (!ok)
|
||||
goto quit;
|
||||
|
||||
// May be set with OPJ_NUM_THREADS=number or ALL_CPUS
|
||||
// opj_codec_set_threads(jcodec, 4);
|
||||
|
||||
if (getenv("JP2_USE_FILE"))
|
||||
{
|
||||
jstream =
|
||||
opj_stream_create_default_file_stream(im->real_file, OPJ_TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
jstream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE, OPJ_TRUE);
|
||||
if (!jstream)
|
||||
goto quit;
|
||||
|
||||
mm_init(fdata, im->fsize);
|
||||
opj_stream_set_user_data(jstream, &mdata, NULL);
|
||||
opj_stream_set_user_data_length(jstream, im->fsize);
|
||||
opj_stream_set_read_function(jstream, mm_read);
|
||||
opj_stream_set_skip_function(jstream, mm_seek_cur);
|
||||
opj_stream_set_seek_function(jstream, mm_seek_set);
|
||||
}
|
||||
|
||||
opj_read_header(jstream, jcodec, &jimage);
|
||||
if (!jimage)
|
||||
goto quit;
|
||||
im->w = jimage->x1 - jimage->x0;
|
||||
im->h = jimage->y1 - jimage->y0;
|
||||
IM_FLAG_UPDATE(im, F_HAS_ALPHA,
|
||||
jimage->numcomps == 4 || jimage->numcomps == 2);
|
||||
D("WxH=%dx%d alpha=%d numcomp=%d colorspace=%d\n",
|
||||
im->w, im->h, IM_FLAG_ISSET(im, F_HAS_ALPHA),
|
||||
jimage->numcomps, jimage->color_space);
|
||||
|
||||
for (i = 0; i < (int)jimage->numcomps; i++)
|
||||
{
|
||||
DL("%d: dx/y=%d/%d wxh=%d,%d prec=%d bpp=%d sgnd=%d fact=%d\n", i,
|
||||
jimage->comps[i].dx, jimage->comps[i].dy,
|
||||
jimage->comps[i].w, jimage->comps[i].h,
|
||||
jimage->comps[i].prec, jimage->comps[i].bpp,
|
||||
jimage->comps[i].sgnd, jimage->comps[i].factor);
|
||||
if (jimage->comps[0].dx != jimage->comps[i].dx ||
|
||||
jimage->comps[0].dy != jimage->comps[i].dy ||
|
||||
(int)jimage->comps[i].w != im->w ||
|
||||
(int)jimage->comps[i].h != im->h)
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (!load_data)
|
||||
QUIT_WITH_RC(LOAD_SUCCESS);
|
||||
|
||||
/* Load data */
|
||||
|
||||
ok = opj_decode(jcodec, jstream, jimage);
|
||||
if (!ok)
|
||||
goto quit;
|
||||
|
||||
ok = opj_end_decompress(jcodec, jstream);
|
||||
if (!ok)
|
||||
goto quit;
|
||||
|
||||
if (!__imlib_AllocateData(im))
|
||||
QUIT_WITH_RC(LOAD_OOM);
|
||||
|
||||
/* Ignoring color_space and data format details... */
|
||||
|
||||
dst = im->data;
|
||||
pa = jimage->comps[0].data; /* Avoid compiler warning */
|
||||
|
||||
switch (jimage->numcomps)
|
||||
{
|
||||
default:
|
||||
goto quit;
|
||||
|
||||
case 4: /* RGBA */
|
||||
pa = jimage->comps[3].data;
|
||||
/* FALLTHROUGH */
|
||||
case 3: /* RGB */
|
||||
pr = jimage->comps[0].data;
|
||||
pg = jimage->comps[1].data;
|
||||
pb = jimage->comps[2].data;
|
||||
for (i = 0; i < im->h; i++)
|
||||
{
|
||||
for (j = 0; j < im->w; j++)
|
||||
{
|
||||
r = *pr++;
|
||||
g = *pg++;
|
||||
b = *pb++;
|
||||
a = (jimage->numcomps == 4) ? *pa++ : 0xff;
|
||||
|
||||
*dst++ = PIXEL_ARGB(a, r, g, b);
|
||||
}
|
||||
|
||||
if (im->lc && __imlib_LoadProgressRows(im, i, 1))
|
||||
QUIT_WITH_RC(LOAD_BREAK);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: /* Gray with A */
|
||||
pa = jimage->comps[1].data;
|
||||
/* FALLTHROUGH */
|
||||
case 1: /* Gray */
|
||||
pg = jimage->comps[0].data;
|
||||
for (i = 0; i < im->h; i++)
|
||||
{
|
||||
for (j = 0; j < im->w; j++)
|
||||
{
|
||||
g = *pg++;
|
||||
a = (jimage->numcomps == 2) ? *pa++ : 0xff;
|
||||
|
||||
*dst++ = PIXEL_ARGB(a, g, g, g);
|
||||
}
|
||||
|
||||
if (im->lc && __imlib_LoadProgressRows(im, i, 1))
|
||||
QUIT_WITH_RC(LOAD_BREAK);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
rc = LOAD_SUCCESS;
|
||||
|
||||
quit:
|
||||
if (jimage)
|
||||
opj_image_destroy(jimage);
|
||||
if (jstream)
|
||||
opj_stream_destroy(jstream);
|
||||
if (jcodec)
|
||||
opj_destroy_codec(jcodec);
|
||||
munmap(fdata, im->fsize);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
formats(ImlibLoader * l)
|
||||
{
|
||||
static const char *const list_formats[] = { "jp2", "j2k" };
|
||||
__imlib_LoaderSetFormats(l, list_formats, ARRAY_SIZE(list_formats));
|
||||
}
|
Loading…
Reference in New Issue