Exemple #1
0
static gboolean
lcms_image_set_profile (gint32       image,
                        cmsHPROFILE  profile,
                        const gchar *filename,
                        gboolean     undo_group)
{
  g_return_val_if_fail (image != -1, FALSE);

  if (filename)
    {
      GimpParasite *parasite;
      GMappedFile  *file;
      GError       *error = NULL;

      file = g_mapped_file_new (filename, FALSE, &error);

      if (! file)
        {
          g_message ("%s", error->message);
          g_error_free (error);

          return FALSE;
        }

      /* check that this file is actually an ICC profile */
      if (! profile)
        {
          profile = cmsOpenProfileFromMem (g_mapped_file_get_contents (file),
                                           g_mapped_file_get_length (file));

          if (profile)
            {
              cmsCloseProfile (profile);
            }
          else
            {
              g_message (_("'%s' does not appear to be an ICC color profile"),
                         gimp_filename_to_utf8 (filename));
              return FALSE;
            }
        }

      if (undo_group)
        gimp_image_undo_group_start (image);

      parasite = gimp_parasite_new ("icc-profile",
                                    GIMP_PARASITE_PERSISTENT |
                                    GIMP_PARASITE_UNDOABLE,
                                    g_mapped_file_get_length (file),
                                    g_mapped_file_get_contents (file));

      g_mapped_file_unref (file);

      gimp_image_attach_parasite (image, parasite);
      gimp_parasite_free (parasite);
    }
  else
    {
      if (undo_group)
        gimp_image_undo_group_start (image);

      gimp_image_detach_parasite (image, "icc-profile");
    }

  gimp_image_detach_parasite (image, "icc-profile-name");

  if (undo_group)
    gimp_image_undo_group_end (image);

  return TRUE;
}
/**
 * gimp_image_parasite_attach:
 * @image_ID: The image.
 * @parasite: The parasite to attach to an image.
 *
 * Deprecated: Use gimp_image_attach_parasite() instead.
 *
 * Returns: TRUE on success.
 **/
gboolean
gimp_image_parasite_attach (gint32              image_ID,
                            const GimpParasite *parasite)
{
  return gimp_image_attach_parasite (image_ID, parasite);
}
Exemple #3
0
static gboolean
lcms_image_set_profile (gint32       image,
                        cmsHPROFILE  profile,
                        GFile       *file)
{
  g_return_val_if_fail (image != -1, FALSE);

  if (file)
    {
      cmsHPROFILE   file_profile;
      GimpParasite *parasite;
      guint8       *profile_data;
      gsize         profile_length;
      GError       *error = NULL;

      /* check that this file is actually an ICC profile */
      file_profile = gimp_lcms_profile_open_from_file (file, &error);

      if (! file_profile)
        {
          g_message ("%s", error->message);
          g_clear_error (&error);

          return FALSE;
        }

      profile_data = gimp_lcms_profile_save_to_data (file_profile,
                                                     &profile_length,
                                                     &error);
      cmsCloseProfile (file_profile);

      if (! profile_data)
        {
          g_message ("%s", error->message);
          g_clear_error (&error);

          return FALSE;
        }

      gimp_image_undo_group_start (image);

      parasite = gimp_parasite_new ("icc-profile",
                                    GIMP_PARASITE_PERSISTENT |
                                    GIMP_PARASITE_UNDOABLE,
                                    profile_length, profile_data);

      g_free (profile_data);

      gimp_image_attach_parasite (image, parasite);
      gimp_parasite_free (parasite);
    }
  else
    {
      gimp_image_undo_group_start (image);

      gimp_image_detach_parasite (image, "icc-profile");
    }

  gimp_image_detach_parasite (image, "icc-profile-name");

  gimp_image_undo_group_end (image);

  return TRUE;
}
Exemple #4
0
gint32
load_image (const gchar  *filename,
            GimpRunMode   runmode,
            gboolean      preview,
            gboolean     *resolution_loaded,
            GError      **error)
{
  gint32 volatile  image_ID;
  gint32           layer_ID;
  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr           jerr;
  jpeg_saved_marker_ptr         marker;
  FILE            *infile;
  guchar          *buf;
  guchar         **rowbuf;
  GimpImageBaseType image_type;
  GimpImageType    layer_type;
  GeglBuffer      *buffer = NULL;
  const Babl      *format;
  gint             tile_height;
  gint             scanlines;
  gint             i, start, end;
  cmsHTRANSFORM    cmyk_transform = NULL;

  /* We set up the normal JPEG error routines. */
  cinfo.err = jpeg_std_error (&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  if (!preview)
    {
      jerr.pub.output_message = my_output_message;

      gimp_progress_init_printf (_("Opening '%s'"),
                                 gimp_filename_to_utf8 (filename));
    }

  if ((infile = g_fopen (filename, "rb")) == 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;
    }

  image_ID = -1;

  /* Establish the setjmp return context for my_error_exit to use. */
  if (setjmp (jerr.setjmp_buffer))
    {
      /* If we get here, the JPEG code has signaled an error.
       * We need to clean up the JPEG object, close the input file, and return.
       */
      jpeg_destroy_decompress (&cinfo);
      if (infile)
        fclose (infile);

      if (image_ID != -1 && !preview)
        gimp_image_delete (image_ID);

      if (preview)
        destroy_preview ();

      if (buffer)
        g_object_unref (buffer);

      return -1;
    }

  /* Now we can initialize the JPEG decompression object. */
  jpeg_create_decompress (&cinfo);

  /* Step 2: specify data source (eg, a file) */

  jpeg_stdio_src (&cinfo, infile);

  if (! preview)
    {
      /* - step 2.1: tell the lib to save the comments */
      jpeg_save_markers (&cinfo, JPEG_COM, 0xffff);

      /* - step 2.2: tell the lib to save APP1 data (Exif or XMP) */
      jpeg_save_markers (&cinfo, JPEG_APP0 + 1, 0xffff);

      /* - step 2.3: tell the lib to save APP2 data (ICC profiles) */
      jpeg_save_markers (&cinfo, JPEG_APP0 + 2, 0xffff);
    }

  /* Step 3: read file parameters with jpeg_read_header() */

  jpeg_read_header (&cinfo, TRUE);

  /* We can ignore the return value from jpeg_read_header since
   *   (a) suspension is not possible with the stdio data source, and
   *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
   * See libjpeg.doc for more info.
   */

  /* Step 4: set parameters for decompression */

  /* In this example, we don't need to change any of the defaults set by
   * jpeg_read_header(), so we do nothing here.
   */

  /* Step 5: Start decompressor */

  jpeg_start_decompress (&cinfo);

  /* We may need to do some setup of our own at this point before reading
   * the data.  After jpeg_start_decompress() we have the correct scaled
   * output image dimensions available, as well as the output colormap
   * if we asked for color quantization.
   */

  /* temporary buffer */
  tile_height = gimp_tile_height ();
  buf = g_new (guchar,
               tile_height * cinfo.output_width * cinfo.output_components);

  rowbuf = g_new (guchar *, tile_height);

  for (i = 0; i < tile_height; i++)
    rowbuf[i] = buf + cinfo.output_width * cinfo.output_components * i;

  switch (cinfo.output_components)
    {
    case 1:
      image_type = GIMP_GRAY;
      layer_type = GIMP_GRAY_IMAGE;
      break;

    case 3:
      image_type = GIMP_RGB;
      layer_type = GIMP_RGB_IMAGE;
      break;

    case 4:
      if (cinfo.out_color_space == JCS_CMYK)
        {
          image_type = GIMP_RGB;
          layer_type = GIMP_RGB_IMAGE;
          break;
        }
      /*fallthrough*/

    default:
      g_message ("Don't know how to load JPEG images "
                 "with %d color channels, using colorspace %d (%d).",
                 cinfo.output_components, cinfo.out_color_space,
                 cinfo.jpeg_color_space);
      return -1;
      break;
    }

  if (preview)
    {
      image_ID = preview_image_ID;
    }
  else
    {
      image_ID = gimp_image_new_with_precision (cinfo.output_width,
                                                cinfo.output_height,
                                                image_type,
                                                GIMP_PRECISION_U8_GAMMA);

      gimp_image_undo_disable (image_ID);
      gimp_image_set_filename (image_ID, filename);
    }

  if (preview)
    {
      preview_layer_ID = gimp_layer_new (preview_image_ID, _("JPEG preview"),
                                         cinfo.output_width,
                                         cinfo.output_height,
                                         layer_type, 100, GIMP_NORMAL_MODE);
      layer_ID = preview_layer_ID;
    }
  else
    {
      layer_ID = gimp_layer_new (image_ID, _("Background"),
                                 cinfo.output_width,
                                 cinfo.output_height,
                                 layer_type, 100, GIMP_NORMAL_MODE);
    }

  if (! preview)
    {
      GString  *comment_buffer = NULL;
      guint8   *profile        = NULL;
      guint     profile_size   = 0;

      /* Step 5.0: save the original JPEG settings in a parasite */
      jpeg_detect_original_settings (&cinfo, image_ID);

      /* Step 5.1: check for comments, or Exif metadata in APP1 markers */
      for (marker = cinfo.marker_list; marker; marker = marker->next)
        {
          const gchar *data = (const gchar *) marker->data;
          gsize        len  = marker->data_length;

          if (marker->marker == JPEG_COM)
            {
#ifdef GIMP_UNSTABLE
              g_print ("jpeg-load: found image comment (%d bytes)\n",
                       marker->data_length);
#endif

              if (! comment_buffer)
                {
                  comment_buffer = g_string_new_len (data, len);
                }
              else
                {
                  /* concatenate multiple comments, separate them with LF */
                  g_string_append_c (comment_buffer, '\n');
                  g_string_append_len (comment_buffer, data, len);
                }
            }
          else if ((marker->marker == JPEG_APP0 + 1)
                   && (len > sizeof (JPEG_APP_HEADER_EXIF) + 8)
                   && ! strcmp (JPEG_APP_HEADER_EXIF, data))
            {
#ifdef GIMP_UNSTABLE
              g_print ("jpeg-load: found Exif block (%d bytes)\n",
                       (gint) (len - sizeof (JPEG_APP_HEADER_EXIF)));
#endif
            }
        }

      if (jpeg_load_resolution (image_ID, &cinfo))
        {
          if (resolution_loaded)
            *resolution_loaded = TRUE;
        }

      /* if we found any comments, then make a parasite for them */
      if (comment_buffer && comment_buffer->len)
        {
          GimpParasite *parasite;

          jpeg_load_sanitize_comment (comment_buffer->str);
          parasite = gimp_parasite_new ("gimp-comment",
                                        GIMP_PARASITE_PERSISTENT,
                                        strlen (comment_buffer->str) + 1,
                                        comment_buffer->str);
          gimp_image_attach_parasite (image_ID, parasite);
          gimp_parasite_free (parasite);

          g_string_free (comment_buffer, TRUE);
        }

      /* Step 5.3: check for an embedded ICC profile in APP2 markers */
      jpeg_icc_read_profile (&cinfo, &profile, &profile_size);

      if (cinfo.out_color_space == JCS_CMYK)
        {
          cmyk_transform = jpeg_load_cmyk_transform (profile, profile_size);
        }
      else if (profile) /* don't attach the profile if we are transforming */
        {
          GimpParasite *parasite;

          parasite = gimp_parasite_new ("icc-profile",
                                        GIMP_PARASITE_PERSISTENT |
                                        GIMP_PARASITE_UNDOABLE,
                                        profile_size, profile);
          gimp_image_attach_parasite (image_ID, parasite);
          gimp_parasite_free (parasite);
        }

      g_free (profile);

      /* Do not attach the "jpeg-save-options" parasite to the image
       * because this conflicts with the global defaults (bug #75398).
       */
    }

  /* Step 6: while (scan lines remain to be read) */
  /*           jpeg_read_scanlines(...); */

  /* Here we use the library's state variable cinfo.output_scanline as the
   * loop counter, so that we don't have to keep track ourselves.
   */

  buffer = gimp_drawable_get_buffer (layer_ID);
  format = babl_format (image_type == GIMP_RGB ? "R'G'B' u8" : "Y' u8");

  while (cinfo.output_scanline < cinfo.output_height)
    {
      start = cinfo.output_scanline;
      end   = cinfo.output_scanline + tile_height;
      end   = MIN (end, cinfo.output_height);

      scanlines = end - start;

      for (i = 0; i < scanlines; i++)
        jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &rowbuf[i], 1);

      if (cinfo.out_color_space == JCS_CMYK)
        jpeg_load_cmyk_to_rgb (buf, cinfo.output_width * scanlines,
                               cmyk_transform);

      gegl_buffer_set (buffer,
                       GEGL_RECTANGLE (0, start, cinfo.output_width, scanlines),
                       0,
                       format,
                       buf,
                       GEGL_AUTO_ROWSTRIDE);

      if (! preview && (cinfo.output_scanline % 32) == 0)
        gimp_progress_update ((gdouble) cinfo.output_scanline /
                              (gdouble) cinfo.output_height);
    }

  /* Step 7: Finish decompression */

  jpeg_finish_decompress (&cinfo);
  /* We can ignore the return value since suspension is not possible
   * with the stdio data source.
   */

  if (cmyk_transform)
    cmsDeleteTransform (cmyk_transform);

  /* Step 8: Release JPEG decompression object */

  /* This is an important step since it will release a good deal of memory. */
  jpeg_destroy_decompress (&cinfo);

  g_object_unref (buffer);

  /* free up the temporary buffers */
  g_free (rowbuf);
  g_free (buf);

  /* After finish_decompress, we can close the input file.
   * Here we postpone it until after no more JPEG errors are possible,
   * so as to simplify the setjmp error logic above.  (Actually, I don't
   * think that jpeg_destroy can do an error exit, but why assume anything...)
   */
  fclose (infile);

  /* At this point you may want to check to see whether any corrupt-data
   * warnings occurred (test whether jerr.num_warnings is nonzero).
   */

  /* Detach from the drawable and add it to the image.
   */
  if (! preview)
    {
      gimp_progress_update (1.0);
    }

  gimp_image_insert_layer (image_ID, layer_ID, -1, 0);

  return image_ID;
}
static gint32
load_image (const gchar  *filename,
            gboolean      thumbnail,
            GError      **error)
{
  FILE     *fd;
  guchar    buf[16];
  guchar    c;
  CMap      localColorMap;
  gint      grayScale;
  gboolean  useGlobalColormap;
  gint      bitPixel;
  gint      imageCount = 0;
  gchar     version[4];
  gint32    image_ID = -1;

  fd = g_fopen (filename, "rb");

  if (! fd)
    {
      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;
    }

  gimp_progress_init_printf (_("Opening '%s'"),
                             gimp_filename_to_utf8 (filename));

  if (! ReadOK (fd, buf, 6))
    {
      g_message ("Error reading magic number");
      return -1;
    }

  if (strncmp ((gchar *) buf, "GIF", 3) != 0)
    {
      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                   "%s", _("This is not a GIF file"));
      return -1;
    }

  strncpy (version, (gchar *) buf + 3, 3);
  version[3] = '\0';

  if ((strcmp (version, "87a") != 0) && (strcmp (version, "89a") != 0))
    {
      g_message ("Bad version number, not '87a' or '89a'");
      return -1;
    }

  if (! ReadOK (fd, buf, 7))
    {
      g_message ("Failed to read screen descriptor");
      return -1;
    }

  GifScreen.Width           = LM_to_uint (buf[0], buf[1]);
  GifScreen.Height          = LM_to_uint (buf[2], buf[3]);
  GifScreen.BitPixel        = 2 << (buf[4] & 0x07);
  GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
  GifScreen.Background      = buf[5];
  GifScreen.AspectRatio     = buf[6];

  if (BitSet (buf[4], LOCALCOLORMAP))
    {
      /* Global Colormap */
      if (! ReadColorMap (fd, GifScreen.BitPixel, GifScreen.ColorMap,
                          &GifScreen.GrayScale))
        {
          g_message ("Error reading global colormap");
          return -1;
        }
    }

  if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49)
    {
      g_message (_("Non-square pixels.  Image might look squashed."));
    }


  highest_used_index = 0;

  while (TRUE)
    {
      if (! ReadOK (fd, &c, 1))
        {
          g_message ("EOF / read error on image data");
          return image_ID; /* will be -1 if failed on first image! */
        }

      if (c == ';')
        {
          /* GIF terminator */
          return image_ID;
        }

      if (c == '!')
        {
          /* Extension */
          if (! ReadOK (fd, &c, 1))
            {
              g_message ("EOF / read error on extension function code");
              return image_ID; /* will be -1 if failed on first image! */
            }

          DoExtension (fd, c);
          continue;
        }

      if (c != ',')
        {
          /* Not a valid start character */
          g_printerr ("GIF: bogus character 0x%02x, ignoring.\n", (int) c);
          continue;
        }

      ++imageCount;

      if (! ReadOK (fd, buf, 9))
        {
          g_message ("Couldn't read left/top/width/height");
          return image_ID; /* will be -1 if failed on first image! */
        }

      useGlobalColormap = !BitSet (buf[8], LOCALCOLORMAP);

      bitPixel = 1 << ((buf[8] & 0x07) + 1);

      if (! useGlobalColormap)
        {
          if (! ReadColorMap (fd, bitPixel, localColorMap, &grayScale))
            {
              g_message ("Error reading local colormap");
              return image_ID; /* will be -1 if failed on first image! */
            }

          image_ID = ReadImage (fd, filename, LM_to_uint (buf[4], buf[5]),
                                LM_to_uint (buf[6], buf[7]),
                                localColorMap, bitPixel,
                                grayScale,
                                BitSet (buf[8], INTERLACE), imageCount,
                                (guint) LM_to_uint (buf[0], buf[1]),
                                (guint) LM_to_uint (buf[2], buf[3]),
                                GifScreen.Width,
                                GifScreen.Height);
        }
      else
        {
          image_ID = ReadImage (fd, filename, LM_to_uint (buf[4], buf[5]),
                                LM_to_uint (buf[6], buf[7]),
                                GifScreen.ColorMap, GifScreen.BitPixel,
                                GifScreen.GrayScale,
                                BitSet (buf[8], INTERLACE), imageCount,
                                (guint) LM_to_uint (buf[0], buf[1]),
                                (guint) LM_to_uint (buf[2], buf[3]),
                                GifScreen.Width,
                                GifScreen.Height);
        }

      if (comment_parasite != NULL)
        {
          if (! thumbnail)
            gimp_image_attach_parasite (image_ID, comment_parasite);

          gimp_parasite_free (comment_parasite);
          comment_parasite = NULL;
        }

      /* If we are loading a thumbnail, we stop after the first frame. */
      if (thumbnail)
        break;
    }

  return image_ID;
}
Exemple #6
0
static void
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
{
  static GimpParam  values[MAX_EXTRACT_IMAGES + 1];
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  gint32            num_images;
  gint32            image_ID_extract[MAX_EXTRACT_IMAGES];
  gint32            layer_ID_extract[MAX_EXTRACT_IMAGES];
  gint              j;
  gint32            layer;
  gint32            num_layers;
  gint32            image_ID;

  INIT_I18N ();
  gegl_init (NULL, NULL);

  run_mode = param[0].data.d_int32;
  image_ID = param[1].data.d_image;
  layer    = param[2].data.d_drawable;

  *nreturn_vals = MAX_EXTRACT_IMAGES + 1;
  *return_vals  = values;

  values[0].type          = GIMP_PDB_STATUS;
  values[0].data.d_status = status;

  for (j = 0; j < MAX_EXTRACT_IMAGES; j++)
    {
      values[j+1].type         = GIMP_PDB_IMAGE;
      values[j+1].data.d_int32 = -1;
    }

  switch (run_mode)
    {
    case GIMP_RUN_INTERACTIVE:
      /*  Possibly retrieve data  */
      gimp_get_data (PLUG_IN_PROC, &decovals);

      /*  First acquire information with a dialog  */
      if (! decompose_dialog ())
        return;
      break;

    case GIMP_RUN_NONINTERACTIVE:
      /*  Make sure all the arguments are there!  */
      if (nparams != 4 && nparams != 5 && nparams != 6)
        {
          status = GIMP_PDB_CALLING_ERROR;
        }
      else
        {
          strncpy (decovals.extract_type, param[3].data.d_string,
                   sizeof (decovals.extract_type));
          decovals.extract_type[sizeof (decovals.extract_type) - 1] = '\0';

          decovals.as_layers = nparams > 4 ? param[4].data.d_int32 : FALSE;
          decovals.use_registration = (strcmp (name, PLUG_IN_PROC_REG) == 0);
        }
      break;

    case GIMP_RUN_WITH_LAST_VALS:
      /*  Possibly retrieve data  */
      gimp_get_data (PLUG_IN_PROC, &decovals);
      break;

    default:
      break;
    }

  if (status == GIMP_PDB_SUCCESS)
    {
      gimp_progress_init (_("Decomposing"));

      num_images = decompose (image_ID, layer,
                              decovals.extract_type,
                              image_ID_extract,
                              &num_layers,
                              layer_ID_extract);

      if (num_images <= 0)
        {
          status = GIMP_PDB_EXECUTION_ERROR;
        }
      else
        {
          /* create decompose-data parasite */
          GString *data = g_string_new ("");

          g_string_printf (data, "source=%d type=%s ",
                           layer, decovals.extract_type);

          for (j = 0; j < num_layers; j++)
            g_string_append_printf (data, "%d ", layer_ID_extract[j]);

          for (j = 0; j < num_images; j++)
            {
              GimpParasite *parasite;

              values[j+1].data.d_int32 = image_ID_extract[j];

              gimp_image_undo_enable (image_ID_extract[j]);
              gimp_image_clean_all (image_ID_extract[j]);

              parasite = gimp_parasite_new ("decompose-data",
                                            0, data->len + 1, data->str);
              gimp_image_attach_parasite (image_ID_extract[j], parasite);
              gimp_parasite_free (parasite);

              if (run_mode != GIMP_RUN_NONINTERACTIVE)
                gimp_display_new (image_ID_extract[j]);
            }

          /*  Store data  */
          if (run_mode == GIMP_RUN_INTERACTIVE)
            gimp_set_data (PLUG_IN_PROC, &decovals, sizeof (DecoVals));
        }

      gimp_progress_end ();
    }

  values[0].data.d_status = status;
}
Exemple #7
0
static void
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
{
  static GimpParam   values[4];
  gint32             image_ID;
  XMPModel          *xmp_model;
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
  GimpParasite      *parasite = NULL;

  *nreturn_vals = 1;
  *return_vals  = values;

  values[0].type          = GIMP_PDB_STATUS;
  values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;

  INIT_I18N();

  if (! strcmp (name, EDITOR_PROC))
    image_ID = param[1].data.d_image;
  else
    image_ID = param[0].data.d_image;

  xmp_model = xmp_model_new ();

  /* if there is already a metadata parasite, load it */
  parasite = gimp_image_get_parasite (image_ID, METADATA_PARASITE);
  if (parasite)
    {
      GError *error = NULL;

      if (!! strncmp (gimp_parasite_data (parasite),
                      METADATA_MARKER, METADATA_MARKER_LEN)
          || ! xmp_model_parse_buffer (xmp_model,
                                       (const gchar *) gimp_parasite_data (parasite)
                                       + METADATA_MARKER_LEN,
                                       gimp_parasite_data_size (parasite)
                                       - METADATA_MARKER_LEN,
                                       TRUE, &error))
        {
          g_printerr ("\nMetadata parasite seems to be corrupt\n");
          /* continue anyway, we will attach a clean parasite later */
        }
      gimp_parasite_free (parasite);
    }

  /* If we have no metadata yet, try to find an XMP packet in the file
   * (but ignore errors if nothing is found).
   *
   * FIXME: This is a workaround until all file plug-ins do the right
   * thing when loading their files.
   */
  if (xmp_model_is_empty (xmp_model)
      && !! strcmp (name, DECODE_XMP_PROC))
    {
      const gchar *filename;
      GError      *error = NULL;

      filename = gimp_image_get_filename (image_ID);
      if (filename != NULL)
        if (xmp_model_parse_file (xmp_model, filename, &error))
          /* g_message ("XMP loaded from file '%s'\n", filename) */;
    }

  /* Now check what we are supposed to do */
  if (! strcmp (name, DECODE_XMP_PROC))
    {
      const gchar *buffer;
      GError      *error = NULL;

      buffer = param[1].data.d_string;
      if (! xmp_model_parse_buffer (xmp_model, buffer, strlen (buffer),
                                    FALSE, &error))
        status = GIMP_PDB_EXECUTION_ERROR;

    }
  else if (! strcmp (name, ENCODE_XMP_PROC))
    {
      /* done below together with the parasite */
    }
  else if (! strcmp (name, DECODE_EXIF_PROC))
    {
        GError      *error         = NULL;

        if (! xmp_merge_from_exifbuffer (xmp_model, image_ID, &error))
          {
            status = GIMP_PDB_EXECUTION_ERROR;
            g_printerr ("\nExif to XMP merge failed.\n");
          }
    }
  else if (! strcmp (name, GET_PROC))
    {
      g_printerr ("Not implemented yet (GET_PROC)\n"); /* FIXME */
      status = GIMP_PDB_EXECUTION_ERROR;
    }
  else if (! strcmp (name, SET_PROC))
    {
      g_printerr ("Not implemented yet (SET_PROC)\n"); /* FIXME */
      status = GIMP_PDB_EXECUTION_ERROR;
    }
  else if (! strcmp (name, GET_SIMPLE_PROC))
    {
      const gchar *schema_name;
      const gchar *property_name;
      const gchar *value;

      schema_name = param[1].data.d_string;
      property_name = param[2].data.d_string;
      value = xmp_model_get_scalar_property (xmp_model, schema_name,
                                             property_name);
      if (value)
        {
          *nreturn_vals = 2;
          values[1].type = GIMP_PDB_STRING;
          values[1].data.d_string = g_strdup (value);
        }
      else
        status = GIMP_PDB_EXECUTION_ERROR;
    }
  else if (! strcmp (name, SET_SIMPLE_PROC))
    {
      const gchar *schema_name;
      const gchar *property_name;
      const gchar *property_value;

      schema_name = param[1].data.d_string;
      property_name = param[2].data.d_string;
      property_value = param[3].data.d_string;
      if (! xmp_model_set_scalar_property (xmp_model, schema_name,
                                           property_name, property_value))
        status = GIMP_PDB_EXECUTION_ERROR;
    }
  else if (! strcmp (name, IMPORT_PROC))
    {
      const gchar *filename;
      gchar       *buffer;
      gsize        buffer_length;
      GError      *error = NULL;

      filename = param[1].data.d_string;
      if (! g_file_get_contents (filename, &buffer, &buffer_length, &error))
        {
          g_error_free (error);
          status = GIMP_PDB_EXECUTION_ERROR;
        }
      else if (! xmp_model_parse_buffer (xmp_model, buffer, buffer_length,
                                         TRUE, &error))
        {
          g_error_free (error);
          status = GIMP_PDB_EXECUTION_ERROR;
        }
      g_free (buffer);
    }
  else if (! strcmp (name, EXPORT_PROC))
    {
      /* FIXME: this is easy to implement, but the first thing to do is */
      /* to improve the code of export_dialog_response() in interface.c */
      g_printerr ("Not implemented yet (EXPORT_PROC)\n");
      status = GIMP_PDB_EXECUTION_ERROR;
    }
  else if (! strcmp (name, EDITOR_PROC))
    {
      GimpRunMode run_mode;

      run_mode = param[0].data.d_int32;
      if (run_mode == GIMP_RUN_INTERACTIVE)
        {
          if (! metadata_dialog (image_ID, xmp_model))
            status = GIMP_PDB_CANCEL;
        }

      g_printerr ("Not implemented yet (EDITOR_PROC)\n");
      status = GIMP_PDB_EXECUTION_ERROR;
    }
  else
    {
      status = GIMP_PDB_CALLING_ERROR;
    }

  if (status == GIMP_PDB_SUCCESS)
    {
      GString *buffer;

      /* Generate the updated parasite and attach it to the image */
      buffer = g_string_new (METADATA_MARKER);
      xmp_generate_packet (xmp_model, buffer);
      parasite = gimp_parasite_new (METADATA_PARASITE,
                                    GIMP_PARASITE_PERSISTENT,
                                    buffer->len,
                                    (gpointer) buffer->str);
      gimp_image_attach_parasite (image_ID, parasite);
      if (! strcmp (name, ENCODE_XMP_PROC))
        {
          *nreturn_vals = 2;
          values[1].type = GIMP_PDB_STRING;
          values[1].data.d_string = g_strdup (buffer->str
                                              + METADATA_MARKER_LEN);
        }
      g_string_free (buffer, TRUE);
    }

  g_object_unref (xmp_model);

  values[0].data.d_status = status;
}