Blame operations/external/jp2-load.c

Packit bc1512
/* This file is an image processing operation for GEGL
Packit bc1512
 *
Packit bc1512
 * GEGL is free software; you can redistribute it and/or
Packit bc1512
 * modify it under the terms of the GNU Lesser General Public
Packit bc1512
 * License as published by the Free Software Foundation; either
Packit bc1512
 * version 3 of the License, or (at your option) any later version.
Packit bc1512
 *
Packit bc1512
 * GEGL is distributed in the hope that it will be useful,
Packit bc1512
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit bc1512
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit bc1512
 * Lesser General Public License for more details.
Packit bc1512
 *
Packit bc1512
 * You should have received a copy of the GNU Lesser General Public
Packit bc1512
 * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
Packit bc1512
 *
Packit bc1512
 * Copyright (c) 2010, 2011 Mukund Sivaraman <muks@banu.com>
Packit bc1512
 */
Packit bc1512
Packit bc1512
#include "config.h"
Packit bc1512
#include <glib/gi18n-lib.h>
Packit bc1512
Packit bc1512
Packit bc1512
#ifdef GEGL_CHANT_PROPERTIES
Packit bc1512
Packit bc1512
gegl_chant_file_path (path, _("File"), "", _("Path of file to load"))
Packit bc1512
Packit bc1512
#else
Packit bc1512
Packit bc1512
#define GEGL_CHANT_TYPE_SOURCE
Packit bc1512
#define GEGL_CHANT_C_FILE       "jp2-load.c"
Packit bc1512
Packit bc1512
#include "gegl-chant.h"
Packit bc1512
#include <stdio.h>
Packit bc1512
#include <jasper/jasper.h>
Packit bc1512
Packit bc1512
static gboolean
Packit bc1512
query_jp2 (const gchar   *path,
Packit bc1512
           gint          *width,
Packit bc1512
           gint          *height,
Packit bc1512
           gint          *depth,
Packit bc1512
           jas_image_t  **jas_image)
Packit bc1512
{
Packit bc1512
  gboolean ret;
Packit bc1512
  jas_stream_t *in;
Packit bc1512
  int image_fmt;
Packit bc1512
  jas_image_t *image;
Packit bc1512
  jas_cmprof_t *output_profile;
Packit bc1512
  jas_image_t *cimage;
Packit bc1512
  int numcmpts;
Packit bc1512
  int i;
Packit bc1512
  gboolean b;
Packit bc1512
Packit bc1512
  in = NULL;
Packit bc1512
  cimage = image = NULL;
Packit bc1512
  output_profile = NULL;
Packit bc1512
  ret = FALSE;
Packit bc1512
Packit bc1512
  do
Packit bc1512
    {
Packit bc1512
      in = jas_stream_fopen (path, "rb");
Packit bc1512
      if (!in)
Packit bc1512
        {
Packit bc1512
          g_warning ("Unable to open image file '%s'", path);
Packit bc1512
          break;
Packit bc1512
        }
Packit bc1512
Packit bc1512
      image_fmt = jas_image_getfmt (in);
Packit bc1512
      if (image_fmt < 0)
Packit bc1512
        {
Packit bc1512
          g_warning (_("Unknown JPEG 2000 image format in '%s'"), path);
Packit bc1512
          break;
Packit bc1512
        }
Packit bc1512
Packit bc1512
      image = jas_image_decode (in, image_fmt, NULL);
Packit bc1512
      if (!image)
Packit bc1512
        {
Packit bc1512
          g_warning (_("Unable to open JPEG 2000 image in '%s'"), path);
Packit bc1512
          break;
Packit bc1512
        }
Packit bc1512
Packit bc1512
      output_profile = jas_cmprof_createfromclrspc (JAS_CLRSPC_SRGB);
Packit bc1512
      if (!output_profile)
Packit bc1512
        {
Packit bc1512
          g_warning (_("Unable to create output color profile for '%s'"), path);
Packit bc1512
          break;
Packit bc1512
        }
Packit bc1512
Packit bc1512
      cimage = jas_image_chclrspc (image, output_profile,
Packit bc1512
                                   JAS_CMXFORM_INTENT_PER);
Packit bc1512
      if (!cimage)
Packit bc1512
        {
Packit bc1512
          g_warning (_("Unable to convert image to sRGB color space "
Packit bc1512
                       "when processing '%s'"), path);
Packit bc1512
          break;
Packit bc1512
        }
Packit bc1512
Packit bc1512
      numcmpts = jas_image_numcmpts (cimage);
Packit bc1512
      if (numcmpts != 3)
Packit bc1512
        {
Packit bc1512
          g_warning (_("Unsupported non-RGB JPEG 2000 file with "
Packit bc1512
                       "%d components in '%s'"), numcmpts, path);
Packit bc1512
          break;
Packit bc1512
        }
Packit bc1512
Packit bc1512
      *width = jas_image_cmptwidth (cimage, 0);
Packit bc1512
      *height = jas_image_cmptheight (cimage, 0);
Packit bc1512
      *depth = jas_image_cmptprec (cimage, 0);
Packit bc1512
Packit bc1512
      if ((*depth != 8) && (*depth != 16))
Packit bc1512
        {
Packit bc1512
          g_warning (_("Unsupported JPEG 2000 file with depth %d in '%s'"),
Packit bc1512
                     *depth, path);
Packit bc1512
          break;
Packit bc1512
        }
Packit bc1512
Packit bc1512
      b = FALSE;
Packit bc1512
Packit bc1512
      for (i = 1; i < 3; i++)
Packit bc1512
        {
Packit bc1512
          if ((jas_image_cmptprec (cimage, i) != *depth) ||
Packit bc1512
              (jas_image_cmptwidth (cimage, i) != *width) ||
Packit bc1512
              (jas_image_cmptheight (cimage, i) != *height))
Packit bc1512
            {
Packit bc1512
              g_warning (_("Components of input image '%s' don't match"),
Packit bc1512
                         path);
Packit bc1512
              b = TRUE;
Packit bc1512
              break;
Packit bc1512
            }
Packit bc1512
        }
Packit bc1512
Packit bc1512
      if (b)
Packit bc1512
        break;
Packit bc1512
Packit bc1512
      ret = TRUE;
Packit bc1512
    }
Packit bc1512
  while (FALSE); /* structured goto */
Packit bc1512
Packit bc1512
  if (jas_image)
Packit bc1512
    *jas_image = cimage;
Packit bc1512
  else if (cimage)
Packit bc1512
    jas_image_destroy (cimage);
Packit bc1512
Packit bc1512
  if (image)
Packit bc1512
    jas_image_destroy (image);
Packit bc1512
Packit bc1512
  if (output_profile)
Packit bc1512
    jas_cmprof_destroy (output_profile);
Packit bc1512
Packit bc1512
  if (in)
Packit bc1512
    jas_stream_close (in);
Packit bc1512
Packit bc1512
  return ret;
Packit bc1512
}
Packit bc1512
Packit bc1512
static void
Packit bc1512
prepare (GeglOperation *operation)
Packit bc1512
{
Packit bc1512
  static gboolean initialized = FALSE;
Packit bc1512
Packit bc1512
  if (!initialized)
Packit bc1512
    {
Packit bc1512
      jas_init ();
Packit bc1512
      initialized = TRUE;
Packit bc1512
    }
Packit bc1512
}
Packit bc1512
Packit bc1512
static gboolean
Packit bc1512
process (GeglOperation       *operation,
Packit bc1512
         GeglBuffer          *output,
Packit bc1512
         const GeglRectangle *result,
Packit bc1512
         gint                 level)
Packit bc1512
{
Packit bc1512
  GeglChantO   *o = GEGL_CHANT_PROPERTIES (operation);
Packit bc1512
  GeglRectangle rect = {0,0,0,0};
Packit bc1512
  jas_image_t *image;
Packit bc1512
  gint width, height, depth;
Packit bc1512
  guchar *data_b;
Packit bc1512
  gushort *data_s;
Packit bc1512
  gboolean ret;
Packit bc1512
  int components[3];
Packit bc1512
  jas_matrix_t *matrices[3] = {NULL, NULL, NULL};
Packit bc1512
  gint i;
Packit bc1512
  gint row;
Packit bc1512
  gboolean b;
Packit bc1512
Packit bc1512
  image = NULL;
Packit bc1512
  data_b = NULL;
Packit bc1512
  data_s = NULL;
Packit bc1512
Packit bc1512
  width = height = depth = 0;
Packit bc1512
Packit bc1512
  if (!query_jp2 (o->path, &width, &height, &depth, &image))
Packit bc1512
    return FALSE;
Packit bc1512
Packit bc1512
  ret = FALSE;
Packit bc1512
  b = FALSE;
Packit bc1512
Packit bc1512
  do
Packit bc1512
    {
Packit bc1512
      components[0] = jas_image_getcmptbytype
Packit bc1512
        (image, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R));
Packit bc1512
      components[1] = jas_image_getcmptbytype
Packit bc1512
        (image, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G));
Packit bc1512
      components[2] = jas_image_getcmptbytype
Packit bc1512
        (image, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B));
Packit bc1512
Packit bc1512
      if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0))
Packit bc1512
        {
Packit bc1512
          g_warning (_("One or more of R, G, B components are missing "
Packit bc1512
                       "from '%s'"), o->path);
Packit bc1512
          break;
Packit bc1512
        }
Packit bc1512
Packit bc1512
      if (jas_image_cmptsgnd (image, components[0]) ||
Packit bc1512
          jas_image_cmptsgnd (image, components[1]) ||
Packit bc1512
          jas_image_cmptsgnd (image, components[2]))
Packit bc1512
        {
Packit bc1512
          g_warning (_("One or more of R, G, B components have signed "
Packit bc1512
                       "data in '%s'"), o->path);
Packit bc1512
          break;
Packit bc1512
        }
Packit bc1512
Packit bc1512
      for (i = 0; i < 3; i++)
Packit bc1512
        matrices[i] = jas_matrix_create(1, width);
Packit bc1512
Packit bc1512
      switch (depth)
Packit bc1512
        {
Packit bc1512
        case 16:
Packit bc1512
          data_s = (gushort *) g_malloc (width * 3 * sizeof (gushort));
Packit bc1512
          break;
Packit bc1512
Packit bc1512
        case 8:
Packit bc1512
          data_b = (guchar *) g_malloc (width * 3 * sizeof (guchar));
Packit bc1512
          break;
Packit bc1512
Packit bc1512
        default:
Packit bc1512
          g_warning ("%s: Programmer stupidity error", G_STRLOC);
Packit bc1512
          return FALSE;
Packit bc1512
        }
Packit bc1512
Packit bc1512
      for (row = 0; row < height; row++)
Packit bc1512
        {
Packit bc1512
          gint plane, col;
Packit bc1512
          jas_seqent_t *jrow[3] = {NULL, NULL, NULL};
Packit bc1512
Packit bc1512
          for (plane = 0; plane < 3; plane++)
Packit bc1512
            {
Packit bc1512
              int r = jas_image_readcmpt (image, components[plane], 0, row,
Packit bc1512
                                          width, 1, matrices[plane]);
Packit bc1512
              if (r)
Packit bc1512
                {
Packit bc1512
                  g_warning (_("Error reading row %d component %d from '%s'"),
Packit bc1512
                             row, plane, o->path);
Packit bc1512
                  b = TRUE;
Packit bc1512
                  break;
Packit bc1512
                }
Packit bc1512
            }
Packit bc1512
Packit bc1512
          if (b)
Packit bc1512
            break;
Packit bc1512
Packit bc1512
          for (plane = 0; plane < 3; plane++)
Packit bc1512
            jrow[plane] = jas_matrix_getref (matrices[plane], 0, 0);
Packit bc1512
Packit bc1512
          switch (depth)
Packit bc1512
            {
Packit bc1512
            case 16:
Packit bc1512
              for (col = 0; col < width; col++)
Packit bc1512
                {
Packit bc1512
                  data_s[col * 3]     = (gushort) jrow[0][col];
Packit bc1512
                  data_s[col * 3 + 1] = (gushort) jrow[1][col];
Packit bc1512
                  data_s[col * 3 + 2] = (gushort) jrow[2][col];
Packit bc1512
                }
Packit bc1512
              break;
Packit bc1512
Packit bc1512
            case 8:
Packit bc1512
              for (col = 0; col < width; col++)
Packit bc1512
                {
Packit bc1512
                  data_b[col * 3]     = (guchar) jrow[0][col];
Packit bc1512
                  data_b[col * 3 + 1] = (guchar) jrow[1][col];
Packit bc1512
                  data_b[col * 3 + 2] = (guchar) jrow[2][col];
Packit bc1512
                }
Packit bc1512
              break;
Packit bc1512
Packit bc1512
            default:
Packit bc1512
              g_warning ("%s: Programmer stupidity error", G_STRLOC);
Packit bc1512
              b = TRUE;
Packit bc1512
            }
Packit bc1512
Packit bc1512
          if (b)
Packit bc1512
            break;
Packit bc1512
Packit bc1512
          rect.x = 0;
Packit bc1512
          rect.y = row;
Packit bc1512
          rect.width = width;
Packit bc1512
          rect.height = 1;
Packit bc1512
Packit bc1512
          switch (depth)
Packit bc1512
            {
Packit bc1512
            case 16:
Packit bc1512
              gegl_buffer_set (output, &rect, 0, babl_format ("R'G'B' u16"),
Packit bc1512
                               data_s, GEGL_AUTO_ROWSTRIDE);
Packit bc1512
              break;
Packit bc1512
Packit bc1512
            case 8:
Packit bc1512
              gegl_buffer_set (output, &rect, 0, babl_format ("R'G'B' u8"),
Packit bc1512
                               data_b, GEGL_AUTO_ROWSTRIDE);
Packit bc1512
	      break;
Packit bc1512
Packit bc1512
            default:
Packit bc1512
              g_warning ("%s: Programmer stupidity error", G_STRLOC);
Packit bc1512
              b = TRUE;
Packit bc1512
            }
Packit bc1512
        }
Packit bc1512
Packit bc1512
      if (b)
Packit bc1512
        break;
Packit bc1512
Packit bc1512
      ret = TRUE;
Packit bc1512
    }
Packit bc1512
  while (FALSE); /* structured goto */
Packit bc1512
Packit bc1512
  for (i = 0; i < 3; i++)
Packit bc1512
    if (matrices[i])
Packit bc1512
      jas_matrix_destroy (matrices[i]);
Packit bc1512
Packit bc1512
  if (data_b)
Packit bc1512
    g_free (data_b);
Packit bc1512
Packit bc1512
  if (data_s)
Packit bc1512
    g_free (data_s);
Packit bc1512
Packit bc1512
  if (image)
Packit bc1512
    jas_image_destroy (image);
Packit bc1512
Packit bc1512
  return ret;
Packit bc1512
}
Packit bc1512
Packit bc1512
static GeglRectangle
Packit bc1512
get_bounding_box (GeglOperation * operation)
Packit bc1512
{
Packit bc1512
  GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
Packit bc1512
  GeglRectangle result = { 0, 0, 0, 0 };
Packit bc1512
  gint width, height, depth;
Packit bc1512
Packit bc1512
  width = height = depth = 0;
Packit bc1512
Packit bc1512
  if (!query_jp2 (o->path, &width, &height, &depth, NULL))
Packit bc1512
    return result;
Packit bc1512
Packit bc1512
  result.width = width;
Packit bc1512
  result.height = height;
Packit bc1512
Packit bc1512
  switch (depth)
Packit bc1512
    {
Packit bc1512
    case 16:
Packit bc1512
      gegl_operation_set_format (operation, "output",
Packit bc1512
                                 babl_format ("R'G'B' u16"));
Packit bc1512
      break;
Packit bc1512
Packit bc1512
    case 8:
Packit bc1512
      gegl_operation_set_format (operation, "output",
Packit bc1512
                                 babl_format ("R'G'B' u8"));
Packit bc1512
      break;
Packit bc1512
Packit bc1512
    default:
Packit bc1512
      g_warning ("%s: Programmer stupidity error", G_STRLOC);
Packit bc1512
    }
Packit bc1512
Packit bc1512
  return result;
Packit bc1512
}
Packit bc1512
Packit bc1512
static GeglRectangle
Packit bc1512
get_cached_region (GeglOperation       *operation,
Packit bc1512
                   const GeglRectangle *roi)
Packit bc1512
{
Packit bc1512
  return get_bounding_box (operation);
Packit bc1512
}
Packit bc1512
Packit bc1512
static void
Packit bc1512
gegl_chant_class_init (GeglChantClass *klass)
Packit bc1512
{
Packit bc1512
  GeglOperationClass       *operation_class;
Packit bc1512
  GeglOperationSourceClass *source_class;
Packit bc1512
Packit bc1512
  operation_class = GEGL_OPERATION_CLASS (klass);
Packit bc1512
  source_class    = GEGL_OPERATION_SOURCE_CLASS (klass);
Packit bc1512
Packit bc1512
  source_class->process = process;
Packit bc1512
  operation_class->prepare = prepare;
Packit bc1512
  operation_class->get_bounding_box = get_bounding_box;
Packit bc1512
  operation_class->get_cached_region = get_cached_region;
Packit bc1512
Packit bc1512
  gegl_operation_class_set_keys (operation_class,
Packit bc1512
    "name"        , "gegl:jp2-load",
Packit bc1512
    "categories"  , "hidden",
Packit bc1512
    "description" , _("JPEG 2000 image loader"),
Packit bc1512
    NULL);
Packit bc1512
Packit bc1512
  gegl_extension_handler_register (".jp2", "gegl:jp2-load");
Packit bc1512
  gegl_extension_handler_register (".jpx", "gegl:jp2-load");
Packit bc1512
}
Packit bc1512
Packit bc1512
#endif