kwo pushed a commit to branch master.

http://git.enlightenment.org/legacy/imlib2.git/commit/?id=9ebd8399d2247a79e827d4820a449195377c152a

commit 9ebd8399d2247a79e827d4820a449195377c152a
Author: Kim Woelders <[email protected]>
Date:   Fri Apr 8 13:45:43 2022 +0200

    Add J2K (JPEG 2000) loader using openjpeg2 library
---
 configure.ac                     |   2 +
 src/lib/loaders.c                |   6 +
 src/modules/loaders/Makefile.am  |   9 ++
 src/modules/loaders/loader_j2k.c | 287 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 304 insertions(+)

diff --git a/configure.ac b/configure.ac
index 9d063e2..c2b59db 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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"
diff --git a/src/lib/loaders.c b/src/lib/loaders.c
index d1142e7..c6098ed 100644
--- a/src/lib/loaders.c
+++ b/src/lib/loaders.c
@@ -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
diff --git a/src/modules/loaders/Makefile.am b/src/modules/loaders/Makefile.am
index bd31d54..cdd637c 100644
--- a/src/modules/loaders/Makefile.am
+++ b/src/modules/loaders/Makefile.am
@@ -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
diff --git a/src/modules/loaders/loader_j2k.c b/src/modules/loaders/loader_j2k.c
new file mode 100644
index 0000000..00ed490
--- /dev/null
+++ b/src/modules/loaders/loader_j2k.c
@@ -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));
+}

-- 


Reply via email to