From 7e795349c10d20f654e8f6195e4172fc5d2a0298 Mon Sep 17 00:00:00 2001 From: Sven Neumann Date: Thu, 11 Sep 2003 15:39:07 +0000 Subject: [PATCH] plug-ins/common/compose.c merged in enhancements done by Alexey Dyachenko: 2003-09-11 Sven Neumann * plug-ins/common/compose.c * plug-ins/common/decompose.c: merged in enhancements done by Alexey Dyachenko: support for LAB colorspace and an option to decompose into layers instead of multiple images. --- ChangeLog | 7 + plug-ins/common/compose.c | 199 ++++++++----- plug-ins/common/decompose.c | 547 +++++++++++++++++++++++------------- 3 files changed, 488 insertions(+), 265 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4fead88cfa..087b074df4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2003-09-11 Sven Neumann + + * plug-ins/common/compose.c + * plug-ins/common/decompose.c: merged in enhancements done by + Alexey Dyachenko: support for LAB colorspace and an option to + decompose into layers instead of multiple images. + 2003-09-11 Simon Budig * vectors/gimpbezierstroke.[ch]: Implemented diff --git a/plug-ins/common/compose.c b/plug-ins/common/compose.c index c78f09b902..e41fbb8130 100644 --- a/plug-ins/common/compose.c +++ b/plug-ins/common/compose.c @@ -23,38 +23,25 @@ * This plug-in composes RGB-images from several types of channels */ -/* Event history: - * V 1.00, PK, 29-Jul-97, Creation - * V 1.01, nn, 20-Dec-97, Add default case in switch for hsv_to_rgb () - * V 1.02, PK, 18-Sep-98, Change variable names in Parameter definition. - * Otherwise script-fu merges parameters (reported by Patrick Valsecchi) - * Check images for same width/height (interactive mode) - * Use drawables in interactive menu - * Use g_message in interactive mode - * Check sensitivity of menues (thanks to Kevin Turner, - * kevint@poboxes.com) - * V1.03, PK, 17-Mar-99, Update for GIMP 1.1.3 - * Allow image ID 0 - * Prepare for localization +/* Lab colorspace support originally written by Alexey Dyachenko, + * merged into the officical plug-in by Sven Neumann. */ -static char ident[] = "@(#) GIMP Compose plug-in v1.03 17-Mar-99"; -#ifdef HAVE_CONFIG_H #include "config.h" -#endif #include #include #include -#include #include #include #include +#include #include "libgimp/stdplugins-intl.h" + /* Declare local functions */ static void query (void); @@ -86,6 +73,8 @@ static void compose_cmy (guchar **src, gint *incr, gint numpix, guchar *dst); static void compose_cmyk (guchar **src, gint *incr, gint numpix, guchar *dst); +static void compose_lab (guchar **src, + gint *incr, gint numpix, guchar *dst); static void compose_ycbcr470 (guchar **src, gint *incr, gint numpix, guchar *dst); static void compose_ycbcr709 (guchar **src, @@ -110,6 +99,12 @@ static void compose_ok_callback (GtkWidget *widget, static void compose_type_toggle_update (GtkWidget *widget, gpointer data); + +/* LAB colorspace constants */ +const double Xn = 0.951; +const double Yn = 1.0; +const double Zn = 1.089; + /* Maximum number of images to compose */ #define MAX_COMPOSE_IMAGES 4 @@ -175,6 +170,13 @@ static COMPOSE_DSC compose_dsc[] = N_("Black:") }, { NULL, NULL, NULL, NULL }, "cmyk-compose", compose_cmyk }, + { N_("LAB"), 3, + { "L", + "A", + "B", + NULL }, + { NULL, NULL, NULL, NULL }, + "lab-compose", compose_lab }, { "YCbCr_ITU_R470", 3, { N_("Luma_y470:"), N_("Blueness_cb470:"), @@ -205,8 +207,6 @@ static COMPOSE_DSC compose_dsc[] = "ycbcr709F-compose", compose_ycbcr709f }, }; -#define MAX_COMPOSE_TYPES (G_N_ELEMENTS (compose_dsc)) - typedef struct { @@ -224,7 +224,7 @@ typedef struct GtkWidget *channel_menu[MAX_COMPOSE_IMAGES]; /* The menues */ gint32 select_ID[MAX_COMPOSE_IMAGES]; /* Image Ids selected by menu */ - gint compose_flag[MAX_COMPOSE_TYPES]; /* toggle data of compose type */ + gint compose_flag[G_N_ELEMENTS (compose_dsc)]; /* toggle data of compose type */ gboolean run; } ComposeInterface; @@ -452,30 +452,31 @@ compose (const gchar *compose_type, gint i, j; gint num_layers; gint32 layer_ID_dst, image_ID_dst; - guchar *src[MAX_COMPOSE_IMAGES], *dst = (guchar *)ident; + guchar *src[MAX_COMPOSE_IMAGES]; + guchar *dst; GimpImageType gdtype_dst; GimpDrawable *drawable_src[MAX_COMPOSE_IMAGES], *drawable_dst; GimpPixelRgn pixel_rgn_src[MAX_COMPOSE_IMAGES], pixel_rgn_dst; - + /* Search type of composing */ compose_idx = -1; - for (j = 0; j < MAX_COMPOSE_TYPES; j++) + for (j = 0; j < G_N_ELEMENTS (compose_dsc); j++) { if (g_ascii_strcasecmp (compose_type, compose_dsc[j].compose_type) == 0) compose_idx = j; } if (compose_idx < 0) return (-1); - + num_images = compose_dsc[compose_idx].num_images; tile_height = gimp_tile_height (); - + /* Check image sizes */ if (compose_by_drawable) { width = gimp_drawable_width (compose_ID[0]); height = gimp_drawable_height (compose_ID[0]); - + for (j = 1; j < num_images; j++) { if ((width != (gint)gimp_drawable_width (compose_ID[j])) || @@ -492,7 +493,7 @@ compose (const gchar *compose_type, { width = gimp_image_width (compose_ID[0]); height = gimp_image_height (compose_ID[0]); - + for (j = 1; j < num_images; j++) { if ((width != (gint)gimp_image_width (compose_ID[j])) || @@ -502,12 +503,12 @@ compose (const gchar *compose_type, return -1; } } - + /* Get first layer/drawable for all input images */ for (j = 0; j < num_images; j++) { gint32 *g32; - + /* Get first layer of image */ g32 = gimp_image_get_layers (compose_ID[j], &num_layers); if ((g32 == NULL) || (num_layers <= 0)) @@ -521,7 +522,7 @@ compose (const gchar *compose_type, g_free (g32); } } - + /* Get pixel region for all input drawables */ for (j = 0; j < num_images; j++) { @@ -529,19 +530,19 @@ compose (const gchar *compose_type, incr_src[j] = drawable_src[j]->bpp; if ((incr_src[j] != 1) && (incr_src[j] != 2)) { - g_message (_("Image is not a gray image (bpp=%d)"), + g_message (_("Image is not a gray image (bpp=%d)"), incr_src[j]); return -1; } - + /* Get pixel region */ gimp_pixel_rgn_init (&(pixel_rgn_src[j]), drawable_src[j], 0, 0, width, height, FALSE, FALSE); - + /* Get memory for retrieving information */ src[j] = g_new (guchar, tile_height * width * drawable_src[j]->bpp); } - + /* Create new image */ gdtype_dst = (compose_dsc[compose_idx].compose_fun == compose_rgba) ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE; @@ -586,7 +587,7 @@ compose (const gchar *compose_type, g_free (dst); gimp_drawable_flush (drawable_dst); gimp_drawable_detach (drawable_dst); - + return image_ID_dst; } @@ -639,7 +640,7 @@ compose_rgb (guchar **src, gint red_incr = incr_src[0]; gint green_incr = incr_src[1]; gint blue_incr = incr_src[2]; - + if ((red_incr == 1) && (green_incr == 1) && (blue_incr == 1)) { while (count-- > 0) @@ -677,7 +678,7 @@ compose_rgba (guchar **src, gint green_incr = incr_src[1]; gint blue_incr = incr_src[2]; gint alpha_incr = incr_src[3]; - + if ((red_incr == 1) && (green_incr == 1) && (blue_incr == 1) && (alpha_incr == 1)) { @@ -719,8 +720,8 @@ compose_hsv (guchar **src, while (count-- > 0) { - gimp_hsv_to_rgb4 (rgb_dst, (gdouble) *hue_src / 255.0, - (gdouble) *sat_src / 255.0, + gimp_hsv_to_rgb4 (rgb_dst, (gdouble) *hue_src / 255.0, + (gdouble) *sat_src / 255.0, (gdouble) *val_src / 255.0); rgb_dst += 3; hue_src += hue_incr; @@ -817,7 +818,79 @@ compose_cmyk (guchar **src, } } -/* these are here so the code is more readable and we can use +static void +compose_lab (guchar **src, + gint *incr_src, + gint numpix, + guchar *dst) +{ + register guchar *l_src = src[0]; + register guchar *a_src = src[1]; + register guchar *b_src = src[2]; + register guchar *rgb_dst = dst; + + register gint count = numpix; + gint l_incr = incr_src[0], a_incr = incr_src[1], b_incr = incr_src[2]; + + gdouble red, green, blue; + gdouble x, y, z; + gdouble l, a, b; + + gdouble p, yyn; + gdouble ha, hb, sqyyn; + + while (count-- > 0) + { + l = *l_src / 2.550; + a = ( *a_src - 128.0 ) / 1.27; + b = ( *b_src - 128.0 ) / 1.27; + + p = (l + 16.) / 116.; + yyn = p*p*p; + + if (yyn > 0.008856) + { + y = Yn * yyn; + ha = (p + a/500.); + x = Xn * ha*ha*ha; + hb = (p - b/200.); + z = Zn * hb*hb*hb; + } + else + { + y = Yn * l/903.3; + sqyyn = pow(l/903.3,1./3.); + ha = a/500./7.787 + sqyyn; + x = Xn * ha*ha*ha; + hb = sqyyn - b/200./7.787; + z = Zn * hb*hb*hb; + }; + + red = 3.063 * x - 1.393 * y - 0.476 * z; + green = -0.969 * x + 1.876 * y + 0.042 * z; + blue = 0.068 * x - 0.229 * y + 1.069 * z; + + red = ( red > 0 ) ? red : 0; + green = ( green > 0 ) ? green : 0; + blue = ( blue > 0 ) ? blue : 0; + + red = ( red < 1.0 ) ? red : 1.0; + green = ( green < 1.0 ) ? green : 1.0; + blue = ( blue < 1.0 ) ? blue : 1.0; + + rgb_dst[0] = (guchar) ( red * 255.999 ); + rgb_dst[1] = (guchar) ( green * 255.999 ); + rgb_dst[2] = (guchar) ( blue * 255.999 ); + + rgb_dst += 3; + l_src += l_incr; + a_src += a_incr; + b_src += b_incr; + } +} + + +/* these are here so the code is more readable and we can use the standart values instead of some scaled and rounded fixpoint values */ #define FIX(a) ((int)((a)*256.0*256.0 + 0.5)) #define FIXY(a) ((int)((a)*256.0*256.0*255.0/219.0 + 0.5)) @@ -842,17 +915,17 @@ compose_ycbcr470 (guchar **src, while (count-- > 0) { int r,g,b,y,cb,cr; - y = *y_src - 16; - cb= *cb_src - 128; + y = *y_src - 16; + cb= *cb_src - 128; cr= *cr_src - 128; y_src += y_incr; cb_src += cb_incr; cr_src += cr_incr; - + r = (FIXY(1.0)*y + FIXC(1.4022)*cr + FIX(0.5))>>16; g = (FIXY(1.0)*y - FIXC(0.3456)*cb - FIXC(0.7145)*cr + FIX(0.5))>>16; b = (FIXY(1.0)*y + FIXC(1.7710)*cb + FIX(0.5))>>16; - + if(((unsigned)r) > 255) r = ((r>>10)&255)^255; if(((unsigned)g) > 255) g = ((g>>10)&255)^255; if(((unsigned)b) > 255) b = ((b>>10)&255)^255; @@ -878,21 +951,21 @@ compose_ycbcr709 (guchar **src, gint y_incr = incr_src[0]; gint cb_incr = incr_src[1]; gint cr_incr = incr_src[2]; - + while (count-- > 0) { int r,g,b,y,cb,cr; - y = *y_src - 16; - cb= *cb_src - 128; + y = *y_src - 16; + cb= *cb_src - 128; cr= *cr_src - 128; y_src += y_incr; cb_src += cb_incr; cr_src += cr_incr; - + r = (FIXY(1.0)*y + FIXC(1.5748)*cr + FIX(0.5))>>16; g = (FIXY(1.0)*y - FIXC(0.1873)*cb - FIXC(0.4681)*cr + FIX(0.5))>>16; b = (FIXY(1.0)*y + FIXC(1.8556)*cb + FIX(0.5))>>16; - + if(((unsigned)r) > 255) r = ((r>>10)&255)^255; if(((unsigned)g) > 255) g = ((g>>10)&255)^255; if(((unsigned)b) > 255) b = ((b>>10)&255)^255; @@ -918,21 +991,21 @@ compose_ycbcr470f (guchar **src, gint y_incr = incr_src[0]; gint cb_incr = incr_src[1]; gint cr_incr = incr_src[2]; - + while (count-- > 0) { int r,g,b,y,cb,cr; - y = *y_src; - cb= *cb_src - 128; + y = *y_src; + cb= *cb_src - 128; cr= *cr_src - 128; y_src += y_incr; cb_src += cb_incr; cr_src += cr_incr; - + r = (FIX(1.0)*y + FIX(1.4022)*cr + FIX(0.5))>>16; g = (FIX(1.0)*y - FIX(0.3456)*cb - FIX(0.7145)*cr + FIX(0.5))>>16; b = (FIX(1.0)*y + FIX(1.7710)*cb + FIX(0.5))>>16; - + if(((unsigned)r) > 255) r = ((r>>10)&255)^255; if(((unsigned)g) > 255) g = ((g>>10)&255)^255; if(((unsigned)b) > 255) b = ((b>>10)&255)^255; @@ -958,21 +1031,21 @@ compose_ycbcr709f (guchar **src, gint y_incr = incr_src[0]; gint cb_incr = incr_src[1]; gint cr_incr = incr_src[2]; - + while (count-- > 0) { int r,g,b,y,cb,cr; - y = *y_src; - cb= *cb_src - 128; + y = *y_src; + cb= *cb_src - 128; cr= *cr_src - 128; y_src += y_incr; cb_src += cb_incr; cr_src += cr_incr; - + r = (FIX(1.0)*y + FIX(1.5748)*cr + FIX(0.5))>>16; g = (FIX(1.0)*y - FIX(0.1873)*cb - FIX(0.4681)*cr + FIX(0.5))>>16; b = (FIX(1.0)*y + FIX(1.8556)*cb + FIX(0.5))>>16; - + if(((unsigned)r) > 255) r = ((r>>10)&255)^255; if(((unsigned)g) > 255) g = ((g>>10)&255)^255; if(((unsigned)b) > 255) b = ((b>>10)&255)^255; @@ -1002,7 +1075,7 @@ compose_dialog (const gchar *compose_type, /* Check default compose type */ compose_idx = -1; - for (j = 0; j < MAX_COMPOSE_TYPES; j++) + for (j = 0; j < G_N_ELEMENTS (compose_dsc); j++) { if (g_ascii_strcasecmp (compose_type, compose_dsc[j].compose_type) == 0) compose_idx = j; @@ -1102,10 +1175,10 @@ compose_dialog (const gchar *compose_type, /* Set sensitivity of last menu */ gtk_widget_set_sensitive (composeint.channel_menu[3], compose_dsc[compose_idx].channel_name[3] != NULL); - + /* Compose types */ group = NULL; - for (j = 0; j < MAX_COMPOSE_TYPES; j++) + for (j = 0; j < G_N_ELEMENTS (compose_dsc); j++) { toggle = gtk_radio_button_new_with_label (group, gettext (compose_dsc[j].compose_type)); @@ -1167,7 +1240,7 @@ compose_ok_callback (GtkWidget *widget, for (j = 0; j < MAX_COMPOSE_IMAGES; j++) composevals.compose_ID[j] = composeint.select_ID[j]; - for (j = 0; j < MAX_COMPOSE_TYPES; j++) + for (j = 0; j < G_N_ELEMENTS (compose_dsc); j++) { if (composeint.compose_flag[j]) { diff --git a/plug-ins/common/decompose.c b/plug-ins/common/decompose.c index ae5f234d7b..f174dd42b9 100644 --- a/plug-ins/common/decompose.c +++ b/plug-ins/common/decompose.c @@ -23,52 +23,53 @@ * This filter decomposes RGB-images into several types of channels */ -/* Event history: - * V 1.00, PK, 29-Jul-97, Creation - * V 1.01, PK, 19-Mar-99, Update for GIMP V1.1.3 - * Prepare for localization - * Use g_message() in interactive mode +/* Lab colorspace support originally written by Alexey Dyachenko, + * merged into the officical plug-in by Sven Neumann. */ -static char ident[] = "@(#) GIMP Decompose plug-in v1.01 19-Mar-99"; -#ifdef HAVE_CONFIG_H + #include "config.h" -#endif #include #include #include -#include - -#include #include #include +#include #include "libgimp/stdplugins-intl.h" /* 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 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, - gchar *extract_type, - gint32 *drawable_ID_dst); +static gint32 decompose (gint32 image_id, + gint32 drawable_ID, + gchar *extract_type, + gint32 *drawable_ID_dst); +static gint32 create_new_image (const gchar *filename, + const gchar *layername, + guint width, + guint height, + GimpImageBaseType type, + gint32 *layer_ID, + GimpDrawable **drawable, + GimpPixelRgn *pixel_rgn); +static gint32 create_new_layer (gint32 image_ID, + const gchar *layername, + guint width, + guint height, + GimpImageBaseType type, + GimpDrawable **drawable, + GimpPixelRgn *pixel_rgn); -static gint32 create_new_image (gchar *filename, - guint width, - guint height, - GimpImageBaseType type, - gint32 *layer_ID, - GimpDrawable **drawable, - GimpPixelRgn *pixel_rgn); static void extract_rgb (guchar *src, gint bpp, gint numpix, guchar **dst); static void extract_red (guchar *src, gint bpp, gint numpix, guchar **dst); @@ -88,6 +89,7 @@ static void extract_cmyk (guchar *src, gint bpp, gint numpix, guchar **dst); static void extract_cyank (guchar *src, gint bpp, gint numpix, guchar **dst); static void extract_magentak (guchar *src, gint bpp, gint numpix, guchar **dst); static void extract_yellowk (guchar *src, gint bpp, gint numpix, guchar **dst); +static void extract_lab (guchar *src, gint bpp, gint numpix, guchar **dst); static void extract_ycbcr470 (guchar *src, gint bpp, gint numpix, guchar **dst); static void extract_ycbcr709 (guchar *src, gint bpp, gint numpix, guchar **dst); static void extract_ycbcr470f(guchar *src, gint bpp, gint numpix, guchar **dst); @@ -97,6 +99,12 @@ static gint decompose_dialog (void); static void decompose_ok_callback (GtkWidget *widget, gpointer data); +/* LAB colorspace constants */ +const double Xn = 0.951; +const double Yn = 1.0; +const double Zn = 1.089; + + /* Maximum number of new images generated by an extraction */ #define MAX_EXTRACT_IMAGES 4 @@ -109,8 +117,7 @@ typedef struct gint num_images; /* Number of images to create */ gchar *channel_name[MAX_EXTRACT_IMAGES]; /* Names of channels to extract */ /* Function that performs the extraction */ - void (*extract_fun) (guchar *src, int bpp, gint numpix, - guchar **dst); + void (*extract_fun) (guchar *src, int bpp, gint numpix, guchar **dst); } EXTRACT; static EXTRACT extract[] = @@ -145,35 +152,39 @@ static EXTRACT extract[] = { N_("Magenta_K"), FALSE, 1, { N_("magenta_k") }, extract_magentak }, { N_("Yellow_K"), FALSE, 1, { N_("yellow_k") }, extract_yellowk }, { N_("Alpha"), TRUE, 1, { N_("alpha") }, extract_alpha }, - { "YCbCr_ITU_R470", + + { N_("LAB"), TRUE, 3, { "L", + "A", + "B" }, extract_lab }, + + { "YCbCr_ITU_R470", TRUE, 3, { N_("luma_y470"), N_("blueness_cb470"), N_("redness_cr470") }, extract_ycbcr470 }, - { "YCbCr_ITU_R709", + { "YCbCr_ITU_R709", TRUE, 3, { N_("luma_y709"), N_("blueness_cb709"), N_("redness_cr709") }, extract_ycbcr709 }, - { "YCbCr_ITU_R470_256", + { "YCbCr_ITU_R470_256", TRUE, 3, { N_("luma_y470f"), N_("blueness_cb470f"), N_("redness_cr470f") }, extract_ycbcr470f }, - { "YCbCr_ITU_R709_256", + { "YCbCr_ITU_R709_256", TRUE, 3, { N_("luma_y709f"), N_("blueness_cb709f"), N_("redness_cr709f") }, extract_ycbcr709f }, }; -/* Number of types of extractions */ -#define NUM_EXTRACT_TYPES (G_N_ELEMENTS (extract)) typedef struct { - gchar extract_type[32]; + gchar extract_type[32]; + gboolean as_layers; } DecoVals; typedef struct { - gint extract_flag[NUM_EXTRACT_TYPES]; + gint extract_flag[G_N_ELEMENTS (extract)]; gboolean run; } DecoInterface; @@ -187,7 +198,8 @@ GimpPlugInInfo PLUG_IN_INFO = static DecoVals decovals = { - "rgb" /* Decompose type */ + "rgb", /* Decompose type */ + TRUE /* Decompose to Layers */ }; static DecoInterface decoint = @@ -206,10 +218,11 @@ query (void) { static GimpParamDef args[] = { - { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" }, - { GIMP_PDB_IMAGE, "image", "Input image (unused)" }, - { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }, - { GIMP_PDB_STRING, "decompose_type", "What to decompose: RGB, Red, Green, Blue, RGBA, Red, Green, Blue, Alpha, HSV, Hue, Saturation, Value, CMY, Cyan, Magenta, Yellow, CMYK, Cyan_K, Magenta_K, Yellow_K, Alpha" } + { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" }, + { GIMP_PDB_IMAGE, "image", "Input image (unused)" }, + { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }, + { GIMP_PDB_STRING, "decompose_type", "What to decompose: RGB, Red, Green, Blue, RGBA, Red, Green, Blue, Alpha, HSV, Hue, Saturation, Value, CMY, Cyan, Magenta, Yellow, CMYK, Cyan_K, Magenta_K, Yellow_K, Alpha, LAB" }, + { GIMP_PDB_INT32, "layers_mode", "Create channels as layers in a single image" } }; static GimpParamDef return_vals[] = { @@ -276,7 +289,7 @@ run (const gchar *name, case GIMP_RUN_NONINTERACTIVE: /* Make sure all the arguments are there! */ - if (nparams != 4) + if (nparams != 4 && nparams != 5) { status = GIMP_PDB_CALLING_ERROR; } @@ -285,6 +298,8 @@ run (const gchar *name, 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; } break; @@ -308,10 +323,10 @@ run (const gchar *name, { if (run_mode != GIMP_RUN_NONINTERACTIVE) gimp_progress_init (_("Decomposing...")); - + num_images = decompose (param[1].data.d_image, param[2].data.d_drawable, decovals.extract_type, image_ID_extract); - + if (num_images <= 0) { status = GIMP_PDB_EXECUTION_ERROR; @@ -326,13 +341,13 @@ run (const gchar *name, 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_decompose", &decovals, sizeof (DecoVals)); } } - + values[0].data.d_status = status; } @@ -347,17 +362,18 @@ decompose (gint32 image_ID, char *extract_type, gint32 *image_ID_dst) { - gint i, j, extract_idx, scan_lines; - gint height, width, tile_height, num_images; - guchar *src = (guchar *)ident; /* Just to satisfy gcc/lint */ - gchar *filename; + const gchar *layername; + gint i, j, extract_idx, scan_lines; + gint height, width, tile_height, num_images; + gchar *filename; + guchar *src; guchar *dst[MAX_EXTRACT_IMAGES]; - gint32 layer_ID_dst[MAX_EXTRACT_IMAGES]; + gint32 layer_ID_dst[MAX_EXTRACT_IMAGES]; GimpDrawable *drawable_src, *drawable_dst[MAX_EXTRACT_IMAGES]; GimpPixelRgn pixel_rgn_src, pixel_rgn_dst[MAX_EXTRACT_IMAGES]; extract_idx = -1; /* Search extract type */ - for (j = 0; j < NUM_EXTRACT_TYPES; j++) + for (j = 0; j < G_N_ELEMENTS (extract); j++) { if (g_ascii_strcasecmp (extract_type, extract[j].type) == 0) { @@ -365,23 +381,24 @@ decompose (gint32 image_ID, break; } } - if (extract_idx < 0) return (-1); - + if (extract_idx < 0) + return -1; + /* Check structure of source image */ drawable_src = gimp_drawable_get (drawable_ID); if (drawable_src->bpp < 3) { g_message ("Not an RGB image."); - return (-1); + return -1; } - if ((extract[extract_idx].extract_fun == extract_alpha || + if ((extract[extract_idx].extract_fun == extract_alpha || extract[extract_idx].extract_fun == extract_rgba) && (!gimp_drawable_has_alpha (drawable_ID))) { g_message ("No alpha channel available."); - return (-1); + return -1; } - + width = drawable_src->width; height = drawable_src->height; @@ -394,9 +411,9 @@ decompose (gint32 image_ID, /* Create all new gray images */ num_images = extract[extract_idx].num_images; - if (num_images > MAX_EXTRACT_IMAGES) + if (num_images > MAX_EXTRACT_IMAGES) num_images = MAX_EXTRACT_IMAGES; - + for (j = 0; j < num_images; j++) { /* Build a filename like -. */ @@ -417,14 +434,24 @@ decompose (gint32 image_ID, if (extension >= fname) { *(extension++) = '\0'; - filename = g_strdup_printf ("%s-%s.%s", fname, - gettext (extract[extract_idx].channel_name[j]), - extension); + + if (decovals.as_layers) + filename = g_strdup_printf ("%s-%s.%s", fname, + gettext (extract[extract_idx].type), + extension); + else + filename = g_strdup_printf ("%s-%s.%s", fname, + gettext (extract[extract_idx].channel_name[j]), + extension); } else { - filename = g_strdup_printf ("%s-%s", fname, - gettext (extract[extract_idx].channel_name[j])); + if (decovals.as_layers) + filename = g_strdup_printf ("%s-%s", fname, + gettext (extract[extract_idx].type)); + else + filename = g_strdup_printf ("%s-%s", fname, + gettext (extract[extract_idx].channel_name[j])); } } else @@ -432,89 +459,139 @@ decompose (gint32 image_ID, filename = g_strdup (gettext (extract[extract_idx].channel_name[j])); } - image_ID_dst[j] = create_new_image (filename, width, height, GIMP_GRAY, - layer_ID_dst+j, drawable_dst+j, - pixel_rgn_dst+j); + if (decovals.as_layers) + { + layername = gettext (extract[extract_idx].channel_name[j]); + + if (j == 0) + image_ID_dst[j] = create_new_image (filename, layername, + width, height, GIMP_GRAY, + layer_ID_dst + j, + drawable_dst + j, pixel_rgn_dst + j); + else + create_new_layer (image_ID_dst[0], layername, + width, height, GIMP_GRAY, + drawable_dst + j, pixel_rgn_dst + j); + } + else + { + image_ID_dst[j] = create_new_image (filename, NULL, + width, height, GIMP_GRAY, + layer_ID_dst + j, + drawable_dst + j, pixel_rgn_dst + j); + } + g_free (filename); g_free (fname); dst[j] = g_new (guchar, tile_height * width); } - + i = 0; while (i < height) { /* Get source pixel region */ scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); gimp_pixel_rgn_get_rect (&pixel_rgn_src, src, 0, i, width, scan_lines); - + /* Extract the channel information */ extract[extract_idx].extract_fun (src, drawable_src->bpp, scan_lines*width, dst); - + /* Set destination pixel regions */ for (j = 0; j < num_images; j++) gimp_pixel_rgn_set_rect (&(pixel_rgn_dst[j]), dst[j], 0, i, width, scan_lines); i += scan_lines; - + if (run_mode != GIMP_RUN_NONINTERACTIVE) gimp_progress_update (((gdouble)i) / (gdouble)height); } + g_free (src); + for (j = 0; j < num_images; j++) { gimp_drawable_flush (drawable_dst[j]); gimp_drawable_detach (drawable_dst[j]); g_free (dst[j]); } - + gimp_drawable_flush (drawable_src); gimp_drawable_detach (drawable_src); - - return (num_images); + + return (decovals.as_layers ? 1 : num_images); } /* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */ static gint32 -create_new_image (gchar *filename, - guint width, - guint height, +create_new_image (const gchar *filename, + const gchar *layername, + guint width, + guint height, GimpImageBaseType type, - gint32 *layer_ID, - GimpDrawable **drawable, - GimpPixelRgn *pixel_rgn) + gint32 *layer_ID, + GimpDrawable **drawable, + GimpPixelRgn *pixel_rgn) { gint32 image_ID; - GimpImageType gdtype; - - if (type == GIMP_GRAY) - gdtype = GIMP_GRAY_IMAGE; - else if (type == GIMP_INDEXED) - gdtype = GIMP_INDEXED_IMAGE; - else - gdtype = GIMP_RGB_IMAGE; - + image_ID = gimp_image_new (width, height, type); gimp_image_set_filename (image_ID, filename); - - *layer_ID = gimp_layer_new (image_ID, _("Background"), width, height, - gdtype, 100, GIMP_NORMAL_MODE); - gimp_image_add_layer (image_ID, *layer_ID, 0); - - *drawable = gimp_drawable_get (*layer_ID); + + *layer_ID = create_new_layer (image_ID, + layername, width, height, type, + drawable, pixel_rgn); + + return image_ID; +} + + +static gint32 +create_new_layer (gint32 image_ID, + const gchar *layername, + guint width, + guint height, + GimpImageBaseType type, + GimpDrawable **drawable, + GimpPixelRgn *pixel_rgn) +{ + gint32 layer_ID; + 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_ID = gimp_layer_new (image_ID, layername, width, height, + gdtype, 100, GIMP_NORMAL_MODE); + gimp_image_add_layer (image_ID, layer_ID, 0); + + *drawable = gimp_drawable_get (layer_ID); gimp_pixel_rgn_init (pixel_rgn, *drawable, 0, 0, (*drawable)->width, (*drawable)->height, TRUE, FALSE); - - return (image_ID); + + return layer_ID; } /* Extract functions */ -static void -extract_rgb (guchar *src, - gint bpp, +static void +extract_rgb (guchar *src, + gint bpp, gint numpix, guchar **dst) { @@ -523,7 +600,7 @@ extract_rgb (guchar *src, register guchar *green_dst = dst[1]; register guchar *blue_dst = dst[2]; register gint count = numpix, offset = bpp-3; - + while (count-- > 0) { *(red_dst++) = *(rgb_src++); @@ -533,9 +610,9 @@ extract_rgb (guchar *src, } } -static void -extract_rgba (guchar *src, - gint bpp, +static void +extract_rgba (guchar *src, + gint bpp, gint numpix, guchar **dst) { @@ -545,7 +622,7 @@ extract_rgba (guchar *src, register guchar *blue_dst = dst[2]; register guchar *alpha_dst = dst[3]; register gint count = numpix, offset = bpp-4; - + while (count-- > 0) { *(red_dst++) = *(rgba_src++); @@ -556,16 +633,16 @@ extract_rgba (guchar *src, } } -static void -extract_red (guchar *src, - gint bpp, +static void +extract_red (guchar *src, + gint bpp, gint numpix, guchar **dst) { register guchar *rgb_src = src; register guchar *red_dst = dst[0]; register gint count = numpix, offset = bpp; - + while (count-- > 0) { *(red_dst++) = *rgb_src; @@ -574,16 +651,16 @@ extract_red (guchar *src, } -static void -extract_green (guchar *src, - gint bpp, +static void +extract_green (guchar *src, + gint bpp, gint numpix, guchar **dst) { register guchar *rgb_src = src+1; register guchar *green_dst = dst[0]; register gint count = numpix, offset = bpp; - + while (count-- > 0) { *(green_dst++) = *rgb_src; @@ -592,16 +669,16 @@ extract_green (guchar *src, } -static void -extract_blue (guchar *src, - gint bpp, +static void +extract_blue (guchar *src, + gint bpp, gint numpix, guchar **dst) { register guchar *rgb_src = src+2; register guchar *blue_dst = dst[0]; register gint count = numpix, offset = bpp; - + while (count-- > 0) { *(blue_dst++) = *rgb_src; @@ -610,16 +687,16 @@ extract_blue (guchar *src, } -static void -extract_alpha (guchar *src, - gint bpp, +static void +extract_alpha (guchar *src, + gint bpp, gint numpix, guchar **dst) { register guchar *rgb_src = src+3; register guchar *alpha_dst = dst[0]; register gint count = numpix, offset = bpp; - + while (count-- > 0) { *(alpha_dst++) = *rgb_src; @@ -629,8 +706,8 @@ extract_alpha (guchar *src, static void -extract_cmy (guchar *src, - gint bpp, +extract_cmy (guchar *src, + gint bpp, gint numpix, guchar **dst) { @@ -639,7 +716,7 @@ extract_cmy (guchar *src, register guchar *magenta_dst = dst[1]; register guchar *yellow_dst = dst[2]; register gint count = numpix, offset = bpp-3; - + while (count-- > 0) { *(cyan_dst++) = 255 - *(rgb_src++); @@ -650,9 +727,9 @@ extract_cmy (guchar *src, } -static void -extract_hsv (guchar *src, - gint bpp, +static void +extract_hsv (guchar *src, + gint bpp, gint numpix, guchar **dst) { @@ -662,7 +739,7 @@ extract_hsv (guchar *src, register guchar *val_dst = dst[2]; register gint count = numpix, offset = bpp; gdouble hue, sat, val; - + while (count-- > 0) { gimp_rgb_to_hsv4 (rgb_src, &hue, &sat, &val); @@ -674,9 +751,9 @@ extract_hsv (guchar *src, } -static void -extract_hue (guchar *src, - gint bpp, +static void +extract_hue (guchar *src, + gint bpp, gint numpix, guchar **dst) { @@ -684,7 +761,7 @@ extract_hue (guchar *src, register guchar *hue_dst = dst[0]; register gint count = numpix, offset = bpp; gdouble hue, dummy; - + while (count-- > 0) { gimp_rgb_to_hsv4 (rgb_src, &hue, &dummy, &dummy); @@ -694,9 +771,9 @@ extract_hue (guchar *src, } -static void -extract_sat (guchar *src, - gint bpp, +static void +extract_sat (guchar *src, + gint bpp, gint numpix, guchar **dst) { @@ -704,7 +781,7 @@ extract_sat (guchar *src, register guchar *sat_dst = dst[0]; register gint count = numpix, offset = bpp; gdouble sat, dummy; - + while (count-- > 0) { gimp_rgb_to_hsv4 (rgb_src, &dummy, &sat, &dummy); @@ -714,9 +791,9 @@ extract_sat (guchar *src, } -static void -extract_val (guchar *src, - gint bpp, +static void +extract_val (guchar *src, + gint bpp, gint numpix, guchar **dst) { @@ -724,7 +801,7 @@ extract_val (guchar *src, register guchar *val_dst = dst[0]; register gint count = numpix, offset = bpp; gdouble val, dummy; - + while (count-- > 0) { gimp_rgb_to_hsv4 (rgb_src, &dummy, &dummy, &val); @@ -734,16 +811,16 @@ extract_val (guchar *src, } -static void -extract_cyan (guchar *src, - gint bpp, +static void +extract_cyan (guchar *src, + gint bpp, gint numpix, guchar **dst) { register guchar *rgb_src = src; register guchar *cyan_dst = dst[0]; register gint count = numpix, offset = bpp-1; - + while (count-- > 0) { *(cyan_dst++) = 255 - *(rgb_src++); @@ -752,16 +829,16 @@ extract_cyan (guchar *src, } -static void -extract_magenta (guchar *src, - gint bpp, +static void +extract_magenta (guchar *src, + gint bpp, gint numpix, guchar **dst) { register guchar *rgb_src = src+1; register guchar *magenta_dst = dst[0]; register gint count = numpix, offset = bpp-1; - + while (count-- > 0) { *(magenta_dst++) = 255 - *(rgb_src++); @@ -770,16 +847,16 @@ extract_magenta (guchar *src, } -static void -extract_yellow (guchar *src, - gint bpp, +static void +extract_yellow (guchar *src, + gint bpp, gint numpix, guchar **dst) { register guchar *rgb_src = src+2; register guchar *yellow_dst = dst[0]; register gint count = numpix, offset = bpp-1; - + while (count-- > 0) { *(yellow_dst++) = 255 - *(rgb_src++); @@ -788,9 +865,9 @@ extract_yellow (guchar *src, } -static void -extract_cmyk (guchar *src, - gint bpp, +static void +extract_cmyk (guchar *src, + gint bpp, gint numpix, guchar **dst) @@ -802,15 +879,15 @@ extract_cmyk (guchar *src, register guchar *black_dst = dst[3]; register guchar k, s; register gint count = numpix, offset = bpp-3; - + while (count-- > 0) { *cyan_dst = k = 255 - *(rgb_src++); *magenta_dst = s = 255 - *(rgb_src++); - if (s < k) + if (s < k) k = s; *yellow_dst = s = 255 - *(rgb_src++); - if (s < k) + if (s < k) k = s; /* Black intensity is minimum of c, m, y */ if (k) { @@ -822,15 +899,15 @@ extract_cmyk (guchar *src, magenta_dst++; yellow_dst++; *(black_dst++) = k; - + rgb_src += offset; } } -static void -extract_cyank (guchar *src, - gint bpp, +static void +extract_cyank (guchar *src, + gint bpp, gint numpix, guchar **dst) { @@ -838,7 +915,7 @@ extract_cyank (guchar *src, register guchar *cyan_dst = dst[0]; register guchar s, k; register gint count = numpix, offset = bpp-3; - + while (count-- > 0) { *cyan_dst = k = 255 - *(rgb_src++); @@ -848,15 +925,15 @@ extract_cyank (guchar *src, if (s < k) k = s; if (k) *cyan_dst -= k; cyan_dst++; - + rgb_src += offset; } } -static void -extract_magentak (guchar *src, - gint bpp, +static void +extract_magentak (guchar *src, + gint bpp, gint numpix, guchar **dst) { @@ -864,28 +941,28 @@ extract_magentak (guchar *src, register guchar *magenta_dst = dst[0]; register guchar s, k; register gint count = numpix, offset = bpp-3; - + while (count-- > 0) { k = 255 - *(rgb_src++); /* cyan */ *magenta_dst = s = 255 - *(rgb_src++); /* magenta */ - if (s < k) + if (s < k) k = s; s = 255 - *(rgb_src++); /* yellow */ - if (s < k) + if (s < k) k = s; - if (k) + if (k) *magenta_dst -= k; magenta_dst++; - + rgb_src += offset; } } -static void -extract_yellowk (guchar *src, - gint bpp, +static void +extract_yellowk (guchar *src, + gint bpp, gint numpix, guchar **dst) @@ -894,34 +971,88 @@ extract_yellowk (guchar *src, register guchar *yellow_dst = dst[0]; register guchar s, k; register gint count = numpix, offset = bpp-3; - + while (count-- > 0) { k = 255 - *(rgb_src++); /* cyan */ s = 255 - *(rgb_src++); /* magenta */ if (s < k) k = s; *yellow_dst = s = 255 - *(rgb_src++); - if (s < k) + if (s < k) k = s; - if (k) + if (k) *yellow_dst -= k; yellow_dst++; - + rgb_src += offset; } } -/* these are here so the code is more readable and we can use - the standart values instead of some scaled and rounded fixpoint values */ +static void +extract_lab (guchar *src, + gint bpp, + gint numpix, + guchar **dst) +{ + register guchar *rgb_src = src; + register guchar *l_dst = dst[0]; + register guchar *a_dst = dst[1]; + register guchar *b_dst = dst[2]; + register gint count = numpix, offset = bpp; + + gdouble red, green, blue; + gdouble x, y, z; + gdouble l; /*, a, b; */ + gdouble tx, ty, tz; + gdouble ftx, fty, ftz; + + gdouble sixteenth = 16.0 / 116.0; + + + while (count-- > 0) + { + red = rgb_src[0] / 255.0; + green = rgb_src[1] / 255.0; + blue = rgb_src[2] / 255.0; + + x = 0.431 * red + 0.342 * green + 0.178 * blue; + y = 0.222 * red + 0.707 * green + 0.071 * blue; + z = 0.020 * red + 0.130 * green + 0.939 * blue; + + if (( ty = y/Yn ) > 0.008856) + { + l = 116.0 * cbrt( ty ) - 16.0; + fty = cbrt( ty ); + } + else + { + l = 903.3 * ty; + fty = 7.78*ty + sixteenth; + } + + ftx = ((tx = x/Xn) > 0.008856) ? cbrt (tx) : 7.78 * tx + sixteenth; + ftz = ((tz = z/Zn) > 0.008856) ? cbrt (tz) : 7.78 * tz + sixteenth; + + *l_dst++ = (guchar) (l * 2.5599); + *a_dst++ = (guchar) (128.0 + (ftx - fty) * 635 ); + *b_dst++ = (guchar) (128.0 + (fty - ftz) * 254 ); + + rgb_src += offset; + } +} + + +/* these are here so the code is more readable and we can use + the standard values instead of some scaled and rounded fixpoint values */ #define FIX(a) ((int)((a)*256.0*256.0 + 0.5)) #define FIXY(a) ((int)((a)*256.0*256.0*219.0/255.0 + 0.5)) #define FIXC(a) ((int)((a)*256.0*256.0*224.0/255.0 + 0.5)) static void -extract_ycbcr470 (guchar *src, - gint bpp, - gint numpix, - guchar **dst) +extract_ycbcr470 (guchar *src, + gint bpp, + gint numpix, + guchar **dst) { register guchar *rgb_src = src; register guchar *y_dst = dst[0]; @@ -945,10 +1076,10 @@ extract_ycbcr470 (guchar *src, static void -extract_ycbcr709 (guchar *src, - gint bpp, - gint numpix, - guchar **dst) +extract_ycbcr709 (guchar *src, + gint bpp, + gint numpix, + guchar **dst) { register guchar *rgb_src = src; register guchar *y_dst = dst[0]; @@ -972,10 +1103,10 @@ extract_ycbcr709 (guchar *src, static void -extract_ycbcr470f (guchar *src, - gint bpp, - gint numpix, - guchar **dst) +extract_ycbcr470f (guchar *src, + gint bpp, + gint numpix, + guchar **dst) { register guchar *rgb_src = src; register guchar *y_dst = dst[0]; @@ -1002,8 +1133,8 @@ extract_ycbcr470f (guchar *src, static void -extract_ycbcr709f (guchar *src, - gint bpp, +extract_ycbcr709f (guchar *src, + gint bpp, gint numpix, guchar **dst) { @@ -1071,11 +1202,13 @@ decompose_dialog (void) gtk_container_add (GTK_CONTAINER (frame), vbox); group = NULL; - for (j = 0; j < NUM_EXTRACT_TYPES; j++) + for (j = 0; j < G_N_ELEMENTS (extract); j++) { - if (!extract[j].dialog) + if (!extract[j].dialog) continue; - toggle = gtk_radio_button_new_with_label (group, gettext (extract[j].type)); + + toggle = gtk_radio_button_new_with_label (group, + gettext (extract[j].type)); group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (toggle)); gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0); decoint.extract_flag[j] = @@ -1089,6 +1222,16 @@ decompose_dialog (void) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), decoint.extract_flag[j]); } + + toggle = gtk_check_button_new_with_label (_("Decompose to _Layers")); + gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0); + g_signal_connect (toggle, "toggled", + G_CALLBACK (gimp_toggle_button_update), + &decovals.as_layers); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), + decovals.as_layers); + gtk_widget_show (toggle); + gtk_widget_show (vbox); gtk_widget_show (frame); gtk_widget_show (dlg); @@ -1108,7 +1251,7 @@ decompose_ok_callback (GtkWidget *widget, decoint.run = TRUE; gtk_widget_destroy (GTK_WIDGET (data)); - for (j = 0; j < NUM_EXTRACT_TYPES; j++) + for (j = 0; j < G_N_ELEMENTS (extract); j++) { if (decoint.extract_flag[j]) {