Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  decompose.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * Decompose plug-in (C) 1997 Peter Kirchgessner
 * e-mail: peter@kirchgessner.net, WWW: http://www.kirchgessner.net
 *
 * Copyright 2013 Martijn van Beers <mail_dev@martijn.at>
 * Copyright 2013 Téo Mazars        <teo.mazars@ensimag.fr>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */


/*  Lab colorspace support originally written by Alexey Dyachenko,
 *  merged into the officical plug-in by Sven Neumann.
 */


#include "config.h"

#include <string.h>

#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>

#include "libgimp/stdplugins-intl.h"

#define PLUG_IN_PROC   "plug-in-decompose"
#define PLUG_IN_BINARY "decompose"
#define PLUG_IN_ROLE   "gimp-decompose"


/* Description of a component */
typedef struct
{
  const gchar    *babl_name;           /* channel's  babl_component name    */
  const gchar    *channel_name;        /* name of channel to extract        */

  const gdouble   range_min;           /* min and max                       */
  const gdouble   range_max;
  const gboolean  perceptual_channel;  /* "correct" the channel in Y' space */

} Component;


/* Maximum number of images/layers generated by an extraction */
#define MAX_EXTRACT_IMAGES 4

/* Description of an extraction */
typedef struct
{
  const gchar     *type;        /* What to extract */
  const gchar     *model;       /* the babl_model string to use */
  const gboolean   dialog;      /* Set to TRUE if you want
                                 * this extract function in the dialog */

  const gint       num_images;  /* Number of images to create */

  const gboolean   clamp;       /* clamping values in [0.0, 1.0] */

                                /* the babl_component names of the channels */
  const Component  component[MAX_EXTRACT_IMAGES];

} Extract;


typedef struct _Decompose      Decompose;
typedef struct _DecomposeClass DecomposeClass;

struct _Decompose
{
  GimpPlugIn parent_instance;
};

struct _DecomposeClass
{
  GimpPlugInClass parent_class;
};


#define DECOMPOSE_TYPE  (decompose_get_type ())
#define DECOMPOSE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DECOMPOSE_TYPE, Decompose))

GType                   decompose_get_type         (void) G_GNUC_CONST;

static GList          * decompose_query_procedures (GimpPlugIn           *plug_in);
static GimpProcedure  * decompose_create_procedure (GimpPlugIn           *plug_in,
                                                    const gchar          *name);

static GimpValueArray * decompose_run              (GimpProcedure        *procedure,
                                                    GimpRunMode           run_mode,
                                                    GimpImage            *image,
                                                    GimpDrawable        **drawables,
                                                    GimpProcedureConfig  *config,
                                                    gpointer              run_data);

static gint        decompose                   (GimpImage           *image,
                                                GimpDrawable        *drawable,
                                                GObject             *config,
                                                GimpImage          **image_dst,
                                                gint32              *num_layers,
                                                GimpLayer          **layer_dst);
static GimpImage * create_new_image            (GFile               *file,
                                                const gchar         *layername,
                                                guint                width,
                                                guint                height,
                                                GimpImageBaseType    type,
                                                GimpPrecision        precision,
                                                gdouble              xres,
                                                gdouble              yres,
                                                GimpLayer          **layer);
static GimpLayer * create_new_layer            (GimpImage           *image,
                                                gint                 position,
                                                const gchar         *layername,
                                                guint                width,
                                                guint                height,
                                                GimpImageBaseType    type);
static void        transfer_registration_color (GeglBuffer          *src,
                                                GeglBuffer         **dst,
                                                gint                 count);
static void        cpn_affine_transform_clamp  (GeglBuffer          *buffer,
                                                gdouble              min,
                                                gdouble              max,
                                                gboolean             clamp);
static void        copy_n_components           (GeglBuffer          *src,
                                                GeglBuffer         **dst,
                                                Extract              ext);
static void        copy_one_component          (GeglBuffer          *src,
                                                GeglBuffer          *dst,
                                                const char          *model,
                                                const Component      component,
                                                gboolean             clamp);
static gboolean    decompose_dialog            (GimpProcedure       *procedure,
                                                GObject             *config);
static gchar   *   generate_filename           (GimpImage           *image,
                                                GObject             *config,
                                                guint                colorspace,
                                                guint                channel);


G_DEFINE_TYPE (Decompose, decompose, GIMP_TYPE_PLUG_IN)

GIMP_MAIN (DECOMPOSE_TYPE)
DEFINE_STD_SET_I18N


#define CPN_RGBA_R      { "R",          N_("red"),           0.0, 1.0, FALSE }
#define CPN_RGBA_G      { "G",          N_("green"),         0.0, 1.0, FALSE }
#define CPN_RGBA_B      { "B",          N_("blue"),          0.0, 1.0, FALSE }
#define CPN_RGBA_A      { "A",          N_("alpha"),         0.0, 1.0, TRUE  }

#define CPN_HSV_H       { "hue",        N_("hue"),           0.0, 1.0, TRUE }
#define CPN_HSV_S       { "saturation", N_("saturation"),    0.0, 1.0, TRUE }
#define CPN_HSV_V       { "value",      N_("value"),         0.0, 1.0, TRUE }

#define CPN_HSL_H       { "hue",        N_("hue"),           0.0, 1.0, TRUE }
#define CPN_HSL_S       { "saturation", N_("saturation"),    0.0, 1.0, TRUE }
#define CPN_HSL_L       { "lightness",  N_("lightness"),     0.0, 1.0, TRUE }

#define CPN_CMYK_C      { "Cyan",       N_("cyan"),          0.0, 1.0, TRUE }
#define CPN_CMYK_M      { "Magenta",    N_("magenta"),       0.0, 1.0, TRUE }
#define CPN_CMYK_Y      { "Yellow",     N_("yellow"),        0.0, 1.0, TRUE }
#define CPN_CMYK_K      { "Key",        N_("black"),         0.0, 1.0, TRUE }

#define CPN_LAB_L       { "CIE L",      N_("L"),             0.0, 100.0, TRUE }
#define CPN_LAB_A       { "CIE a",      N_("A"),          -127.5, 127.5, TRUE }
#define CPN_LAB_B       { "CIE b",      N_("B"),          -127.5, 127.5, TRUE }

#define CPN_LCH_L       { "CIE L",      N_("L"),             0.0, 100.0, TRUE }
#define CPN_LCH_C       { "CIE C(ab)",  N_("C"),             0.0, 200.0, TRUE }
#define CPN_LCH_H       { "CIE H(ab)",  N_("H"),             0.0, 360.0, TRUE }

#define CPN_YCBCR_Y     { "Y'",         N_("luma-y470"),       0.0, 1.0, TRUE }
#define CPN_YCBCR_CB    { "Cb",         N_("blueness-cb470"), -0.5, 0.5, TRUE }
#define CPN_YCBCR_CR    { "Cr",         N_("redness-cr470"),  -0.5, 0.5, TRUE }

#define CPN_YCBCR709_Y  { "Y'",         N_("luma-y709"),       0.0, 1.0, TRUE }
#define CPN_YCBCR709_CB { "Cb",         N_("blueness-cb709"), -0.5, 0.5, TRUE }
#define CPN_YCBCR709_CR { "Cr",         N_("redness-cr709"),  -0.5, 0.5, TRUE }


static const Extract extract[] =
{
  { N_("RGB"),   "RGB",  TRUE,  3, FALSE, { CPN_RGBA_R, CPN_RGBA_G, CPN_RGBA_B } },
  { N_("RGBA"),  "RGBA", TRUE,  4, FALSE, { CPN_RGBA_R, CPN_RGBA_G, CPN_RGBA_B, CPN_RGBA_A } },

  { N_("Red"),   "RGB",  FALSE, 1, FALSE, { CPN_RGBA_R } },
  { N_("Green"), "RGB",  FALSE, 1, FALSE, { CPN_RGBA_G } },
  { N_("Blue"),  "RGB",  FALSE, 1, FALSE, { CPN_RGBA_B } },
  { N_("Alpha"), "RGBA", TRUE , 1, FALSE, { CPN_RGBA_A } },

  { N_("HSV"),        "HSV",  TRUE,  3, FALSE, { CPN_HSV_H, CPN_HSV_S, CPN_HSV_V } },
  { N_("Hue"),        "HSV",  FALSE, 1, FALSE, { CPN_HSV_H } },
  { N_("Saturation"), "HSV",  FALSE, 1, FALSE, { CPN_HSV_S } },
  { N_("Value"),      "HSV",  FALSE, 1, FALSE, { CPN_HSV_V } },

  { N_("HSL"),              "HSL", TRUE,  3, FALSE, { CPN_HSL_H, CPN_HSL_S, CPN_HSL_L } },
  { N_("Hue (HSL)"),        "HSL", FALSE, 1, FALSE, { CPN_HSL_H } },
  { N_("Saturation (HSL)"), "HSL", FALSE, 1, FALSE, { CPN_HSL_S } },
  { N_("Lightness"),        "HSL", FALSE, 1, FALSE, { CPN_HSL_L } },

  { N_("CMYK"),      "CMYK", TRUE,  4, FALSE, { CPN_CMYK_C, CPN_CMYK_M, CPN_CMYK_Y, CPN_CMYK_K } },
  { N_("Cyan"),      "CMYK", FALSE, 1, FALSE, { CPN_CMYK_C } },
  { N_("Magenta"),   "CMYK", FALSE, 1, FALSE, { CPN_CMYK_M } },
  { N_("Yellow"),    "CMYK", FALSE, 1, FALSE, { CPN_CMYK_Y } },
  { N_("Black"),     "CMYK", FALSE, 1, FALSE, { CPN_CMYK_K } },

  { N_("LAB"), "CIE Lab",     TRUE, 3, FALSE, { CPN_LAB_L, CPN_LAB_A, CPN_LAB_B } },

  { N_("LCH"), "CIE LCH(ab)", TRUE, 3, FALSE, { CPN_LCH_L, CPN_LCH_C, CPN_LCH_H } },

  { N_("YCbCr470"),  "Y'CbCr", TRUE, 3, FALSE, { CPN_YCBCR_Y, CPN_YCBCR_CB, CPN_YCBCR_CR} },
  { N_("YCbCr470f"), "Y'CbCr", TRUE, 3, TRUE,  { CPN_YCBCR_Y, CPN_YCBCR_CB, CPN_YCBCR_CR} },

  { N_("YCbCr709"),  "Y'CbCr709", TRUE, 3, FALSE, { CPN_YCBCR709_Y, CPN_YCBCR709_CB, CPN_YCBCR709_CR} },
  { N_("YCbCr709f"), "Y'CbCr709", TRUE, 3, TRUE,  { CPN_YCBCR709_Y, CPN_YCBCR709_CB, CPN_YCBCR709_CR} }
};


static void
decompose_class_init (DecomposeClass *klass)
{
  GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);

  plug_in_class->query_procedures = decompose_query_procedures;
  plug_in_class->create_procedure = decompose_create_procedure;
  plug_in_class->set_i18n         = STD_SET_I18N;
}

static void
decompose_init (Decompose *decompose)
{
}

static GList *
decompose_query_procedures (GimpPlugIn *plug_in)
{
  return g_list_append (NULL, g_strdup (PLUG_IN_PROC));
}

static GimpProcedure *
decompose_create_procedure (GimpPlugIn  *plug_in,
                           const gchar *name)
{
  GimpProcedure *procedure = NULL;

  if (! strcmp (name, PLUG_IN_PROC))
    {
      GString *type_desc;
      gint     i;

      type_desc = g_string_new (_("What to decompose: "));
      g_string_append_c (type_desc, '"');
      g_string_append (type_desc, extract[0].type);
      g_string_append_c (type_desc, '"');

      for (i = 1; i < G_N_ELEMENTS (extract); i++)
        {
          g_string_append (type_desc, ", ");
          g_string_append_c (type_desc, '"');
          g_string_append (type_desc, extract[i].type);
          g_string_append_c (type_desc, '"');
        }

      procedure = gimp_image_procedure_new (plug_in, name,
                                            GIMP_PDB_PROC_TYPE_PLUGIN,
                                            decompose_run, NULL, NULL);

      gimp_procedure_set_image_types (procedure, "RGB*");
      gimp_procedure_set_sensitivity_mask (procedure,
                                           GIMP_PROCEDURE_SENSITIVE_DRAWABLE);

      gimp_procedure_set_menu_label (procedure, _("_Decompose..."));
      gimp_procedure_add_menu_path (procedure, "<Image>/Colors/Components");

      gimp_procedure_set_documentation (procedure,
                                        _("Decompose an image into separate "
                                          "colorspace components"),
                                        "This function creates new gray images "
                                        "with different channel information "
                                        "in each of them",
                                        name);
      gimp_procedure_set_attribution (procedure,
                                      "Peter Kirchgessner",
                                      "Peter Kirchgessner, Clarence Risher",
                                      "1997");

      gimp_procedure_add_choice_argument (procedure, "decompose-type",
                                          _("Color _model"),
                                          _("The model to decompose to"),
                                          gimp_choice_new_with_values ("rgb",        0, _("RGB"),                NULL,
                                                                       "rgba",       1, _("RGBA"),               NULL,
                                                                       "alpha",      2, _("Alpha"),              NULL,
                                                                       "hsv",        3, _("HSV"),                NULL,
                                                                       "hsl",        4, _("HSL"),                NULL,
                                                                       "cmyk",       5, _("CMYK"),               NULL,
                                                                       "lab",        6, _("LAB"),                NULL,
                                                                       "lch",        7, _("LCH"),                NULL,
                                                                       "ycbcr470",   8, _("YCbCr ITU R470"),     NULL,
                                                                       "ycbcr709",   9, _("YCbCr ITU R709"),     NULL,
                                                                       "ycbcr470f", 10, _("YCbCr ITU R470 256"), NULL,
                                                                       "ycbcr709f", 11, _("YCbCr ITU R709 256"), NULL,
                                                                       NULL),
                                          "rgb",
                                          G_PARAM_READWRITE);

      gimp_procedure_add_boolean_argument (procedure, "layers-mode",
                                           _("_Decompose to layers"),
                                           _("Create channels as layers in a single image"),
                                           TRUE,
                                           G_PARAM_READWRITE);

      gimp_procedure_add_boolean_argument (procedure, "use-registration",
                                           _("_Foreground as registration color"),
                                           _("When enabled, pixels in the foreground color "
                                             "will appear black in all output images. This "
                                             "can be used for things like crop marks that "
                                             "have to show up on all channels."),
                                           FALSE,
                                           G_PARAM_READWRITE);

      gimp_procedure_add_image_return_value (procedure, "new-image-1",
                                             "New image 1",
                                             "Output gray image 1",
                                             FALSE,
                                             G_PARAM_READWRITE);

      gimp_procedure_add_image_return_value (procedure, "new-image-2",
                                             "New image 2",
                                             "Output gray image 2 (N/A for single channel extract)",
                                             TRUE,
                                             G_PARAM_READWRITE);

      gimp_procedure_add_image_return_value (procedure, "new-image-3",
                                             "New image 3",
                                             "Output gray image 3 (N/A for single channel extract)",
                                             TRUE,
                                             G_PARAM_READWRITE);

      gimp_procedure_add_image_return_value (procedure, "new-image-4",
                                             "New image 4",
                                             "Output gray image 4 (N/A for single channel extract)",
                                             TRUE,
                                             G_PARAM_READWRITE);

      g_string_free (type_desc, TRUE);
    }

  return procedure;
}

static GimpValueArray *
decompose_run (GimpProcedure        *procedure,
               GimpRunMode           run_mode,
               GimpImage            *image,
               GimpDrawable        **drawables,
               GimpProcedureConfig  *config,
               gpointer              run_data)
{
  GimpValueArray *return_vals;
  GimpDrawable   *drawable;
  gint            num_images;
  GimpImage      *image_extract[MAX_EXTRACT_IMAGES];
  GimpLayer      *layer_extract[MAX_EXTRACT_IMAGES];
  gint            num_layers;
  GString        *data;
  gchar          *decompose_type;
  gint            j;

  gegl_init (NULL, NULL);

  if (gimp_core_object_array_get_length ((GObject **) drawables) != 1)
    {
      GError *error = NULL;

      g_set_error (&error, GIMP_PLUG_IN_ERROR, 0,
                   _("Procedure '%s' only works with one drawable."),
                   PLUG_IN_PROC);

      return gimp_procedure_new_return_values (procedure,
                                               GIMP_PDB_CALLING_ERROR,
                                               error);
    }
  else
    {
      drawable = drawables[0];
    }

  if (run_mode == GIMP_RUN_INTERACTIVE && ! decompose_dialog (procedure, G_OBJECT (config)))
    return gimp_procedure_new_return_values (procedure, GIMP_PDB_CANCEL, NULL);

  gimp_progress_init (_("Decomposing"));

  num_images = decompose (image,
                          drawable,
                          G_OBJECT (config),
                          image_extract,
                          &num_layers,
                          layer_extract);

  if (num_images <= 0)
    return gimp_procedure_new_return_values (procedure, GIMP_PDB_EXECUTION_ERROR, NULL);

  /* create decompose-data parasite */
  data = g_string_new ("");

  g_object_get (config,
                "decompose-type", &decompose_type,
                NULL);

  g_string_printf (data, "source=%d type=%s ",
                   gimp_item_get_id (GIMP_ITEM (drawable)),
                   decompose_type);

  g_free (decompose_type);

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

  return_vals = gimp_procedure_new_return_values (procedure,
                                                  GIMP_PDB_SUCCESS,
                                                  NULL);

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

      GIMP_VALUES_SET_IMAGE (return_vals, j + 1, image_extract[j]);

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

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

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

  gimp_progress_end ();

  return return_vals;
}


/* Decompose an image. It returns the number of new (gray) images.
 * The image IDs for the new images are returned in image_dst.
 * On failure, -1 is returned.
 */

static gint
decompose (GimpImage    *image,
           GimpDrawable *drawable,
           GObject      *config,
           GimpImage   **image_dst,
           gint         *nlayers,
           GimpLayer   **layer_dst)
{
  const gchar   *layername;
  gint           j, extract_idx;
  gint           height, width;
  gint           num_layers;
  GeglBuffer    *src_buffer;
  GeglBuffer    *dst_buffer[MAX_EXTRACT_IMAGES];
  GimpPrecision  precision;
  gboolean       requirements      = FALSE;
  gboolean       decomp_has_alpha = FALSE;
  gchar         *config_extract_type;
  gboolean       config_as_layers;
  gboolean       config_use_registration;

  g_object_get (config,
                "decompose-type",   &config_extract_type,
                "layers-mode",      &config_as_layers,
                "use-registration", &config_use_registration,
                NULL);

  extract_idx = -1;   /* Search extract type */
  for (j = 0; j < G_N_ELEMENTS (extract); j++)
    {
      if (g_ascii_strcasecmp (config_extract_type, extract[j].type) == 0)
        {
          extract_idx = j;
          break;
        }
    }
  if (extract_idx < 0)
    return -1;

  num_layers = extract[extract_idx].num_images;

  /* Sanity checks */
  src_buffer = gimp_drawable_get_buffer (drawable);
  precision  = gimp_image_get_precision (image);

  for (j = 0; j < num_layers; j++)
    {
      /* FIXME: Not 100% reliable */
      decomp_has_alpha |= ! g_strcmp0 ("alpha",
                                       extract[extract_idx].component[j].babl_name);
      decomp_has_alpha |= ! g_strcmp0 ("A",
                                       extract[extract_idx].component[j].babl_name);
    }

  requirements |= (gimp_drawable_is_rgb (drawable));
  requirements |= (gimp_drawable_is_indexed (drawable));
  requirements |= (gimp_drawable_is_gray (drawable)
                   && gimp_drawable_has_alpha (drawable)
                   && (num_layers <= 2)
                   && decomp_has_alpha);
  requirements &= (!decomp_has_alpha || gimp_drawable_has_alpha (drawable));

  if (!requirements)
    {
      g_message (_("Image not suitable for this decomposition"));
      return -1;
    }

  width  = gegl_buffer_get_width  (src_buffer);
  height = gegl_buffer_get_height (src_buffer);

  /* Create all new gray images */
  for (j = 0; j < num_layers; j++)
    {
      gchar   *filename;
      gdouble  xres, yres;

      filename = generate_filename (image, config, extract_idx, j);
      gimp_image_get_resolution (image, &xres, &yres);

      if (config_as_layers)
        {
          layername = gettext (extract[extract_idx].component[j].channel_name);

          if (j == 0)
            image_dst[j] = create_new_image (g_file_new_for_path (filename),
                                             layername,
                                             width, height, GIMP_GRAY, precision,
                                             xres, yres,
                                             layer_dst + j);
          else
            layer_dst[j] = create_new_layer (image_dst[0], j, layername,
                                             width, height, GIMP_GRAY);
        }
      else
        {
          image_dst[j] = create_new_image (g_file_new_for_path (filename),
                                           NULL,
                                           width, height, GIMP_GRAY, precision,
                                           xres, yres,
                                           layer_dst + j);
        }

      g_free (filename);

      dst_buffer[j] = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer_dst[j]));
    }

  copy_n_components (src_buffer, dst_buffer,
                     extract[extract_idx]);

  if (config_use_registration)
    transfer_registration_color (src_buffer, dst_buffer, num_layers);

  gimp_progress_update (1.0);

  g_object_unref (src_buffer);

  for (j = 0; j < num_layers; j++)
    {
      g_object_unref (dst_buffer[j]);
    }

  *nlayers = num_layers;

  return (config_as_layers ? 1 : num_layers);
}


/* Create an image. Returns layer and image */
static GimpImage *
create_new_image (GFile             *file,
                  const gchar       *layername,
                  guint              width,
                  guint              height,
                  GimpImageBaseType  type,
                  GimpPrecision      precision,
                  gdouble            xres,
                  gdouble            yres,
                  GimpLayer        **layer)
{
  GimpImage *image;

  image = gimp_image_new_with_precision (width, height, type, precision);

  gimp_image_undo_disable (image);
  gimp_image_set_file (image, file);
  gimp_image_set_resolution (image, xres, yres);

  *layer = create_new_layer (image, 0,
                             layername, width, height, type);

  return image;
}


static GimpLayer *
create_new_layer (GimpImage         *image,
                  gint               position,
                  const gchar       *layername,
                  guint              width,
                  guint              height,
                  GimpImageBaseType  type)
{
  GimpLayer     *layer;
  GimpImageType  gdtype = GIMP_RGB_IMAGE;

  switch (type)
    {
    case GIMP_RGB:
      gdtype = GIMP_RGB_IMAGE;
      break;
    case GIMP_GRAY:
      gdtype = GIMP_GRAY_IMAGE;
      break;
    case GIMP_INDEXED:
      gdtype = GIMP_INDEXED_IMAGE;
      break;
    }

  if (! layername)
    layername = _("Background");

  layer = gimp_layer_new (image, layername, width, height,
                          gdtype,
                          100,
                          gimp_image_get_default_new_layer_mode (image));
  gimp_image_insert_layer (image, layer, NULL, position);

  return layer;
}

/* Registration Color function */

static void
transfer_registration_color (GeglBuffer  *src,
                             GeglBuffer **dst,
                             gint         count)
{
  GeglColor          *color;
  GeglBufferIterator *gi;
  const Babl         *src_format;
  const Babl         *dst_format;
  gint                src_bpp;
  gint                dst_bpp;
  gint                i;
  gdouble             white;

  color = gimp_context_get_foreground ();
  white = 1.0;

  src_format = gegl_buffer_get_format (src);
  src_bpp = babl_format_get_bytes_per_pixel (src_format);

  dst_format = gegl_buffer_get_format (dst[0]);
  dst_bpp = babl_format_get_bytes_per_pixel (dst_format);

  gi = gegl_buffer_iterator_new (src, NULL, 0, NULL,
                                 GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 10);

  for (i = 0; i < count; i++)
    {
      gegl_buffer_iterator_add (gi, dst[i], NULL, 0, NULL,
                                GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE);
    }

  while (gegl_buffer_iterator_next (gi))
    {
      gpointer src_data;
      gpointer dst_data[MAX_EXTRACT_IMAGES];
      gint     j, k;

      src_data = gi->items[0].data;
      for (j = 0; j < count; j++)
        dst_data[j] = gi->items[j + 1].data;

      for (k = 0; k < gi->length; k++)
        {
          GeglColor *test;
          gulong     pos = k * src_bpp;

          test = gegl_color_new (NULL);
          gegl_color_set_pixel (test, src_format, ((guchar *)src_data) + pos);

          if (gimp_color_is_perceptually_identical (test, color))
            {
              for (j = 0; j < count; j++)
                {
                  gpointer data = dst_data[j];

                  babl_process (babl_fish (babl_format ("Y double"), dst_format),
                                &white, (guchar *)data + (k * dst_bpp), 1);
                }
            }

          g_object_unref (test);
        }
    }

  g_object_unref (color);
}

static void
cpn_affine_transform_clamp (GeglBuffer *buffer,
                            gdouble     min,
                            gdouble     max,
                            gboolean    clamp)
{
  GeglBufferIterator *gi;
  gdouble             scale  = 1.0 / (max - min);
  gdouble             offset = - min;

  /* We want to scale values linearly, regardless of the format of the buffer */
  gegl_buffer_set_format (buffer, babl_format ("Y double"));

  gi = gegl_buffer_iterator_new (buffer, NULL, 0, NULL,
                                 GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE, 1);

  while (gegl_buffer_iterator_next (gi))
    {
      guint k;
      double *data;

      data = (double*) gi->items[0].data;

      if (clamp)
        {
          for (k = 0; k < gi->length; k++)
            {
              data[k] = CLAMP ((data[k] + offset) * scale, 0.0, 1.0);
            }
        }
      else
        {
          for (k = 0; k < gi->length; k++)
            {
              data[k] = (data[k] + offset) * scale;
            }
        }
    }
}

static void
copy_n_components (GeglBuffer  *src,
                   GeglBuffer **dst,
                   Extract      ext)
{
  gint i;

  for (i = 0; i < ext.num_images; i++)
    {
      gimp_progress_update ((gdouble) i / (gdouble) ext.num_images);

      copy_one_component (src, dst[i], ext.model, ext.component[i], ext.clamp);
    }
}

static void
copy_one_component (GeglBuffer      *src,
                    GeglBuffer      *dst,
                    const gchar     *model,
                    const Component  component,
                    gboolean         clamp)
{
  const Babl          *component_format;
  const Babl          *dst_format;
  GeglBuffer          *temp;
  const GeglRectangle *extent;

  /* We are working in linear double precision */
  component_format = babl_format_new (babl_model (model),
                                      babl_type ("double"),
                                      babl_component (component.babl_name),
                                      NULL);

  /* We need to enforce linearity here
   * If the output is "Y'", the output of temp is already ok
   * If the output is "Y" , it will enforce gamma-decoding.
   * A bit tricky and suboptimal...
   */

  if (component.perceptual_channel)
    dst_format = babl_format ("Y' double");
  else
    dst_format = babl_format ("Y double");

  extent = gegl_buffer_get_extent (src);
  temp = gegl_buffer_new (extent, dst_format);

  /* we want to copy the component as is */
  gegl_buffer_set_format (temp, component_format);
  gegl_buffer_copy (src, NULL, GEGL_ABYSS_NONE, temp, NULL);

  if (component.range_min != 0.0 ||
      component.range_max != 1.0 ||
      clamp)
    {
      cpn_affine_transform_clamp (temp,
                                  component.range_min, component.range_max,
                                  clamp);
    }

  /* This is our new "Y(') double" component buffer */
  gegl_buffer_set_format (temp, NULL);

  /* Now we let babl convert it back to the format that dst needs */
  gegl_buffer_copy (temp, NULL, GEGL_ABYSS_NONE, dst, NULL);

  g_object_unref (temp);
}

static gboolean
decompose_dialog (GimpProcedure *procedure,
                  GObject       *config)
{
  GtkWidget    *dialog;
  GtkWidget    *vbox;
  gboolean      run;

  gimp_ui_init (PLUG_IN_BINARY);

  dialog = gimp_procedure_dialog_new (procedure,
                                      GIMP_PROCEDURE_CONFIG (config),
                                      _("Decompose"));

  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);

  gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
                                   "extract-label", _("Extract Channels"),
                                   FALSE, FALSE);
  gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
                                    "extract-frame",
                                    "extract-label", FALSE,
                                    "decompose-type");

  vbox = gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog),
                                         "decompose-vbox",
                                         "extract-frame", "layers-mode",
                                         "use-registration",
                                         NULL);
  gtk_box_set_spacing (GTK_BOX (vbox), 12);
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);

  gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog),
                              "decompose-vbox", NULL);

  gtk_widget_set_visible (dialog, TRUE);

  run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog));

  gtk_widget_destroy (dialog);

  return run;
}

/* Build a filename like <imagename>-<channel>.<extension> */
gchar *
generate_filename (GimpImage *image,
                   GObject   *config,
                   guint      colorspace,
                   guint      channel)
{
  /* Build a filename like <imagename>-<channel>.<extension> */
  GFile    *file;
  gchar    *fname = NULL;
  gchar    *filename;
  gchar    *extension;
  gboolean  config_as_layers;

  g_object_get (config,
                "layers-mode", &config_as_layers,
                NULL);

  file  = gimp_image_get_file (image);
  if (file)
    fname = g_file_get_path (file);

  if (fname)
    {
      extension = fname + strlen (fname) - 1;

      while (extension >= fname)
        {
          if (*extension == '.')
            break;
          extension--;
        }

      if (extension >= fname)
        {
          *(extension++) = '\0';
        }

      if (config_as_layers)
        filename = g_strdup_printf ("%s-%s.xcf", fname,
                                    gettext (extract[colorspace].type));
      else
        filename = g_strdup_printf ("%s-%s.xcf", fname,
                                    gettext (extract[colorspace].component[channel].channel_name));
    }
  else
    {
      if (config_as_layers)
        filename = g_strdup_printf ("%s.xcf",
                                    gettext (extract[colorspace].type));
      else
        filename = g_strdup_printf ("%s.xcf",
                                    gettext (extract[colorspace].component[channel].channel_name));
    }

  g_free (fname);

  return filename;
}

Messung
CHZG
839610093

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104851
#Domains=417125