[gimp/muks/openjpeg] file-jp2-load: Switch from Jasper to OpenJPEG library



commit 32f60acead3e475687c8469d34e47fd497dee97f
Author: Mukund Sivaraman <muks banu com>
Date:   Mon Feb 20 01:36:26 2017 +0530

    file-jp2-load: Switch from Jasper to OpenJPEG library

 configure.ac                    |   34 +-
 plug-ins/common/Makefile.am     |    4 +-
 plug-ins/common/file-jp2-load.c |  909 ++++++++++++++++++++++++++++++---------
 plug-ins/common/plugin-defs.pl  |    2 +-
 4 files changed, 734 insertions(+), 215 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index a4df228..f00feb0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -73,6 +73,7 @@ m4_define([lcms_required_version], [2.8])
 m4_define([libpng_required_version], [1.6.25])
 m4_define([liblzma_required_version], [5.0.0])
 m4_define([openexr_required_version], [1.6.1])
+m4_define([openjpeg_required_version], [2.1.0])
 m4_define([gtk_mac_integration_required_version], [2.0.0])
 m4_define([intltool_required_version], [0.40.1])
 m4_define([perl_required_version], [5.10.0])
@@ -1798,30 +1799,27 @@ AC_SUBST(WMF_LIBS)
 AC_SUBST(WMF_CFLAGS)
 
 
-#####################
-# Check for libjasper
-#####################
+####################
+# Check for OpenJPEG
+####################
 
-AC_ARG_WITH(libjasper,  [  --without-libjasper     build without JPEG-2000 support])
+AC_ARG_WITH(jpeg2000, [  --without-jpeg2000      build without JPEG 2000 support])
 
-have_jp2=no
-if test "x$with_libjasper" != xno && test -z "$JASPER_LIBS"; then
-  have_jp2=yes
-  AC_CHECK_LIB(jasper, jas_init,
-    FILE_JP2_LOAD='file-jp2-load$(EXEEXT)' ; JP2_LIBS=-ljasper,
-    [have_jp2="no (JasPer library not found)"
-    AC_MSG_WARN(*** JP2 plug-in will not be built (JasPer library not found) ***)])
-else
-   have_jp2="no (JasPer support disabled)"
+have_openjpeg=no
+if test "x$with_jpeg2000" != xno; then
+  have_openjpeg=yes
+  PKG_CHECK_MODULES(OPENJPEG, libopenjp2 >= openjpeg_required_version,
+    FILE_JP2_LOAD='file-jp2-load$(EXEEXT)'
+    have_openjpeg=yes,
+    have_openjpeg="no (OpenJPEG not found)")
 fi
 
-if test "x$have_jp2" = xyes; then
-  MIME_TYPES="$MIME_TYPES;image/jp2;image/jpeg2000;image/jpx"
+if test "x$have_openjpeg" = xyes; then
+  MIME_TYPES="$MIME_TYPES;image/jp2"
 fi
 
-AM_CONDITIONAL(BUILD_JP2, test "x$have_jp2" = xyes)
+AM_CONDITIONAL(HAVE_OPENJPEG, test "x$have_openjpeg" = xyes)
 AC_SUBST(FILE_JP2_LOAD)
-AC_SUBST(JP2_LIBS)
 
 
 ################
@@ -2747,7 +2745,7 @@ Optional Plug-Ins:
   Ascii Art:           $have_libaa
   Ghostscript:         $have_gs
   Help Browser:        $have_webkit
-  JPEG 2000:           $have_jp2
+  JPEG 2000:           $have_openjpeg
   MNG:                 $have_libmng
   OpenEXR:             $have_openexr
   WebP:                $have_webp
diff --git a/plug-ins/common/Makefile.am b/plug-ins/common/Makefile.am
index 8a5fe35..0b3619b 100644
--- a/plug-ins/common/Makefile.am
+++ b/plug-ins/common/Makefile.am
@@ -840,6 +840,8 @@ file_html_table_LDADD = \
        $(INTLLIBS)             \
        $(file_html_table_RC)
 
+file_jp2_load_CFLAGS = $(OPENJPEG_CFLAGS)
+
 file_jp2_load_SOURCES = \
        file-jp2-load.c
 
@@ -854,7 +856,7 @@ file_jp2_load_LDADD = \
        $(libgimpbase)          \
        $(GTK_LIBS)             \
        $(GEGL_LIBS)            \
-       $(JP2_LIBS)             \
+       $(OPENJPEG_LIBS)                \
        $(RT_LIBS)              \
        $(INTLLIBS)             \
        $(file_jp2_load_RC)
diff --git a/plug-ins/common/file-jp2-load.c b/plug-ins/common/file-jp2-load.c
index 0de1905..68af294 100644
--- a/plug-ins/common/file-jp2-load.c
+++ b/plug-ins/common/file-jp2-load.c
@@ -19,6 +19,47 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+/*
+ * Portions of this plug-in code (color conversion, etc.) were imported
+ * from the OpenJPEG project covered under the following GNU GPL
+ * compatible license:
+ *
+ * The copyright in this software is being made available under the 2-clauses
+ * BSD License, included below. This software may be subject to other third
+ * party and contributor rights, including patent rights, and no such rights
+ * are granted under this license.
+ *
+ * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium
+ * Copyright (c) 2002-2014, Professor Benoit Macq
+ * Copyright (c) 2001-2003, David Janssens
+ * Copyright (c) 2002-2003, Yannick Verschueren
+ * Copyright (c) 2003-2007, Francois-Olivier Devaux
+ * Copyright (c) 2003-2014, Antonin Descampe
+ * Copyright (c) 2005, Herve Drolon, FreeImage Team
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
 #include "config.h"
 
 #ifdef HAVE_UNISTD_H
@@ -27,6 +68,7 @@
 
 #include <errno.h>
 #include <string.h>
+#include <stdlib.h>
 
 #include <glib/gstdio.h>
 
@@ -43,7 +85,7 @@
 
 #include "libgimp/stdplugins-intl.h"
 
-#include <jasper/jasper.h>
+#include <openjpeg.h>
 
 
 #define LOAD_PROC      "file-jp2-load"
@@ -58,10 +100,6 @@ static void     run               (const gchar      *name,
                                    GimpParam       **return_vals);
 static gint32   load_image        (const gchar      *filename,
                                    GError          **error);
-static gboolean load_icc_profile  (jas_image_t      *jas_image,
-                                   gint              image_ID,
-                                   GError          **error);
-
 
 const GimpPlugInInfo PLUG_IN_INFO =
 {
@@ -103,15 +141,11 @@ query (void)
                           load_args, load_return_vals);
 
   gimp_register_magic_load_handler (LOAD_PROC,
-                                    "jp2,jpc,jpx,j2k,jpf",
+                                    "jp2",
                                     "",
                                     "4,string,jP,0,string,\xff\x4f\xff\x51\x00");
 
   gimp_register_file_handler_mime (LOAD_PROC, "image/jp2");
-#if 0
-  gimp_register_file_handler_mime (LOAD_PROC, "image/jpeg2000");
-  gimp_register_file_handler_mime (LOAD_PROC, "image/jpx");
-#endif
 }
 
 static void
@@ -201,193 +235,697 @@ run (const gchar      *name,
   values[0].data.d_status = status;
 }
 
-static gint32
-load_image (const gchar  *filename,
-            GError      **error)
+static void
+sycc_to_rgb (int  offset,
+             int  upb,
+             int  y,
+             int  cb,
+             int  cr,
+             int *out_r,
+             int *out_g,
+             int *out_b)
 {
-  gint               fd;
-  jas_stream_t      *stream;
-  gint32             image_ID = -1;
-  jas_image_t       *image;
-  gint32             layer_ID;
-  GimpImageType      image_type;
-  GimpImageBaseType  base_type;
-  gint               width;
-  gint               height;
-  gint               num_components;
-  gint               colorspace_family;
-  GeglBuffer        *buffer;
-  gint               i, j, k;
-  guchar            *pixels;
-  jas_matrix_t      *matrix;
-  gint               components[4];
+  int r, g, b;
+
+  cb -= offset;
+  cr -= offset;
+  r = y + (int) (1.402 * (float) cr);
+
+  if (r < 0)
+    r = 0;
+  else if (r > upb)
+    r = upb;
+  *out_r = r;
+
+  g = y - (int) (0.344 * (float) cb + 0.714 * (float) cr);
+  if (g < 0)
+    g = 0;
+  else if (g > upb)
+    g = upb;
+  *out_g = g;
+
+  b = y + (int) (1.772 * (float) cb);
+  if (b < 0)
+    b = 0;
+  else if (b > upb)
+    b = upb;
+  *out_b = b;
+}
 
-  jas_init ();
+static gboolean
+sycc420_to_rgb (opj_image_t *img)
+{
+  int *d0, *d1, *d2, *r, *g, *b, *nr, *ng, *nb;
+  const int *y, *cb, *cr, *ny;
+  size_t maxw, maxh, max, offx, loopmaxw, offy, loopmaxh;
+  int offset, upb;
+  size_t i;
 
-  gimp_progress_init_printf (_("Opening '%s'"),
-                             gimp_filename_to_utf8 (filename));
+  upb = (int) img->comps[0].prec;
+  offset = 1 << (upb - 1);
+  upb = (1 << upb) - 1;
 
-  fd = g_open (filename, O_RDONLY | _O_BINARY, 0);
-  if (fd == -1)
-    {
-      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
-                   _("Could not open '%s' for reading: %s"),
-                   gimp_filename_to_utf8 (filename), g_strerror (errno));
-      return -1;
-    }
+  maxw = (size_t) img->comps[0].w;
+  maxh = (size_t) img->comps[0].h;
+  max = maxw * maxh;
 
-  stream = jas_stream_fdopen (fd, "rb");
-  if (! stream)
+  y = img->comps[0].data;
+  cb = img->comps[1].data;
+  cr = img->comps[2].data;
+
+  d0 = r = (int *) malloc (sizeof (int) * max);
+  d1 = g = (int *) malloc (sizeof (int) * max);
+  d2 = b = (int *) malloc (sizeof (int) * max);
+
+  if (r == NULL || g == NULL || b == NULL)
     {
-      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
-                   _("Could not open '%s' for reading: %s"),
-                   gimp_filename_to_utf8 (filename), g_strerror (errno));
-      return -1;
+      g_warning ("malloc() failed in sycc420_to_rgb()");
+      goto out;
     }
 
-  image = jas_image_decode (stream, -1, 0);
-  if (!image)
+  /* if img->x0 is odd, then first column shall use Cb/Cr = 0 */
+  offx = img->x0 & 1U;
+  loopmaxw = maxw - offx;
+  /* if img->y0 is odd, then first line shall use Cb/Cr = 0 */
+  offy = img->y0 & 1U;
+  loopmaxh = maxh - offy;
+
+  if (offy > 0U)
     {
-      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                   _("Couldn't decode '%s'."),
-                   gimp_filename_to_utf8 (filename));
-      return -1;
+      size_t j;
+
+      for (j = 0; j < maxw; ++j)
+        {
+          sycc_to_rgb (offset, upb, *y, 0, 0, r, g, b);
+          ++y;
+          ++r;
+          ++g;
+          ++b;
+        }
     }
 
-  gimp_progress_update (80);
+  for (i = 0U; i < (loopmaxh & ~(size_t) 1U); i += 2U)
+    {
+      size_t j;
 
-  jas_stream_close (stream);
-  close (fd);
+      ny = y + maxw;
+      nr = r + maxw;
+      ng = g + maxw;
+      nb = b + maxw;
 
-  width  = jas_image_width  (image);
-  height = jas_image_height (image);
+      if (offx > 0U)
+        {
+          sycc_to_rgb (offset, upb, *y, 0, 0, r, g, b);
+          ++y;
+          ++r;
+          ++g;
+          ++b;
+
+          sycc_to_rgb (offset, upb, *ny, *cb, *cr, nr, ng, nb);
+          ++ny;
+          ++nr;
+          ++ng;
+          ++nb;
+        }
 
-  /* determine image type */
-  colorspace_family = jas_clrspc_fam (jas_image_clrspc (image));
-  switch (colorspace_family)
-    {
-    case JAS_CLRSPC_FAM_GRAY:
-      base_type = GIMP_GRAY;
-      components[0] = jas_image_getcmptbytype (image, JAS_IMAGE_CT_GRAY_Y);
-      if (components[0] == -1)
+      for (j = 0; j < (loopmaxw & ~(size_t) 1U); j += 2U)
         {
-          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                       _("The image '%s' is in grayscale but does not contain "
-                         "any gray component."),
-                       gimp_filename_to_utf8 (filename));
-          return -1;
+          sycc_to_rgb (offset, upb, *y, *cb, *cr, r, g, b);
+          ++y;
+          ++r;
+          ++g;
+          ++b;
+
+          sycc_to_rgb (offset, upb, *y, *cb, *cr, r, g, b);
+          ++y;
+          ++r;
+          ++g;
+          ++b;
+
+          sycc_to_rgb (offset, upb, *ny, *cb, *cr, nr, ng, nb);
+          ++ny;
+          ++nr;
+          ++ng;
+          ++nb;
+
+          sycc_to_rgb (offset, upb, *ny, *cb, *cr, nr, ng, nb);
+          ++ny;
+          ++nr;
+          ++ng;
+          ++nb;
+
+          ++cb;
+          ++cr;
         }
 
-      components[1] = jas_image_getcmptbytype (image, JAS_IMAGE_CT_OPACITY);
-      if (components[1] != -1)
+      if (j < loopmaxw)
         {
-          num_components = 2;
-          image_type = GIMP_GRAYA_IMAGE;
+          sycc_to_rgb (offset, upb, *y, *cb, *cr, r, g, b);
+          ++y;
+          ++r;
+          ++g;
+          ++b;
+
+          sycc_to_rgb (offset, upb, *ny, *cb, *cr, nr, ng, nb);
+          ++ny;
+          ++nr;
+          ++ng;
+          ++nb;
+
+          ++cb;
+          ++cr;
         }
-      else
+
+      y += maxw;
+      r += maxw;
+      g += maxw;
+      b += maxw;
+    }
+
+  if (i < loopmaxh)
+    {
+      size_t j;
+
+      for (j = 0U; j < (maxw & ~(size_t) 1U); j += 2U)
         {
-          num_components = 1;
-          image_type = GIMP_GRAY_IMAGE;
+          sycc_to_rgb (offset, upb, *y, *cb, *cr, r, g, b);
+          ++y;
+          ++r;
+          ++g;
+          ++b;
+
+          sycc_to_rgb (offset, upb, *y, *cb, *cr, r, g, b);
+          ++y;
+          ++r;
+          ++g;
+          ++b;
+
+          ++cb;
+          ++cr;
         }
-      break;
-
-    case JAS_CLRSPC_FAM_RGB:
-      base_type = GIMP_RGB;
-      components[0] = jas_image_getcmptbytype (image, JAS_IMAGE_CT_RGB_R);
-      components[1] = jas_image_getcmptbytype (image, JAS_IMAGE_CT_RGB_G);
-      components[2] = jas_image_getcmptbytype (image, JAS_IMAGE_CT_RGB_B);
-      if (components[0] == -1 || components[1] == -1 || components[2] == -1)
+
+      if (j < maxw)
         {
-          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                       _("The image '%s' is in RGB, but is missing some of the "
-                         "components."),
-                       gimp_filename_to_utf8 (filename));
-          return -1;
+          sycc_to_rgb (offset, upb, *y, *cb, *cr, r, g, b);
         }
-      components[3] = jas_image_getcmptbytype (image, JAS_IMAGE_CT_OPACITY);
+    }
+
+  free (img->comps[0].data);
+  img->comps[0].data = d0;
+  free (img->comps[1].data);
+  img->comps[1].data = d1;
+  free (img->comps[2].data);
+  img->comps[2].data = d2;
+
+  img->comps[1].w = img->comps[2].w = img->comps[0].w;
+  img->comps[1].h = img->comps[2].h = img->comps[0].h;
+  img->comps[1].dx = img->comps[2].dx = img->comps[0].dx;
+  img->comps[1].dy = img->comps[2].dy = img->comps[0].dy;
+  img->color_space = OPJ_CLRSPC_SRGB;
+
+  return TRUE;
+
+ out:
+  free (r);
+  free (g);
+  free (b);
+  return FALSE;
+}
+
+static gboolean
+sycc422_to_rgb (opj_image_t *img)
+{
+  int *d0, *d1, *d2, *r, *g, *b;
+  const int *y, *cb, *cr;
+  size_t maxw, maxh, max, offx, loopmaxw;
+  int offset, upb;
+  size_t i;
 
-      /* ImageMagick seems to write out the 'matte' component type
-        (number 3) */
-      if (components[3] == -1)
-        components[3] = jas_image_getcmptbytype (image, 3);
+  upb = (int) img->comps[0].prec;
+  offset = 1 <<(upb - 1);
+  upb = (1 << upb) - 1;
 
-      if (components[3] != -1)
+  maxw = (size_t) img->comps[0].w;
+  maxh = (size_t) img->comps[0].h;
+  max = maxw * maxh;
+
+  y = img->comps[0].data;
+  cb = img->comps[1].data;
+  cr = img->comps[2].data;
+
+  d0 = r = (int *) malloc (sizeof (int) * max);
+  d1 = g = (int *) malloc (sizeof (int) * max);
+  d2 = b = (int *) malloc (sizeof (int) * max);
+
+  if (r == NULL || g == NULL || b == NULL)
+    {
+      g_warning ("malloc() failed in sycc422_to_rgb()");
+      goto out;
+    }
+
+  /* if img->x0 is odd, then first column shall use Cb/Cr = 0 */
+  offx = img->x0 & 1U;
+  loopmaxw = maxw - offx;
+
+  for (i = 0U; i < maxh; ++i)
+    {
+      size_t j;
+
+      if (offx > 0U)
         {
-          num_components = 4;
-          image_type = GIMP_RGBA_IMAGE;
+          sycc_to_rgb (offset, upb, *y, 0, 0, r, g, b);
+          ++y;
+          ++r;
+          ++g;
+          ++b;
         }
-      else
+
+      for (j = 0U; j < (loopmaxw & ~(size_t) 1U); j += 2U)
         {
-          num_components = 3;
-          image_type = GIMP_RGB_IMAGE;
+          sycc_to_rgb (offset, upb, *y, *cb, *cr, r, g, b);
+          ++y;
+          ++r;
+          ++g;
+          ++b;
+
+          sycc_to_rgb (offset, upb, *y, *cb, *cr, r, g, b);
+          ++y;
+          ++r;
+          ++g;
+          ++b;
+          ++cb;
+          ++cr;
         }
-      break;
 
-    case JAS_CLRSPC_FAM_XYZ:
+      if (j < loopmaxw)
+        {
+          sycc_to_rgb (offset, upb, *y, *cb, *cr, r, g, b);
+          ++y;
+          ++r;
+          ++g;
+          ++b;
+          ++cb;
+          ++cr;
+        }
+    }
+
+  free (img->comps[0].data);
+  img->comps[0].data = d0;
+  free (img->comps[1].data);
+  img->comps[1].data = d1;
+  free (img->comps[2].data);
+  img->comps[2].data = d2;
+
+  img->comps[1].w = img->comps[2].w = img->comps[0].w;
+  img->comps[1].h = img->comps[2].h = img->comps[0].h;
+  img->comps[1].dx = img->comps[2].dx = img->comps[0].dx;
+  img->comps[1].dy = img->comps[2].dy = img->comps[0].dy;
+  img->color_space = OPJ_CLRSPC_SRGB;
+
+  return (TRUE);
+
+ out:
+  free (r);
+  free (g);
+  free (b);
+  return (FALSE);
+}
+
+static gboolean
+sycc444_to_rgb (opj_image_t *img)
+{
+  int *d0, *d1, *d2, *r, *g, *b;
+  const int *y, *cb, *cr;
+  size_t maxw, maxh, max, i;
+  int offset, upb;
+
+  upb = (int) img->comps[0].prec;
+  offset = 1 << (upb - 1);
+  upb = (1 << upb) - 1;
+
+  maxw = (size_t) img->comps[0].w;
+  maxh = (size_t) img->comps[0].h;
+  max = maxw * maxh;
+
+  y = img->comps[0].data;
+  cb = img->comps[1].data;
+  cr = img->comps[2].data;
+
+  d0 = r = (int *) malloc(sizeof (int) * max);
+  d1 = g = (int *) malloc(sizeof (int) * max);
+  d2 = b = (int *) malloc(sizeof (int) * max);
+
+  if (r == NULL || g == NULL || b == NULL)
+    {
+      g_warning ("malloc() failed in sycc444_to_rgb()");
+      goto out;
+    }
+
+  for (i = 0U; i < max; ++i)
+    {
+      sycc_to_rgb (offset, upb, *y, *cb, *cr, r, g, b);
+      ++y;
+      ++cb;
+      ++cr;
+      ++r;
+      ++g;
+      ++b;
+    }
+
+  free (img->comps[0].data);
+  img->comps[0].data = d0;
+  free (img->comps[1].data);
+  img->comps[1].data = d1;
+  free (img->comps[2].data);
+  img->comps[2].data = d2;
+
+  img->color_space = OPJ_CLRSPC_SRGB;
+  return TRUE;
+
+ out:
+  free (r);
+  free (g);
+  free (b);
+  return FALSE;
+}
+
+static gboolean
+color_sycc_to_rgb (opj_image_t *img)
+{
+  if (img->numcomps < 3)
+    {
+      img->color_space = OPJ_CLRSPC_GRAY;
+      return TRUE;
+    }
+  else if ((img->comps[0].dx == 1) &&
+           (img->comps[1].dx == 2) &&
+           (img->comps[2].dx == 2) &&
+           (img->comps[0].dy == 1) &&
+           (img->comps[1].dy == 2) &&
+           (img->comps[2].dy == 2))
+    {
+      /* horizontal and vertical sub-sample */
+      return sycc420_to_rgb (img);
+    }
+  else if ((img->comps[0].dx == 1) &&
+           (img->comps[1].dx == 2) &&
+           (img->comps[2].dx == 2) &&
+           (img->comps[0].dy == 1) &&
+           (img->comps[1].dy == 1) &&
+           (img->comps[2].dy == 1))
+    {
+      /* horizontal sub-sample only */
+      return sycc422_to_rgb (img);
+    }
+  else if ((img->comps[0].dx == 1) &&
+           (img->comps[1].dx == 1) &&
+           (img->comps[2].dx == 1) &&
+           (img->comps[0].dy == 1) &&
+           (img->comps[1].dy == 1) &&
+           (img->comps[2].dy == 1))
+    {
+      /* no sub-sample */
+      return sycc444_to_rgb (img);
+    }
+  else
+    {
+      g_warning ("Cannot convert in color_sycc_to_rgb()");
+      return FALSE;
+    }
+}
+
+static gboolean
+color_cmyk_to_rgb (opj_image_t *image)
+{
+  float C, M, Y, K;
+  float sC, sM, sY, sK;
+  unsigned int w, h, max, i;
+
+  w = image->comps[0].w;
+  h = image->comps[0].h;
+
+  if ((image->numcomps < 4) ||
+      (image->comps[0].dx != image->comps[1].dx) ||
+      (image->comps[0].dx != image->comps[2].dx) ||
+      (image->comps[0].dx != image->comps[3].dx) ||
+      (image->comps[0].dy != image->comps[1].dy) ||
+      (image->comps[0].dy != image->comps[2].dy) ||
+      (image->comps[0].dy != image->comps[3].dy))
+    {
+      g_warning ("Cannot convert in color_cmyk_to_rgb()");
+      return FALSE;
+    }
+
+  max = w * h;
+
+  sC = 1.0f / (float) ((1 << image->comps[0].prec) - 1);
+  sM = 1.0f / (float) ((1 << image->comps[1].prec) - 1);
+  sY = 1.0f / (float) ((1 << image->comps[2].prec) - 1);
+  sK = 1.0f / (float) ((1 << image->comps[3].prec) - 1);
+
+  for (i = 0; i < max; ++i)
+    {
+      /* CMYK values from 0 to 1 */
+      C = (float) (image->comps[0].data[i]) * sC;
+      M = (float) (image->comps[1].data[i]) * sM;
+      Y = (float) (image->comps[2].data[i]) * sY;
+      K = (float) (image->comps[3].data[i]) * sK;
+
+      /* Invert all CMYK values */
+      C = 1.0f - C;
+      M = 1.0f - M;
+      Y = 1.0f - Y;
+      K = 1.0f - K;
+
+      /* CMYK -> RGB : RGB results from 0 to 255 */
+      image->comps[0].data[i] = (int) (255.0f * C * K); /* R */
+      image->comps[1].data[i] = (int) (255.0f * M * K); /* G */
+      image->comps[2].data[i] = (int) (255.0f * Y * K); /* B */
+    }
+
+  free (image->comps[3].data);
+  image->comps[3].data = NULL;
+  image->comps[0].prec = 8;
+  image->comps[1].prec = 8;
+  image->comps[2].prec = 8;
+  image->numcomps -= 1;
+  image->color_space = OPJ_CLRSPC_SRGB;
+
+  for (i = 3; i < image->numcomps; ++i)
+    {
+      memcpy(&(image->comps[i]), &(image->comps[i + 1]),
+             sizeof (image->comps[i]));
+    }
+
+  return TRUE;
+}
+
+/*
+ * This code has been adopted from sjpx_openjpeg.c of ghostscript
+ */
+static gboolean
+color_esycc_to_rgb (opj_image_t *image)
+{
+  int y, cb, cr, sign1, sign2, val;
+  unsigned int w, h, max, i;
+  int flip_value;
+  int max_value;
+
+  flip_value = (1 << (image->comps[0].prec - 1));
+  max_value = (1 << image->comps[0].prec) - 1;
+
+  if ((image->numcomps < 3) ||
+      (image->comps[0].dx != image->comps[1].dx) ||
+      (image->comps[0].dx != image->comps[2].dx) ||
+      (image->comps[0].dy != image->comps[1].dy) ||
+      (image->comps[0].dy != image->comps[2].dy))
+    {
+      g_warning ("Cannot convert in color_esycc_to_rgb()");
+      return FALSE;
+    }
+
+  w = image->comps[0].w;
+  h = image->comps[0].h;
+
+  sign1 = (int)image->comps[1].sgnd;
+  sign2 = (int)image->comps[2].sgnd;
+
+  max = w * h;
+
+  for (i = 0; i < max; ++i)
+    {
+
+      y = image->comps[0].data[i];
+      cb = image->comps[1].data[i];
+      cr = image->comps[2].data[i];
+
+      if (! sign1)
+        cb -= flip_value;
+
+      if (! sign2)
+        cr -= flip_value;
+
+      val = (int) ((float) y - (float) 0.0000368 *
+                   (float) cb + (float) 1.40199 * (float) cr + (float) 0.5);
+
+      if (val > max_value)
+        val = max_value;
+      else if (val < 0)
+        val = 0;
+      image->comps[0].data[i] = val;
+
+      val = (int) ((float) 1.0003 * (float) y - (float) 0.344125 *
+                   (float) cb - (float) 0.7141128 * (float) cr + (float) 0.5);
+
+      if (val > max_value)
+        val = max_value;
+      else if(val < 0)
+        val = 0;
+      image->comps[1].data[i] = val;
+
+      val = (int) ((float) 0.999823 * (float) y + (float) 1.77204 *
+                   (float) cb - (float) 0.000008 * (float) cr + (float) 0.5);
+
+      if (val > max_value)
+        val = max_value;
+      else if (val < 0)
+        val = 0;
+      image->comps[2].data[i] = val;
+    }
+
+  image->color_space = OPJ_CLRSPC_SRGB;
+  return TRUE;
+}
+
+static gint32
+load_image (const gchar  *filename,
+            GError      **error)
+{
+  opj_stream_t      *stream;
+  opj_codec_t       *codec;
+  opj_dparameters_t  parameters;
+  opj_image_t       *image;
+  gint32             image_ID;
+  gint32             layer_ID;
+  GimpImageType      image_type;
+  GimpImageBaseType  base_type;
+  gint               width;
+  gint               height;
+  gint               num_components;
+  gint               colorspace_family;
+  GeglBuffer        *buffer;
+  gint               i, j, k;
+  guchar            *pixels;
+  gint               components[4];
+
+  stream = NULL;
+  codec = NULL;
+  image = NULL;
+  image_ID = -1;
+
+  gimp_progress_init_printf (_("Opening '%s'"),
+                             gimp_filename_to_utf8 (filename));
+
+  stream = opj_stream_create_default_file_stream (filename, OPJ_TRUE);
+  if (! stream)
+    {
       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                   _("The image '%s' is in the CIEXYZ color space, but there is "
-                     "no code in place to convert it to RGB."),
+                   _("Could not open '%s' for reading"),
                    gimp_filename_to_utf8 (filename));
-      return -1;
+      goto out;
+    }
+
+  codec = opj_create_decompress (OPJ_CODEC_JP2);
 
-    case JAS_CLRSPC_FAM_LAB:
+  opj_set_default_decoder_parameters (&parameters);
+  if (opj_setup_decoder (codec, &parameters) != OPJ_TRUE)
+    {
       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                   _("The image '%s' is in the CIELAB color space, but there is "
-                     "no code in place to convert it to RGB."),
+                   _("Couldn't set parameters on decoder for '%s'."),
                    gimp_filename_to_utf8 (filename));
-      return -1;
+      goto out;
+    }
 
-    case JAS_CLRSPC_FAM_YCBCR:
+  if (opj_read_header (stream, codec, &image) != OPJ_TRUE)
+    {
       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                   _("The image '%s' is in the YCbCr color space, but there is "
-                     "no code in place to convert it to RGB."),
+                   _("Couldn't read JP2 header from '%s'."),
                    gimp_filename_to_utf8 (filename));
-      return -1;
+      goto out;
+    }
 
-    case JAS_CLRSPC_FAM_UNKNOWN:
-    default:
+  if (opj_decode (codec, stream, image) != OPJ_TRUE)
+    {
       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                   _("The image '%s' is in an unknown color space."),
+                   _("Couldn't decode JP2 image in '%s'."),
                    gimp_filename_to_utf8 (filename));
-      return -1;
+      goto out;
+    }
+
+  if (opj_end_decompress (codec, stream) != OPJ_TRUE)
+    {
+      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                   _("Couldn't decode JP2 image in '%s'."),
+                   gimp_filename_to_utf8 (filename));
+      goto out;
+    }
+
+  if ((image->color_space != OPJ_CLRSPC_SYCC) &&
+      (image->numcomps == 3) &&
+      (image->comps[0].dx == image->comps[0].dy) &&
+      (image->comps[1].dx != 1))
+    {
+      image->color_space = OPJ_CLRSPC_SYCC;
+    }
+  else if (image->numcomps <= 2)
+    {
+      image->color_space = OPJ_CLRSPC_GRAY;
     }
 
-  /* check all components if their dimensions match image dimensions */
-  for (i = 0; i < num_components; i++)
+  if (image->color_space == OPJ_CLRSPC_SYCC)
     {
-      if (jas_image_cmpttlx (image, components[i]) != jas_image_tlx (image) ||
-          jas_image_cmpttly (image, components[i]) != jas_image_tly (image) ||
-          jas_image_cmptbrx (image, components[i]) != jas_image_brx (image) ||
-          jas_image_cmptbry (image, components[i]) != jas_image_bry (image))
+      if (! color_sycc_to_rgb (image))
         {
           g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                       _("Image component %d of image '%s' does not have the "
-                         "same size as the image. This is currently not "
-                         "supported."),
-                       i, gimp_filename_to_utf8 (filename));
-          return -1;
+                       _("Couldn't decode JP2 image in '%s'."),
+                       gimp_filename_to_utf8 (filename));
+          goto out;
         }
-
-      if (jas_image_cmpthstep (image, components[i]) != 1 ||
-          jas_image_cmptvstep (image, components[i]) != 1)
+    }
+  else if ((image->color_space == OPJ_CLRSPC_CMYK))
+    {
+      if (! color_cmyk_to_rgb (image))
         {
           g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                       _("Image component %d of image '%s' does not have both "
-                         "a hstep and vstep."),
-                       i, gimp_filename_to_utf8 (filename));
-          return -1;
+                       _("Couldn't decode JP2 image in '%s'."),
+                       gimp_filename_to_utf8 (filename));
+          goto out;
         }
-
-      if (jas_image_cmptsgnd (image, components[i]))
+    }
+  else if (image->color_space == OPJ_CLRSPC_EYCC)
+    {
+      if (! color_esycc_to_rgb (image))
         {
           g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                       _("Image component %d of image '%s' is signed. "
-                         "This is currently not supported."),
-                       i, gimp_filename_to_utf8 (filename));
-          return -1;
+                       _("Couldn't decode JP2 image in '%s'."),
+                       gimp_filename_to_utf8 (filename));
+          goto out;
         }
     }
 
+  num_components = image->numcomps;
+
+  /* FIXME */
+  base_type = GIMP_GRAY;
+  base_type = GIMP_RGB;
+  image_type = GIMP_GRAYA_IMAGE;
+  image_type = GIMP_GRAY_IMAGE;
+  image_type = GIMP_RGBA_IMAGE;
+  image_type = GIMP_RGB_IMAGE;
+
+  width = image->comps[0].w;
+  height = image->comps[0].h;
+
   image_ID = gimp_image_new (width, height, base_type);
   gimp_image_set_filename (image_ID, filename);
 
@@ -402,6 +940,7 @@ load_image (const gchar  *filename,
   buffer = gimp_drawable_get_buffer (layer_ID);
 
   pixels = malloc (width * num_components);
+#if 0
   matrix = jas_matrix_create (1, width);
 
   for (i = 0; i < height; i++)
@@ -436,68 +975,48 @@ load_image (const gchar  *filename,
       gegl_buffer_set (buffer, GEGL_RECTANGLE (0, i, width, 1), 0,
                        NULL, pixels, GEGL_AUTO_ROWSTRIDE);
     }
+#endif
 
-  load_icc_profile (image, image_ID, NULL);
-
-  jas_matrix_destroy (matrix);
   free (pixels);
-  jas_image_destroy (image);
 
   g_object_unref (buffer);
 
-  jas_cleanup ();
-
-  gimp_progress_update (1.0);
-
-  return image_ID;
-}
-
-static gboolean
-load_icc_profile (jas_image_t  *jas_image,
-                  gint          image_ID,
-                  GError      **error)
-{
-  jas_cmprof_t     *cm_prof;
-  jas_iccprof_t    *jas_icc;
-  jas_stream_t     *stream;
-  guint32           profile_size;
-  guchar           *jas_iccile;
-  GimpColorProfile *profile;
-
-  cm_prof = jas_image_cmprof (jas_image);
-  if (!cm_prof)
-    return FALSE;
-
-  jas_icc = jas_iccprof_createfromcmprof (cm_prof);
-  if (!jas_icc)
-    return FALSE;
-
-  stream = jas_stream_memopen (NULL, -1);
-  if (!stream)
-    return FALSE;
-
-  jas_iccprof_save (jas_icc, stream);
-
-  jas_stream_rewind (stream);
-  profile_size = jas_stream_length (stream);
+  if (image->icc_profile_buf)
+    {
+      if (image->icc_profile_len)
+        {
+          GimpColorProfile *profile;
 
-  jas_iccile = g_malloc (profile_size);
-  jas_stream_read (stream, jas_iccile, profile_size);
+          profile = gimp_color_profile_new_from_icc_profile
+            (image->icc_profile_buf, image->icc_profile_len, error);
+          if (! profile)
+            goto out;
 
-  jas_stream_close (stream);
-  jas_iccprof_destroy (jas_icc);
+          gimp_image_set_color_profile (image_ID, profile);
+          g_object_unref (profile);
+        }
+      else
+        {
+          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                       _("Couldn't decode CIELAB JP2 image in '%s'."),
+                       gimp_filename_to_utf8 (filename));
+          goto out;
+        }
 
-  profile = gimp_color_profile_new_from_icc_profile (jas_iccile, profile_size,
-                                                     error);
-  g_free (jas_iccile);
+      free (image->icc_profile_buf);
+      image->icc_profile_buf = NULL;
+      image->icc_profile_len = 0;
+    }
 
-  if (profile)
-    {
-      gimp_image_set_color_profile (image_ID, profile);
-      g_object_unref (profile);
+  gimp_progress_update (1.0);
 
-      return TRUE;
-    }
+ out:
+  if (image)
+    opj_image_destroy (image);
+  if (codec)
+    opj_destroy_codec (codec);
+  if (stream)
+    opj_stream_destroy (stream);
 
-  return FALSE;
+  return image_ID;
 }
diff --git a/plug-ins/common/plugin-defs.pl b/plug-ins/common/plugin-defs.pl
index f23f028..2235cea 100644
--- a/plug-ins/common/plugin-defs.pl
+++ b/plug-ins/common/plugin-defs.pl
@@ -38,7 +38,7 @@
     'file-glob' => {},
     'file-header' => { ui => 1, gegl => 1 },
     'file-html-table' => { ui => 1, gegl => 1 },
-    'file-jp2-load' => { ui => 1, optional => 1, gegl => 1, libs => 'JP2_LIBS' },
+    'file-jp2-load' => { ui => 1, optional => 1, gegl => 1, libs => 'OPENJPEG_LIBS', cflags => 
'OPENJPEG_CFLAGS' },
     'file-mng' => { ui => 1, gegl => 1, optional => 1, libs => 'MNG_LIBS', cflags => 'MNG_CFLAGS' },
     'file-pat' => { ui => 1, gegl => 1 },
     'file-pcx' => { ui => 1, gegl => 1 },


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]