From 58a0a651602d5b55d8c7d3408fb315f4e47d9b8f Mon Sep 17 00:00:00 2001 From: Mukund Sivaraman Date: Mon, 20 Feb 2017 01:36:26 +0530 Subject: [PATCH] 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 | 942 +++++++++++++++++++++++++------- plug-ins/common/plugin-defs.pl | 2 +- 4 files changed, 750 insertions(+), 232 deletions(-) diff --git a/configure.ac b/configure.ac index 14ab68bce7..03ddfb94d9 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 8a5fe35d29..0b3619bc1b 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 1bc684b412..68af294c64 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 . */ +/* + * 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 #include +#include #include @@ -43,7 +85,7 @@ #include "libgimp/stdplugins-intl.h" -#include +#include #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,14 +235,577 @@ run (const gchar *name, values[0].data.d_status = status; } +static void +sycc_to_rgb (int offset, + int upb, + int y, + int cb, + int cr, + int *out_r, + int *out_g, + int *out_b) +{ + 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; +} + +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; + + 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 sycc420_to_rgb()"); + goto out; + } + + /* 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) + { + size_t j; + + for (j = 0; j < maxw; ++j) + { + sycc_to_rgb (offset, upb, *y, 0, 0, r, g, b); + ++y; + ++r; + ++g; + ++b; + } + } + + for (i = 0U; i < (loopmaxh & ~(size_t) 1U); i += 2U) + { + size_t j; + + ny = y + maxw; + nr = r + maxw; + ng = g + maxw; + nb = b + maxw; + + 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; + } + + for (j = 0; j < (loopmaxw & ~(size_t) 1U); j += 2U) + { + 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; + } + + if (j < loopmaxw) + { + 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; + } + + y += maxw; + r += maxw; + g += maxw; + b += maxw; + } + + if (i < loopmaxh) + { + size_t j; + + for (j = 0U; j < (maxw & ~(size_t) 1U); j += 2U) + { + 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; + } + + if (j < maxw) + { + sycc_to_rgb (offset, upb, *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->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; + + 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 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) + { + sycc_to_rgb (offset, upb, *y, 0, 0, r, g, b); + ++y; + ++r; + ++g; + ++b; + } + + for (j = 0U; j < (loopmaxw & ~(size_t) 1U); j += 2U) + { + 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; + } + + 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) { - gint fd; - jas_stream_t *stream; - gint32 image_ID = -1; - jas_image_t *image; + 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; @@ -219,175 +816,115 @@ load_image (const gchar *filename, GeglBuffer *buffer; gint i, j, k; guchar *pixels; - jas_matrix_t *matrix; gint components[4]; - jas_init (); + stream = NULL; + codec = NULL; + image = NULL; + image_ID = -1; gimp_progress_init_printf (_("Opening '%s'"), gimp_filename_to_utf8 (filename)); - 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; - } - - stream = jas_stream_fdopen (fd, "rb"); + stream = opj_stream_create_default_file_stream (filename, OPJ_TRUE); if (! stream) { - 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_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("Could not open '%s' for reading"), + gimp_filename_to_utf8 (filename)); + goto out; } - image = jas_image_decode (stream, -1, 0); - if (!image) + codec = opj_create_decompress (OPJ_CODEC_JP2); + + 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, - _("Couldn't decode '%s'."), + _("Couldn't set parameters on decoder for '%s'."), gimp_filename_to_utf8 (filename)); - return -1; + goto out; } - gimp_progress_update (80); - - jas_stream_close (stream); - close (fd); - - width = jas_image_width (image); - height = jas_image_height (image); - - /* determine image type */ - colorspace_family = jas_clrspc_fam (jas_image_clrspc (image)); - switch (colorspace_family) + if (opj_read_header (stream, codec, &image) != OPJ_TRUE) { - case JAS_CLRSPC_FAM_GRAY: - base_type = GIMP_GRAY; - components[0] = jas_image_getcmptbytype (image, JAS_IMAGE_CT_GRAY_Y); - if (components[0] == -1) + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + _("Couldn't read JP2 header from '%s'."), + gimp_filename_to_utf8 (filename)); + goto out; + } + + if (opj_decode (codec, stream, image) != 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 (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; + } + + if (image->color_space == OPJ_CLRSPC_SYCC) + { + if (! color_sycc_to_rgb (image)) { g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - _("The image '%s' is in grayscale but does not contain " - "any gray component."), + _("Couldn't decode JP2 image in '%s'."), gimp_filename_to_utf8 (filename)); - return -1; + goto out; } - - components[1] = jas_image_getcmptbytype (image, JAS_IMAGE_CT_OPACITY); - if (components[1] != -1) - { - num_components = 2; - image_type = GIMP_GRAYA_IMAGE; - } - else - { - num_components = 1; - image_type = GIMP_GRAY_IMAGE; - } - 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) - { - 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; - } - components[3] = jas_image_getcmptbytype (image, JAS_IMAGE_CT_OPACITY); - - /* ImageMagick seems to write out the 'matte' component type - * (number 3) - */ - if (components[3] == -1) - components[3] = jas_image_getcmptbytype (image, 3); - - if (components[3] != -1) - { - num_components = 4; - image_type = GIMP_RGBA_IMAGE; - } - else - { - num_components = 3; - image_type = GIMP_RGB_IMAGE; - } - break; - - case JAS_CLRSPC_FAM_XYZ: - 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."), - gimp_filename_to_utf8 (filename)); - return -1; - - case JAS_CLRSPC_FAM_LAB: - 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."), - gimp_filename_to_utf8 (filename)); - return -1; - - case JAS_CLRSPC_FAM_YCBCR: - 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."), - gimp_filename_to_utf8 (filename)); - return -1; - - case JAS_CLRSPC_FAM_UNKNOWN: - default: - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, - _("The image '%s' is in an unknown color space."), - gimp_filename_to_utf8 (filename)); - return -1; } - - /* check all components if their dimensions match image dimensions */ - for (i = 0; i < num_components; i++) + else if ((image->color_space == OPJ_CLRSPC_CMYK)) { - 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_cmyk_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; - } - - if (jas_image_cmpthstep (image, components[i]) != 1 || - jas_image_cmptvstep (image, components[i]) != 1) - { - 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; - } - - if (jas_image_cmptsgnd (image, components[i])) - { - 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; } } + 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, + _("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 (); + if (image->icc_profile_buf) + { + if (image->icc_profile_len) + { + GimpColorProfile *profile; + + profile = gimp_color_profile_new_from_icc_profile + (image->icc_profile_buf, image->icc_profile_len, error); + if (! profile) + goto out; + + 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; + } + + free (image->icc_profile_buf); + image->icc_profile_buf = NULL; + image->icc_profile_len = 0; + } gimp_progress_update (1.0); + out: + if (image) + opj_image_destroy (image); + if (codec) + opj_destroy_codec (codec); + if (stream) + opj_stream_destroy (stream); + 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); - - jas_iccile = g_malloc (profile_size); - jas_stream_read (stream, jas_iccile, profile_size); - - jas_stream_close (stream); - jas_iccprof_destroy (jas_icc); - - profile = gimp_color_profile_new_from_icc_profile (jas_iccile, profile_size, - error); - g_free (jas_iccile); - - if (profile) - { - gimp_image_set_color_profile (image_ID, profile); - g_object_unref (profile); - - return TRUE; - } - - return FALSE; -} diff --git a/plug-ins/common/plugin-defs.pl b/plug-ins/common/plugin-defs.pl index f23f028f2e..2235cea373 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 },