[gimp] file-jp2-load: Switch from Jasper to OpenJPEG library
- From: Jehan Pagès <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] file-jp2-load: Switch from Jasper to OpenJPEG library
- Date: Sun, 4 Mar 2018 17:29:31 +0000 (UTC)
commit 58a0a651602d5b55d8c7d3408fb315f4e47d9b8f
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 | 910 ++++++++++++++++++++++++++++++---------
plug-ins/common/plugin-defs.pl | 2 +-
4 files changed, 734 insertions(+), 216 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 14ab68b..03ddfb9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -72,6 +72,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])
@@ -1783,30 +1784,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)
################
@@ -2732,7 +2730,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 1bc684b..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,194 +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 (¶meters);
+ if (opj_setup_decoder (codec, ¶meters) != 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);
@@ -403,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++)
@@ -437,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]