plug-ins: port decompose

This commit is contained in:
Michael Natterer 2019-08-29 20:01:30 +02:00
parent c765fb2b6a
commit 6e43d793ae
3 changed files with 317 additions and 285 deletions

View File

@ -462,8 +462,6 @@ curve_bend_LDADD = \
$(INTLLIBS) \
$(curve_bend_RC)
decompose_CPPFLAGS = $(AM_CPPFLAGS) -DGIMP_DEPRECATED_REPLACE_NEW_API
decompose_SOURCES = \
decompose.c

View File

@ -34,10 +34,9 @@
#include "libgimp/stdplugins-intl.h"
#define PLUG_IN_PROC "plug-in-decompose"
#define PLUG_IN_PROC_REG "plug-in-decompose-registered"
#define PLUG_IN_BINARY "decompose"
#define PLUG_IN_ROLE "gimp-decompose"
#define PLUG_IN_PROC "plug-in-decompose"
#define PLUG_IN_BINARY "decompose"
#define PLUG_IN_ROLE "gimp-decompose"
/* Description of a component */
@ -80,54 +79,81 @@ typedef struct
} DecomposeVals;
/* Declare local functions
*/
static void query (void);
static void run (const gchar *name,
gint nparams,
const GimpParam *param,
gint *nreturn_vals,
GimpParam **return_vals);
static gint32 decompose (gint32 image_id,
gint32 drawable_ID,
const gchar *extract_type,
gint32 *image_ID_dst,
gint32 *num_layers,
gint32 *layer_ID_dst);
static gint32 create_new_image (const gchar *filename,
const gchar *layername,
guint width,
guint height,
GimpImageBaseType type,
GimpPrecision precision,
gdouble xres,
gdouble yres,
gint32 *layer_ID);
static gint32 create_new_layer (gint32 image_ID,
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 (void);
static gchar * generate_filename (guint32 image_ID,
guint colorspace,
guint channel);
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 *drawable,
const GimpValueArray *args,
gpointer run_data);
static gint decompose (GimpImage *image,
GimpDrawable *drawable,
const gchar *extract_type,
GimpImage **image_dst,
gint32 *num_layers,
GimpLayer **layer_dst);
static GimpImage * create_new_image (const gchar *filename,
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 (void);
static gchar * generate_filename (GimpImage *image,
guint colorspace,
guint channel);
G_DEFINE_TYPE (Decompose, decompose, GIMP_TYPE_PLUG_IN)
GIMP_MAIN (DECOMPOSE_TYPE)
#define CPN_RGBA_R { "R", N_("red"), 0.0, 1.0, FALSE }
@ -210,14 +236,6 @@ static const Extract extract[] =
{ N_("YCbCr_ITU_R709_256"), "Y'CbCr709", TRUE, 3, TRUE, { CPN_YCBCR709_Y, CPN_YCBCR709_CB, CPN_YCBCR709_CR} }
};
const GimpPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static DecomposeVals decovals =
{
"rgb", /* Decompose type */
@ -226,149 +244,161 @@ static DecomposeVals decovals =
};
MAIN ()
static void
query (void)
decompose_class_init (DecomposeClass *klass)
{
static GimpParamDef args[] =
{
{ GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
{ GIMP_PDB_IMAGE, "image", "Input image (unused)" },
{ GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
{ GIMP_PDB_STRING, "decompose-type", NULL },
{ GIMP_PDB_INT32, "layers-mode", "Create channels as layers in a single image" }
};
static const GimpParamDef return_vals[] =
{
{ GIMP_PDB_IMAGE, "new-image", "Output gray image" },
{ GIMP_PDB_IMAGE, "new-image", "Output gray image (N/A for single channel extract)" },
{ GIMP_PDB_IMAGE, "new-image", "Output gray image (N/A for single channel extract)" },
{ GIMP_PDB_IMAGE, "new-image", "Output gray image (N/A for single channel extract)" }
};
GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
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, '"');
}
args[3].description = type_desc->str;
gimp_install_procedure (PLUG_IN_PROC,
N_("Decompose an image into separate colorspace components"),
"This function creates new gray images with "
"different channel information in each of them",
"Peter Kirchgessner",
"Peter Kirchgessner",
"1997",
N_("_Decompose..."),
"RGB*",
GIMP_PLUGIN,
G_N_ELEMENTS (args),
G_N_ELEMENTS (return_vals),
args, return_vals);
gimp_install_procedure (PLUG_IN_PROC_REG,
N_("Decompose an image into separate colorspace components"),
"This function creates new gray images with "
"different channel information in each of them. "
"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.",
"Peter Kirchgessner",
"Peter Kirchgessner, Clarence Risher",
"1997",
N_("_Decompose..."),
"RGB*",
GIMP_PLUGIN,
G_N_ELEMENTS (args),
G_N_ELEMENTS (return_vals),
args, return_vals);
gimp_plugin_menu_register (PLUG_IN_PROC_REG, "<Image>/Colors/Components");
g_string_free (type_desc, TRUE);
plug_in_class->query_procedures = decompose_query_procedures;
plug_in_class->create_procedure = decompose_create_procedure;
}
static void
run (const gchar *name,
gint nparams,
const GimpParam *param,
gint *nreturn_vals,
GimpParam **return_vals)
decompose_init (Decompose *decompose)
{
static GimpParam values[MAX_EXTRACT_IMAGES + 1];
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
GimpRunMode run_mode;
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;
}
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_PLUGIN,
decompose_run, NULL, NULL);
gimp_procedure_set_image_types (procedure, "RGB*");
gimp_procedure_set_menu_label (procedure, N_("_Decompose..."));
gimp_procedure_add_menu_path (procedure, "<Image>/Colors/Components");
gimp_procedure_set_documentation (procedure,
N_("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_PROC_ARG_STRING (procedure, "decompose-type",
"Decompose type",
type_desc->str,
NULL,
G_PARAM_READWRITE);
GIMP_PROC_ARG_BOOLEAN (procedure, "layers-mode",
"Layers mode",
"Create channels as layers in a single image",
TRUE,
G_PARAM_READWRITE);
GIMP_PROC_ARG_BOOLEAN (procedure, "use-registration",
"Use registration",
"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_PROC_VAL_IMAGE (procedure, "new-image-1",
"New image 1",
"Output gray image 1",
FALSE,
G_PARAM_READWRITE);
GIMP_PROC_VAL_IMAGE (procedure, "new-image-2",
"New image 2",
"Output gray image 2 (N/A for single channel extract)",
TRUE,
G_PARAM_READWRITE);
GIMP_PROC_VAL_IMAGE (procedure, "new-image-3",
"New image 3",
"Output gray image 3 (N/A for single channel extract)",
TRUE,
G_PARAM_READWRITE);
GIMP_PROC_VAL_IMAGE (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 *drawable,
const GimpValueArray *args,
gpointer run_data)
{
GimpValueArray *return_vals;
gint num_images;
GimpImage *image_extract[MAX_EXTRACT_IMAGES];
GimpLayer *layer_extract[MAX_EXTRACT_IMAGES];
gint j;
gint num_layers;
GString *data;
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;
return gimp_procedure_new_return_values (procedure,
GIMP_PDB_CANCEL,
NULL);
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
{
g_strlcpy (decovals.extract_type, param[3].data.d_string,
sizeof (decovals.extract_type));
g_strlcpy (decovals.extract_type,
GIMP_VALUES_GET_STRING (args, 0),
sizeof (decovals.extract_type));
decovals.as_layers = nparams > 4 ? param[4].data.d_int32 : FALSE;
decovals.use_registration = (strcmp (name, PLUG_IN_PROC_REG) == 0);
}
decovals.as_layers = GIMP_VALUES_GET_BOOLEAN (args, 1);
decovals.use_registration = GIMP_VALUES_GET_BOOLEAN (args, 2);
break;
case GIMP_RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data (PLUG_IN_PROC, &decovals);
break;
@ -376,76 +406,78 @@ run (const gchar *name,
break;
}
if (status == GIMP_PDB_SUCCESS)
gimp_progress_init (_("Decomposing"));
num_images = decompose (image,
drawable,
decovals.extract_type,
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_string_printf (data, "source=%d type=%s ",
gimp_item_get_id (GIMP_ITEM (drawable)),
decovals.extract_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++)
{
gimp_progress_init (_("Decomposing"));
GimpParasite *parasite;
num_images = decompose (image_ID, layer,
decovals.extract_type,
image_ID_extract,
&num_layers,
layer_ID_extract);
GIMP_VALUES_SET_IMAGE (return_vals, j + 1, image_extract[j]);
if (num_images <= 0)
{
status = GIMP_PDB_EXECUTION_ERROR;
}
else
{
/* create decompose-data parasite */
GString *data = g_string_new ("");
gimp_image_undo_enable (image_extract[j]);
gimp_image_clean_all (image_extract[j]);
g_string_printf (data, "source=%d type=%s ",
layer, decovals.extract_type);
parasite = gimp_parasite_new ("decompose-data",
0, data->len + 1, data->str);
gimp_image_attach_parasite (image_extract[j], parasite);
gimp_parasite_free (parasite);
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 (DecomposeVals));
}
gimp_progress_end ();
if (run_mode != GIMP_RUN_NONINTERACTIVE)
gimp_display_new (image_extract[j]);
}
values[0].data.d_status = status;
if (run_mode == GIMP_RUN_INTERACTIVE)
gimp_set_data (PLUG_IN_PROC, &decovals, sizeof (DecomposeVals));
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_ID_dst.
* The image IDs for the new images are returned in image_dst.
* On failure, -1 is returned.
*/
static gint32
decompose (gint32 image_ID,
gint32 drawable_ID,
const gchar *extract_type,
gint32 *image_ID_dst,
gint32 *nlayers,
gint32 *layer_ID_dst)
static gint
decompose (GimpImage *image,
GimpDrawable *drawable,
const gchar *extract_type,
GimpImage **image_dst,
gint *nlayers,
GimpLayer **layer_dst)
{
const gchar *layername;
gint j, extract_idx;
gint height, width, num_layers;
gint height, width;
gint num_layers;
GeglBuffer *src_buffer;
GeglBuffer *dst_buffer[MAX_EXTRACT_IMAGES];
GimpPrecision precision;
@ -467,23 +499,25 @@ decompose (gint32 image_ID,
num_layers = extract[extract_idx].num_images;
/* Sanity checks */
src_buffer = gimp_drawable_get_buffer (drawable_ID);
precision = gimp_image_get_precision (image_ID);
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);
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_ID));
requirements |= (gimp_drawable_is_indexed (drawable_ID));
requirements |= (gimp_drawable_is_gray (drawable_ID)
&& gimp_drawable_has_alpha (drawable_ID)
&& (num_layers <= 2)
&& decomp_has_alpha);
requirements &= (!decomp_has_alpha || gimp_drawable_has_alpha (drawable_ID));
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)
{
@ -500,33 +534,33 @@ decompose (gint32 image_ID,
gchar *filename;
gdouble xres, yres;
filename = generate_filename (image_ID, extract_idx, j);
gimp_image_get_resolution (image_ID, &xres, &yres);
filename = generate_filename (image, extract_idx, j);
gimp_image_get_resolution (image, &xres, &yres);
if (decovals.as_layers)
{
layername = gettext (extract[extract_idx].component[j].channel_name);
if (j == 0)
image_ID_dst[j] = create_new_image (filename, layername,
width, height, GIMP_GRAY, precision,
xres, yres,
layer_ID_dst + j);
image_dst[j] = create_new_image (filename, layername,
width, height, GIMP_GRAY, precision,
xres, yres,
layer_dst + j);
else
layer_ID_dst[j] = create_new_layer (image_ID_dst[0], j, layername,
width, height, GIMP_GRAY);
layer_dst[j] = create_new_layer (image_dst[0], j, layername,
width, height, GIMP_GRAY);
}
else
{
image_ID_dst[j] = create_new_image (filename, NULL,
width, height, GIMP_GRAY, precision,
xres, yres,
layer_ID_dst + j);
image_dst[j] = create_new_image (filename, NULL,
width, height, GIMP_GRAY, precision,
xres, yres,
layer_dst + j);
}
g_free (filename);
dst_buffer[j] = gimp_drawable_get_buffer (layer_ID_dst[j]);
dst_buffer[j] = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer_dst[j]));
}
copy_n_components (src_buffer, dst_buffer,
@ -550,8 +584,8 @@ decompose (gint32 image_ID,
}
/* Create an image. Returns layer_ID and image_ID */
static gint32
/* Create an image. Returns layer and image */
static GimpImage *
create_new_image (const gchar *filename,
const gchar *layername,
guint width,
@ -560,33 +594,33 @@ create_new_image (const gchar *filename,
GimpPrecision precision,
gdouble xres,
gdouble yres,
gint32 *layer_ID)
GimpLayer **layer)
{
gint32 image_ID;
GimpImage *image;
image_ID = gimp_image_new_with_precision (width, height, type, precision);
image = gimp_image_new_with_precision (width, height, type, precision);
gimp_image_undo_disable (image_ID);
gimp_image_set_filename (image_ID, filename);
gimp_image_set_resolution (image_ID, xres, yres);
gimp_image_undo_disable (image);
gimp_image_set_filename (image, filename);
gimp_image_set_resolution (image, xres, yres);
*layer_ID = create_new_layer (image_ID, 0,
layername, width, height, type);
*layer = create_new_layer (image, 0,
layername, width, height, type);
return image_ID;
return image;
}
static gint32
create_new_layer (gint32 image_ID,
static GimpLayer *
create_new_layer (GimpImage *image,
gint position,
const gchar *layername,
guint width,
guint height,
GimpImageBaseType type)
{
gint32 layer_ID;
GimpImageType gdtype = GIMP_RGB_IMAGE;
GimpLayer *layer;
GimpImageType gdtype = GIMP_RGB_IMAGE;
switch (type)
{
@ -604,13 +638,13 @@ create_new_layer (gint32 image_ID,
if (! layername)
layername = _("Background");
layer_ID = gimp_layer_new (image_ID, layername, width, height,
gdtype,
100,
gimp_image_get_default_new_layer_mode (image_ID));
gimp_image_insert_layer (image_ID, layer_ID, -1, position);
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_ID;
return layer;
}
/* Registration Color function */
@ -924,16 +958,16 @@ decompose_dialog (void)
/* Build a filename like <imagename>-<channel>.<extension> */
gchar *
generate_filename (guint32 image_ID,
guint colorspace,
guint channel)
generate_filename (GimpImage *image,
guint colorspace,
guint channel)
{
/* Build a filename like <imagename>-<channel>.<extension> */
gchar *fname;
gchar *filename;
gchar *extension;
fname = gimp_image_get_filename (image_ID);
fname = gimp_image_get_filename (image);
if (fname)
{

View File

@ -12,7 +12,7 @@
'contrast-retinex' => { ui => 1, gegl => 1 },
'crop-zealous' => { gegl => 1, old_api => 1 },
'curve-bend' => { ui => 1, gegl => 1, old_api => 1 },
'decompose' => { ui => 1, gegl => 1, old_api => 1 },
'decompose' => { ui => 1, gegl => 1 },
'depth-merge' => { ui => 1, gegl => 1, old_api => 1 },
'despeckle' => { ui => 1, gegl => 1 },
'destripe' => { ui => 1, gegl => 1 },