/* Twist - A geometric image distortion plugin for 'The GIMP' * (see legal notice below). * Copyright (C) 1997 Peter Uray. * (e-mail: pau@icg.tu-graz.ac.at or peter.uray@joanneum.ac.at) * * 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 2 of the License, or * (at your option) any later version. * * This program is distributed 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* The GIMP -- an image manipulation program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #define ENTRY_WIDTH 70 #define epsilon 0.001 #define preview_width 128 #define preview_height 128 /* The number of parameters needed for non-interative mode */ #define N_PARAMETERS 15 /* The number of available functions */ #define N_FUNCTIONS 8 /* I learned that in general PI is not defined in math.h */ /* (Thanks to all who pointed this out.) Now this #define */ /* solves the problem rather brutally but once and for all. */ #define TWIST_PI 3.1415927 /* Identifiers for the distortion function types */ #define FUNCTION_R_r 0 #define FUNCTION_R_phi 1 #define FUNCTION_Phi_r 2 #define FUNCTION_Phi_phi 3 #define FUNCTION_R_r_Phi_phi 4 #define FUNCTION_R_r_R_phi 5 #define FUNCTION_Cosines 6 #define FUNCTION_Gauss 7 /*************************************************************************** * * * Global data definition. * * ***************************************************************************/ /* do_action is used for preventing the plugin to act when the [Cancel] button was pressed. */ static gint do_action = 0; static gint do_update_preview = 1; /* Some frequently used strings. */ static char PluginName[] = "Twist"; static char PluginResource[] = "plug_in_Twist"; static char PluginAuthor[] = "Peter Uray"; static char PluginYear[] = "1997"; static char PluginDescription[] = "Twist - Geometric image distortion"; static char PluginGroup[] = "/Filters/Distorts/Twist"; /* Definition of global structure types */ /* A GtkObject and a label - used below */ typedef struct { GtkWidget *object; GtkLabel *label; }ObjectAndLabel; /* These parameters are modified in the 'Parameter settings' section. */ typedef struct { gfloat a1; gfloat a2; gfloat a3; gfloat a4; gfloat a5; gfloat a6; gfloat a7; gfloat a8; gchar lettering01[30]; gchar lettering02[30]; gchar lettering03[30]; gchar lettering04[30]; gchar lettering05[30]; gchar lettering06[30]; gchar lettering07[30]; gchar lettering08[30]; gint use_cutoff; gfloat r; gfloat dr; gint current_function; }Parameters; /* The labels of the parameter selection box */ /* These depend on the selected function */ typedef struct { char name_a1[30]; char name_a2[30]; char name_a3[30]; char name_a4[30]; char name_a5[30]; char name_a6[30]; char name_a7[30]; char name_a8[30]; }ParameterNames; /* Data fields used for creating a dialog and the action area. */ typedef struct { GtkWidget *dlg; GtkWidget *ok_button; GtkWidget *cancel_button; GtkWidget *dialog_frame; gchar **argv; gint argc; }DialogTemplateData; /* Data used for maintaining the preview image */ typedef struct { gint width; gint height; gint bpp; gfloat scale; guchar *bits; GtkWidget *display; }PreviewData; /* These pointers are needed for modifying the sliders in update_dialog */ typedef struct { GtkWidget *slider01; GtkWidget *slider02; GtkWidget *slider03; GtkWidget *slider04; GtkWidget *slider05; GtkWidget *slider06; GtkWidget *slider07; GtkWidget *slider08; GtkWidget *slider09; GtkWidget *slider10; GtkLabel *label01; GtkLabel *label02; GtkLabel *label03; GtkLabel *label04; GtkLabel *label05; GtkLabel *label06; GtkLabel *label07; GtkLabel *label08; GtkWidget *toggle01; }WidgetData; /* Parameter initialization */ static Parameters parameter_values = { 0.0, /* a1 */ 0.0, /* a2 */ 0.0, /* a3 */ 0.0, /* a4 */ 0.0, /* a5 */ 0.0, /* a6 */ 0.0, /* a7 */ 0.0, /* a8 */ "unused", /* lettering01 */ "unused", /* lettering02 */ "unused", /* lettering03 */ "unused", /* lettering04 */ "unused", /* lettering05 */ "unused", /* lettering06 */ "unused", /* lettering07 */ "unused", /* lettering08 */ FALSE, /* use_cutoff */ 0.5, /* r */ 0.2, /* dr */ FUNCTION_R_r /* current_function */ }; static DialogTemplateData dtd; static PreviewData preview_data; static WidgetData widget_data; static ParameterNames parameter_names[N_FUNCTIONS]; static Parameters EffectsParameters[N_FUNCTIONS][9]; /*************************************************************************** * * * Forward declarations * * ***************************************************************************/ /* Declare local functions. */ static void query(void); static void run(gchar *name, gint nparams, GimpParam *param, gint *nreturn_vals, GimpParam **return_vals); /* Callback functions */ static void close_callback(GtkWidget *widget, gpointer data); static void ok_callback(GtkWidget *widget, gpointer data); static void cancel_callback(GtkWidget *widget, gpointer data); static void a1_callback(GtkAdjustment *adjustment, gpointer data); static void a2_callback(GtkAdjustment *adjustment, gpointer data); static void a3_callback(GtkAdjustment *adjustment, gpointer data); static void a4_callback(GtkAdjustment *adjustment, gpointer data); static void a5_callback(GtkAdjustment *adjustment, gpointer data); static void a6_callback(GtkAdjustment *adjustment, gpointer data); static void a7_callback(GtkAdjustment *adjustment, gpointer data); static void a8_callback(GtkAdjustment *adjustment, gpointer data); static void use_cutoff_callback(GtkWidget *widget, gpointer data); static void r_callback(GtkAdjustment *adjustment, gpointer data); static void dr_callback(GtkAdjustment *adjustment, gpointer data); static void effect01_callback(GtkWidget *widget, gpointer data); static void effect02_callback(GtkWidget *widget, gpointer data); static void effect03_callback(GtkWidget *widget, gpointer data); static void effect04_callback(GtkWidget *widget, gpointer data); static void effect05_callback(GtkWidget *widget, gpointer data); static void effect06_callback(GtkWidget *widget, gpointer data); static void effect07_callback(GtkWidget *widget, gpointer data); static void effect08_callback(GtkWidget *widget, gpointer data); static void effect09_callback(GtkWidget *widget, gpointer data); static void function01_callback(GtkWidget *widget, gpointer data); static void function02_callback(GtkWidget *widget, gpointer data); static void function03_callback(GtkWidget *widget, gpointer data); static void function04_callback(GtkWidget *widget, gpointer data); static void function05_callback(GtkWidget *widget, gpointer data); static void function06_callback(GtkWidget *widget, gpointer data); static void function07_callback(GtkWidget *widget, gpointer data); static void function08_callback(GtkWidget *widget, gpointer data); /* Dialog creation/updating functions */ /* This function executes the user dialog */ static gint user_dialog(void); /* This function syncs the dialog display with the contents of the parameter_values */ static void update_dialog(void); static void create_base_dialog(void); static ObjectAndLabel create_slider_with_label(gchar *text, GtkWidget *container, GtkSignalFunc callback_func, gfloat initial_value, gfloat min_value, gfloat max_value); static void create_functions_menu(GtkWidget *container); static void create_effects_menu(GtkWidget *container); static void create_cutoff_panel(GtkWidget *container); /* Functions for handling the preview */ static void create_preview(GimpDrawable *drawable); static void update_preview(GtkWidget *preview); /* This function actually modifies the image */ void image_action(GimpDrawable *drawable, Parameters params); /* Functions for calculating the image distortion */ static void polar_coordinates(gfloat x, gfloat y, gfloat *rho, gfloat *phi); /* The distortion functions. */ static void distortion_function01(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2); static void distortion_function02(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2); static void distortion_function03(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2); static void distortion_function04(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2); static void distortion_function05(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2); static void distortion_function06(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2); static void distortion_function07(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2); static void distortion_function08(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2); static void calculate_distortion_function(gint i, gint j, gint width, gint height, gfloat *u, gfloat *v); static gfloat cutoff_function(gfloat u, gfloat v); static void calculate_pixel_color(gfloat u, gfloat v, guchar *source, gint width, gint height, gint bpp, guchar *r, guchar *g, guchar *b, guchar *a); /* Functions for image data exchange between GIMP and the plugin */ static void get_source_image(GimpPixelRgn source_rgn, guchar *buffer, gint x, gint y, gint width, gint height, gint bytes); /*************************************************************************** * * * Implementation * * ***************************************************************************/ /* An auxiliary function to make life easier while initializing the effects */ static void SET_EFFECTS_PARAMS(gint i, gint j, gfloat a1, gfloat a2, gfloat a3, gfloat a4, gfloat a5, gfloat a6, gfloat a7, gfloat a8, gint uc, gfloat r, gfloat dr) { EffectsParameters[i][j].a1 = a1; EffectsParameters[i][j].a2 = a2; EffectsParameters[i][j].a3 = a3; EffectsParameters[i][j].a4 = a4; EffectsParameters[i][j].a5 = a5; EffectsParameters[i][j].a6 = a6; EffectsParameters[i][j].a7 = a7; EffectsParameters[i][j].a8 = a8; EffectsParameters[i][j].use_cutoff = uc; EffectsParameters[i][j].r = r; EffectsParameters[i][j].dr = dr; } GimpPlugInInfo PLUG_IN_INFO = { NULL, /* init_proc */ NULL, /* quit_proc */ query, /* query_proc */ run, /* run_proc */ }; /******************************************************************************/ /* Standard functions */ /******************************************************************************/ /* The main function */ MAIN() static void query () { static GimpParamDef args[] = { { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" }, { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }, { GIMP_PDB_FLOAT, "a1", "float parameter #1" }, { GIMP_PDB_FLOAT, "a2", "float parameter #2" }, { GIMP_PDB_FLOAT, "a3", "float parameter #3" }, { GIMP_PDB_FLOAT, "a4", "float parameter #4" }, { GIMP_PDB_FLOAT, "a5", "float parameter #5" }, { GIMP_PDB_FLOAT, "a6", "float parameter #6" }, { GIMP_PDB_FLOAT, "a7", "float parameter #7" }, { GIMP_PDB_FLOAT, "a8", "float parameter #8" }, { GIMP_PDB_STRING , "lettering01", "lettering #1" }, { GIMP_PDB_STRING , "lettering02", "lettering #2" }, { GIMP_PDB_STRING , "lettering03", "lettering #3" }, { GIMP_PDB_STRING , "lettering04", "lettering #4" }, { GIMP_PDB_STRING , "lettering05", "lettering #5" }, { GIMP_PDB_STRING , "lettering06", "lettering #6" }, { GIMP_PDB_STRING , "lettering07", "lettering #7" }, { GIMP_PDB_STRING , "lettering08", "lettering #8" }, { GIMP_PDB_INT32, "use_cutoff", "Use cutoff or not" }, { GIMP_PDB_FLOAT, "r", "The cutoff radius" }, { GIMP_PDB_FLOAT, "dr", "The falloff radius" }, { GIMP_PDB_INT32, "current_function", "The current function" }, }; static GimpParamDef *return_vals = NULL; static gint nargs = sizeof (args) / sizeof (args[0]); static gint nreturn_vals = 0; gimp_install_procedure (PluginResource, PluginDescription, PluginDescription, PluginAuthor, PluginAuthor, PluginYear, PluginGroup, "RGB*, GRAY*", GIMP_PLUGIN, nargs, nreturn_vals, args, return_vals); } static void run(gchar *name, gint nparams, GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[1]; GimpDrawable *drawable; GimpRunModeType run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; run_mode = param[0].data.d_int32; *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; /* Get the drawable */ drawable = gimp_drawable_get(param[2].data.d_drawable); /* Parameter names for R(r) distortion */ strcpy(parameter_names[0].name_a1, "Linear coefficient:"); strcpy(parameter_names[0].name_a2, "Quadratic coefficient:"); strcpy(parameter_names[0].name_a3, "Cubic coefficient:"); strcpy(parameter_names[0].name_a4, "Quartic coefficient:"); strcpy(parameter_names[0].name_a5, "unused"); strcpy(parameter_names[0].name_a6, "unused"); strcpy(parameter_names[0].name_a7, "unused"); strcpy(parameter_names[0].name_a8, "unused"); /* Parameter names for R(phi) distortion */ strcpy(parameter_names[1].name_a1, "Amplitude 1:"); strcpy(parameter_names[1].name_a2, "Frequency 1:"); strcpy(parameter_names[1].name_a3, "Amplitude 2:"); strcpy(parameter_names[1].name_a4, "Frequency 2"); strcpy(parameter_names[1].name_a5, "unused"); strcpy(parameter_names[1].name_a6, "unused"); strcpy(parameter_names[1].name_a7, "unused"); strcpy(parameter_names[1].name_a8, "unused"); /* Parameter names for Phi(r) distortion */ strcpy(parameter_names[2].name_a1, "Linear coefficient:"); strcpy(parameter_names[2].name_a2, "Quadratic coefficient:"); strcpy(parameter_names[2].name_a3, "Cubic coefficient:"); strcpy(parameter_names[2].name_a4, "Quartic coefficient:"); strcpy(parameter_names[2].name_a5, "unused"); strcpy(parameter_names[2].name_a6, "unused"); strcpy(parameter_names[2].name_a7, "unused"); strcpy(parameter_names[2].name_a8, "unused"); /* Parameter names for Phi(phi) distortion */ strcpy(parameter_names[3].name_a1, "Amplitude 1:"); strcpy(parameter_names[3].name_a2, "Frequency 1:"); strcpy(parameter_names[3].name_a3, "Amplitude 2:"); strcpy(parameter_names[3].name_a4, "Frequency 2"); strcpy(parameter_names[3].name_a5, "unused"); strcpy(parameter_names[3].name_a6, "unused"); strcpy(parameter_names[3].name_a7, "unused"); strcpy(parameter_names[3].name_a8, "unused"); /* Parameter names for R(r)Phi(phi) distortion */ strcpy(parameter_names[4].name_a1, "Linear coefficient:"); strcpy(parameter_names[4].name_a2, "Quadratic coefficient:"); strcpy(parameter_names[4].name_a3, "Cubic coefficient:"); strcpy(parameter_names[4].name_a4, "Quartic coefficient:"); strcpy(parameter_names[4].name_a5, "Amplitude 1:"); strcpy(parameter_names[4].name_a6, "Frequency 1:"); strcpy(parameter_names[4].name_a7, "Amplitude 2:"); strcpy(parameter_names[4].name_a8, "Frequency 2"); /* Parameter names for R(r)R(phi) distortion */ strcpy(parameter_names[5].name_a1, "Linear coefficient:"); strcpy(parameter_names[5].name_a2, "Quadratic coefficient:"); strcpy(parameter_names[5].name_a3, "Cubic coefficient:"); strcpy(parameter_names[5].name_a4, "Quartic coefficient:"); strcpy(parameter_names[5].name_a5, "Amplitude 1:"); strcpy(parameter_names[5].name_a6, "Frequency 1:"); strcpy(parameter_names[5].name_a7, "Amplitude 2:"); strcpy(parameter_names[5].name_a8, "Frequency 2"); /* Parameter names for Cosines distortion */ strcpy(parameter_names[6].name_a1, "x-Amplitude:"); strcpy(parameter_names[6].name_a2, "y-Amplitude:"); strcpy(parameter_names[6].name_a3, "x-Frequency #1:"); strcpy(parameter_names[6].name_a4, "x-Frequency #2:"); strcpy(parameter_names[6].name_a5, "y-Frequency #1:"); strcpy(parameter_names[6].name_a6, "y-Frequency #2:"); strcpy(parameter_names[6].name_a7, "unused:"); strcpy(parameter_names[6].name_a8, "unused"); /* Parameter names for Gauss distortion */ strcpy(parameter_names[7].name_a1, "x-Strength:"); strcpy(parameter_names[7].name_a2, "y-Strength:"); strcpy(parameter_names[7].name_a3, "x-Offset:"); strcpy(parameter_names[7].name_a4, "y-Offset:"); strcpy(parameter_names[7].name_a5, "x-Deviation:"); strcpy(parameter_names[7].name_a6, "y-Deviation:"); strcpy(parameter_names[7].name_a7, "unused:"); strcpy(parameter_names[7].name_a8, "unused"); /* this paragraph initializes the letterings */ strcpy(parameter_values.lettering01, parameter_names[0].name_a1); strcpy(parameter_values.lettering02, parameter_names[0].name_a2); strcpy(parameter_values.lettering03, parameter_names[0].name_a3); strcpy(parameter_values.lettering04, parameter_names[0].name_a4); strcpy(parameter_values.lettering05, parameter_names[0].name_a5); strcpy(parameter_values.lettering06, parameter_names[0].name_a6); strcpy(parameter_values.lettering07, parameter_names[0].name_a7); strcpy(parameter_values.lettering08, parameter_names[0].name_a8); /* This section defines the 'effects' parameters */ SET_EFFECTS_PARAMS(FUNCTION_R_r, 0, 0.0, 0.0, 0.0, -3.5, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r, 1, -0.2, 0.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r, 2, 0.45, -0.4, -0.5, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r, 3, -0.25, -0.5, 0.0, -4.5, 0.0, 0.0, 0.0, 0.0, TRUE, 0.3, 0.01); SET_EFFECTS_PARAMS(FUNCTION_R_r, 4, 1.6, -2.5, -3.7, -1.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r, 5, 1.8, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, TRUE, 0.0, 1.0); SET_EFFECTS_PARAMS(FUNCTION_R_r, 6, -6.0, 4.0, -10.0, 0.0, 0.0, 0.0, 0.0, 0.0, TRUE, 0.0, 0.7); SET_EFFECTS_PARAMS(FUNCTION_R_r, 7, 0.15, 0.2, 5.0, -1.3, 0.0, 0.0, 0.0, 0.0, TRUE, 0.2, 1.0); SET_EFFECTS_PARAMS(FUNCTION_R_r, 8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_phi, 0, -0.65, 0.35, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_phi, 1, 0.1, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_phi, 2, 0.2, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_phi, 3, 0.2, 3.0, 0.5, 2.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_phi, 4, 0.2, 3.0, 0.5, 2.0, 0.0, 0.0, 0.0, 0.0, TRUE, 0.0, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_phi, 5, -1.0, -7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_phi, 6, 0.7, -0.85, -0.25, -0.4, 0.0, 0.0, 0.0, 0.0, TRUE, 0.0, 1.0); SET_EFFECTS_PARAMS(FUNCTION_R_phi, 7, 0.0, 0.0, 10.0, -10.0, 0.0, 0.0, 0.0, 0.0, TRUE, 0.0, 0.7); SET_EFFECTS_PARAMS(FUNCTION_R_phi, 8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Phi_r, 0, 1.3, 0.9, -10.0, -10.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Phi_r, 1, 1.5, 0.5, -4.2, -6.7, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Phi_r, 2, -2.1, 1.0, 2.45, 5.8, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Phi_r, 3, -1.9, 1.0, 1.0, 6.0, 0.0, 0.0, 0.0, 0.0, TRUE, 0.2, 1.0); SET_EFFECTS_PARAMS(FUNCTION_Phi_r, 4, -4.0, 10.0, 10.0, 10.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Phi_r, 5, 0.6, 3.0, 10.0, 10.0, 0.0, 0.0, 0.0, 0.0, TRUE, 0.25, 0.01); SET_EFFECTS_PARAMS(FUNCTION_Phi_r, 6, 0.0, 0.0, -1.85, -2.45, 0.0, 0.0, 0.0, 0.0, TRUE, 0.4, 0.01); SET_EFFECTS_PARAMS(FUNCTION_Phi_r, 7, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, TRUE, 0.4, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Phi_r, 8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Phi_phi, 0, 0.8, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Phi_phi, 1, -0.3, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Phi_phi, 2, -0.3, 10.0, 0.9, 8.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Phi_phi, 3, -7.0, 10.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, TRUE, 0.0, 1.0); SET_EFFECTS_PARAMS(FUNCTION_Phi_phi, 4, 1.0, 8.0, -1.0, 4.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Phi_phi, 5, -6.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, TRUE, 0.25, 0.4); SET_EFFECTS_PARAMS(FUNCTION_Phi_phi, 6, -5.0, 5.0, 10.0, 1.0, 0.0, 0.0, 0.0, 0.0, TRUE, 0.25, 0.4); SET_EFFECTS_PARAMS(FUNCTION_Phi_phi, 7, -0.5, 3.0, -1.0, 1.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Phi_phi, 8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r_Phi_phi, 0, 1.0, 0.0, 0.0, 0.0, 0.8, 1.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r_Phi_phi, 1, 0.6, 0.0, 0.0, 0.0, -0.3, 10.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r_Phi_phi, 2, 0.3, -0.25, -2.5, 2.4, -0.3, 10.0, 0.9, 8.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r_Phi_phi, 3, -0.05, 0.0, 0.0, 0.0, -7.0, 10.0, 2.0, 1.0, TRUE, 0.0, 1.0); SET_EFFECTS_PARAMS(FUNCTION_R_r_Phi_phi, 4, 1.85, -3.9, 0.0, 0.0, 1.0, 8.0, -1.0, 4.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r_Phi_phi, 5, 0.1, 0.0, 0.0, 0.0, -6.0, 4.0, 0.0, 0.0, TRUE, 0.25, 0.4); SET_EFFECTS_PARAMS(FUNCTION_R_r_Phi_phi, 6, 0.3, -0.35, 0.4, -2.8, -5.0, 5.0, 10.0, 1.0, TRUE, 0.25, 0.4); SET_EFFECTS_PARAMS(FUNCTION_R_r_Phi_phi, 7, -2.6, -0.6, -3.1, 10.0, -0.5, 3.0, -1.0, 1.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r_Phi_phi, 8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r_R_phi, 0, 0.0, 2.1, -0.5, 10.0 ,-0.65, 0.35, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r_R_phi, 1, 2.5, 0.0, 10.0, 6.0, 0.1, 4.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r_R_phi, 2, 0.75, -6.5, -2.6, 5.6, 0.2, 6.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r_R_phi, 3, 0.4, 1.0, 0.7, 0.7, 0.2, 3.0, 0.5, 2.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r_R_phi, 4, -1.0, -1.4, 1.3, 1.3, 0.2, 3.0, 0.5, 2.0, TRUE, 0.0, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r_R_phi, 5, 0.1, 0.4, -1.1, 0.1, -1.0, -7.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_R_r_R_phi, 6, -10.0, -10.0, -10.0, -10.0, 0.7, -1.0, -0.25, 3.0, TRUE, 0.0, 1.0); SET_EFFECTS_PARAMS(FUNCTION_R_r_R_phi, 7, 0.1, 0.35, -1.7, -2.3, 0.0, 0.0, 10.0, -10.0, TRUE, 0.0, 0.7); SET_EFFECTS_PARAMS(FUNCTION_R_r_R_phi, 8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Cosines, 0, 0.8, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Cosines, 1, 2.75, -2.75, 3.0, 0.0, -3.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Cosines, 2, 0.8, -0.8, 1.0, -1.6, -1.0, -1.4, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Cosines, 3, -0.1, -2.0, 1.0, -0.7, -10.0, -1.4, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Cosines, 4, -0.2, -2.0, 1.0, -10.0, 0.25, 6.7, 0.0, 0.0, TRUE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Cosines, 5, -6.2, 6.6, -3.8, -1.4, 2.0, 1.2, 0.0, 0.0, TRUE, 0.15, 1.0); SET_EFFECTS_PARAMS(FUNCTION_Cosines, 6, -6.2, 6.6, -3.8, -1.4, 2.0, 1.2, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Cosines, 7, 10.0, 10.0, -1.7, -1.7, 2.1, 2.1, 0.0, 0.0, TRUE, 0.3, 0.6); SET_EFFECTS_PARAMS(FUNCTION_Cosines, 8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Gauss, 0, 4.0, 0.0, 0.0, 0.0, -9.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Gauss, 1, 4.0, 4.0, 0.0, 0.0, -9.0, -9.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Gauss, 2, 4.0, 4.0, 0.0, 0.0, -9.0, -9.0, 0.0, 0.0, TRUE, 0.0, 1.0); SET_EFFECTS_PARAMS(FUNCTION_Gauss, 3, 0.0, -2.4, 0.0, -3.0, 0.0, 0.0, 0.0, 0.0, FALSE, 0.5, 0.2); SET_EFFECTS_PARAMS(FUNCTION_Gauss, 4, 2.3, -3.4, 0.0, -3.0, -9.0, 0.2, 0.0, 0.0, TRUE, 0.0, 1.0); SET_EFFECTS_PARAMS(FUNCTION_Gauss, 5, 10.0, -10.0, 4.0, -3.0, -6.0, 5.6, 0.0, 0.0, TRUE, 0.05, 0.5); SET_EFFECTS_PARAMS(FUNCTION_Gauss, 6, 5.25, 0.0, -10.0, 0.0, 0.0, 0.0, 0.0, 0.0, TRUE, 0.25, 1.0); SET_EFFECTS_PARAMS(FUNCTION_Gauss, 7, -10.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, TRUE, 0.05, 1.0); SET_EFFECTS_PARAMS(FUNCTION_Gauss, 8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.5, 0.2); switch (run_mode) { case GIMP_RUN_INTERACTIVE: /* Possibly retrieve data */ gimp_get_data(PluginResource, ¶meter_values); /* Create the preview */ create_preview(drawable); /* First acquire information with a dialog */ if(! user_dialog ()) return; break; case GIMP_RUN_NONINTERACTIVE: /* Make sure all the arguments are there! */ if(nparams != N_PARAMETERS) status = GIMP_PDB_CALLING_ERROR; if(status == GIMP_PDB_SUCCESS) { parameter_values.a1 = param[3].data.d_float; parameter_values.a2 = param[4].data.d_float; parameter_values.a3 = param[5].data.d_float; parameter_values.a4 = param[6].data.d_float; parameter_values.a5 = param[7].data.d_float; parameter_values.a6 = param[8].data.d_float; parameter_values.a7 = param[9].data.d_float; parameter_values.a8 = param[10].data.d_float; parameter_values.use_cutoff = param[11].data.d_int32; parameter_values.r = param[12].data.d_float; parameter_values.dr = param[13].data.d_float; parameter_values.current_function = param[14].data.d_int32; } break; case GIMP_RUN_WITH_LAST_VALS: /* Possibly retrieve data */ gimp_get_data(PluginResource, ¶meter_values); break; default: break; } /* Make sure that the drawable is gray or RGB color */ if(gimp_drawable_is_rgb(drawable->id) || gimp_drawable_is_gray(drawable->id)) { if(do_action == 0) gimp_progress_init(PluginName); /* set the tile cache size */ gimp_tile_cache_ntiles(2 * (MAX(drawable->width, drawable->height) / gimp_tile_width () + 1)); if(do_action == 0) image_action(drawable, parameter_values); if(run_mode != GIMP_RUN_NONINTERACTIVE) gimp_displays_flush(); /* Store parameter data */ if(run_mode == GIMP_RUN_INTERACTIVE) gimp_set_data(PluginResource, ¶meter_values, sizeof(Parameters)); } else { status = GIMP_PDB_EXECUTION_ERROR; } values[0].data.d_status = status; gimp_drawable_detach(drawable); } /******************************************************************************/ /* Dialog creation functions */ /******************************************************************************/ /* create_base_dialog() creates the dialog window and the action area. */ static void create_base_dialog(void) { dtd.argc = 1; dtd.argv = g_new(gchar *, 1); dtd.argv[0] = g_strdup(PluginName); gtk_init(&dtd.argc, &dtd.argv); gtk_rc_parse(gimp_gtkrc ()); dtd.dlg = gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(dtd.dlg), PluginName); gtk_window_position(GTK_WINDOW(dtd.dlg), GTK_WIN_POS_MOUSE); gtk_signal_connect(GTK_OBJECT(dtd.dlg), "destroy", (GtkSignalFunc)close_callback, NULL); /* Action area */ dtd.ok_button = gtk_button_new_with_label("OK"); GTK_WIDGET_SET_FLAGS(dtd.ok_button, GTK_CAN_DEFAULT); gtk_signal_connect(GTK_OBJECT (dtd.ok_button), "clicked", (GtkSignalFunc) ok_callback, GTK_OBJECT(dtd.dlg)); gtk_box_pack_start(GTK_BOX (GTK_DIALOG (dtd.dlg)->action_area), dtd.ok_button, TRUE, TRUE, 0); gtk_widget_grab_default(dtd.ok_button); gtk_widget_show(dtd.ok_button); dtd.cancel_button = gtk_button_new_with_label("Cancel"); GTK_WIDGET_SET_FLAGS(dtd.cancel_button, GTK_CAN_DEFAULT); gtk_signal_connect_object(GTK_OBJECT(dtd.cancel_button), "clicked", (GtkSignalFunc)cancel_callback, GTK_OBJECT(dtd.dlg)); gtk_box_pack_start(GTK_BOX (GTK_DIALOG (dtd.dlg)->action_area), dtd.cancel_button, TRUE, TRUE, 0); gtk_widget_show(dtd.cancel_button); } /* Not really surprisingly this functon creates a slider and a label. */ /* The widget returned is the GtkObject *data, NOT the slider widget!!! */ static ObjectAndLabel create_slider_with_label(gchar *text, GtkWidget *container, GtkSignalFunc callback_func, gfloat initial_value, gfloat min_value, gfloat max_value) { GtkObject *data; GtkWidget *label; GtkWidget *slider_field; GtkWidget *slider_widget; ObjectAndLabel ret; slider_field = gtk_hbox_new(FALSE, 1); gtk_container_border_width(GTK_CONTAINER(slider_field), 2); gtk_box_pack_start(GTK_BOX(container), slider_field, TRUE, TRUE, 0); label = gtk_label_new(text); gtk_widget_set_usize(label, 140, 0); gtk_box_pack_start(GTK_BOX(slider_field), label, TRUE, TRUE, 0); gtk_misc_set_alignment(GTK_MISC(GTK_LABEL(label)), 0.0, 1.0); gtk_widget_show(label); data = gtk_adjustment_new(initial_value, min_value, max_value, 0.01, 0.01, 0); slider_widget = gtk_hscale_new(GTK_ADJUSTMENT(data)); gtk_box_pack_start(GTK_BOX(slider_field), slider_widget, TRUE, TRUE, 0); gtk_widget_set_usize(slider_widget, 300, 0); gtk_scale_set_value_pos(GTK_SCALE(slider_widget), GTK_POS_TOP); gtk_scale_set_digits(GTK_SCALE(slider_widget), 2); gtk_range_set_update_policy(GTK_RANGE(slider_widget), GTK_UPDATE_DELAYED); gtk_signal_connect(GTK_OBJECT(data), "value_changed", (GtkSignalFunc)callback_func, &initial_value); gtk_widget_show(slider_widget); gtk_widget_show(slider_field); ret.object = (GtkWidget *)data; ret.label = (GtkLabel *)label; return(ret); } static void create_functions_menu(GtkWidget *container) { GtkWidget *menu_field; GtkWidget *label; GtkWidget *menu; GtkWidget *menuitem; GtkWidget *chooser; GtkWidget *current_item; gint dummy; /* current_item must be initialized in order to prevent warnings */ current_item = NULL; menu_field = gtk_hbox_new(FALSE, 1); gtk_container_border_width(GTK_CONTAINER(menu_field), 2); gtk_box_pack_start(GTK_BOX(container), menu_field, TRUE, TRUE, 0); label = gtk_label_new("Functions:"); gtk_widget_set_usize(label, 70, 0); gtk_box_pack_start(GTK_BOX(menu_field), label, TRUE, TRUE, 0); gtk_widget_show(label); chooser = gtk_option_menu_new(); gtk_box_pack_start(GTK_BOX(menu_field), chooser, TRUE, TRUE, 0); gtk_widget_set_usize(chooser, 180, 0); menu = gtk_menu_new(); menuitem = gtk_menu_item_new_with_label("R(r) - 4th order poly"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", (GtkSignalFunc)function01_callback, &dummy); gtk_widget_show(menuitem); if(parameter_values.current_function == FUNCTION_R_r) current_item = menuitem; menuitem = gtk_menu_item_new_with_label("R(phi) - cosine"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", (GtkSignalFunc)function02_callback, &dummy); gtk_widget_show(menuitem); if(parameter_values.current_function == FUNCTION_R_phi) current_item = menuitem; menuitem = gtk_menu_item_new_with_label("Phi(r) - 4th order poly"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", (GtkSignalFunc)function03_callback, &dummy); gtk_widget_show(menuitem); if(parameter_values.current_function == FUNCTION_Phi_r) current_item = menuitem; menuitem = gtk_menu_item_new_with_label("Phi(phi) - cosine"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", (GtkSignalFunc)function04_callback, &dummy); gtk_widget_show(menuitem); if(parameter_values.current_function == FUNCTION_Phi_phi) current_item = menuitem; menuitem = gtk_menu_item_new_with_label("R(r)Phi(phi)"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", (GtkSignalFunc)function05_callback, &dummy); gtk_widget_show(menuitem); if(parameter_values.current_function == FUNCTION_R_r_Phi_phi) current_item = menuitem; menuitem = gtk_menu_item_new_with_label("R(r)R(phi)"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", (GtkSignalFunc)function06_callback, &dummy); gtk_widget_show(menuitem); if(parameter_values.current_function == FUNCTION_R_r_R_phi) current_item = menuitem; menuitem = gtk_menu_item_new_with_label("Cosines"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", (GtkSignalFunc)function07_callback, &dummy); gtk_widget_show(menuitem); if(parameter_values.current_function == FUNCTION_Cosines) current_item = menuitem; menuitem = gtk_menu_item_new_with_label("Gauss"); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_signal_connect(GTK_OBJECT(menuitem), "activate", (GtkSignalFunc)function08_callback, &dummy); gtk_widget_show(menuitem); if(parameter_values.current_function == FUNCTION_Gauss) current_item = menuitem; gtk_menu_set_active(GTK_MENU(menu), (guint)parameter_values.current_function); gtk_option_menu_set_menu(GTK_OPTION_MENU(chooser), menu); gtk_widget_show(chooser); gtk_widget_show(menu_field); } static void create_effects_menu(GtkWidget *container) { GtkWidget *menu_field; GtkWidget *label; GtkWidget *button; gint dummy; menu_field = gtk_hbox_new(FALSE, 1); gtk_container_border_width(GTK_CONTAINER(menu_field), 2); gtk_box_pack_start(GTK_BOX(container), menu_field, TRUE, TRUE, 0); label = gtk_label_new("Effects:"); gtk_widget_set_usize(label, 70, 0); gtk_box_pack_start(GTK_BOX(menu_field), label, TRUE, TRUE, 0); gtk_widget_show(label); button = gtk_button_new_with_label("1"); gtk_box_pack_start(GTK_BOX(menu_field), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "pressed", (GtkSignalFunc)effect01_callback, &dummy); gtk_widget_show(button); button = gtk_button_new_with_label("2"); gtk_box_pack_start(GTK_BOX(menu_field), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "pressed", (GtkSignalFunc)effect02_callback, &dummy); gtk_widget_show(button); button = gtk_button_new_with_label("3"); gtk_box_pack_start(GTK_BOX(menu_field), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "pressed", (GtkSignalFunc)effect03_callback, &dummy); gtk_widget_show(button); button = gtk_button_new_with_label("4"); gtk_box_pack_start(GTK_BOX(menu_field), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "pressed", (GtkSignalFunc)effect04_callback, &dummy); gtk_widget_show(button); button = gtk_button_new_with_label("5"); gtk_box_pack_start(GTK_BOX(menu_field), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "pressed", (GtkSignalFunc)effect05_callback, &dummy); gtk_widget_show(button); button = gtk_button_new_with_label("6"); gtk_box_pack_start(GTK_BOX(menu_field), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "pressed", (GtkSignalFunc)effect06_callback, &dummy); gtk_widget_show(button); button = gtk_button_new_with_label("7"); gtk_box_pack_start(GTK_BOX(menu_field), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "pressed", (GtkSignalFunc)effect07_callback, &dummy); gtk_widget_show(button); button = gtk_button_new_with_label("8"); gtk_box_pack_start(GTK_BOX(menu_field), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "pressed", (GtkSignalFunc)effect08_callback, &dummy); gtk_widget_show(button); button = gtk_button_new_with_label("R"); gtk_box_pack_start(GTK_BOX(menu_field), button, TRUE, TRUE, 0); gtk_signal_connect(GTK_OBJECT(button), "pressed", (GtkSignalFunc)effect09_callback, &dummy); gtk_widget_show(button); gtk_widget_show(menu_field); } /* This function creates the panel for the cutoff function parameters. */ static void create_cutoff_panel(GtkWidget *container) { GtkObject *data; GtkWidget *label; GtkWidget *slider; GtkWidget *toggle; gfloat dummy; gint int_dummy; toggle = gtk_check_button_new_with_label("Use cutoff"); widget_data.toggle01 = toggle; gtk_box_pack_start(GTK_BOX(container), toggle, FALSE, FALSE, 0); gtk_signal_connect(GTK_OBJECT(toggle), "toggled", (GtkSignalFunc)use_cutoff_callback, &int_dummy); gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle), parameter_values.use_cutoff); gtk_widget_show (toggle); label = gtk_label_new("r"); gtk_box_pack_start(GTK_BOX(container), label, TRUE, TRUE, 0); gtk_misc_set_alignment(GTK_MISC(GTK_LABEL(label)), 0.8, 0.5); gtk_widget_show(label); data = gtk_adjustment_new(parameter_values.r, 0.0, 1.0, 0.01, 0.01, 0); widget_data.slider09 = (GtkWidget *)data; slider = gtk_hscale_new(GTK_ADJUSTMENT(data)); gtk_box_pack_start(GTK_BOX(container), slider, TRUE, TRUE, 0); gtk_widget_set_usize(slider, 100, 0); gtk_scale_set_value_pos(GTK_SCALE(slider), GTK_POS_TOP); gtk_scale_set_digits(GTK_SCALE(slider), 2); gtk_range_set_update_policy(GTK_RANGE(slider), GTK_UPDATE_DELAYED); gtk_signal_connect(GTK_OBJECT(data), "value_changed", (GtkSignalFunc)r_callback, &dummy); gtk_widget_show(slider); label = gtk_label_new("dr"); gtk_box_pack_start(GTK_BOX(container), label, TRUE, TRUE, 0); gtk_misc_set_alignment(GTK_MISC(GTK_LABEL(label)), 0.8, 0.5); gtk_widget_show(label); data = gtk_adjustment_new(parameter_values.dr, 0.01, 1.0, 0.01, 0.01, 0); widget_data.slider10 = (GtkWidget *)data; slider = gtk_hscale_new(GTK_ADJUSTMENT(data)); gtk_box_pack_start(GTK_BOX(container), slider, TRUE, TRUE, 0); gtk_widget_set_usize(slider, 100, 0); gtk_scale_set_value_pos(GTK_SCALE(slider), GTK_POS_TOP); gtk_scale_set_digits(GTK_SCALE(slider), 2); gtk_range_set_update_policy(GTK_RANGE(slider), GTK_UPDATE_DELAYED); gtk_signal_connect(GTK_OBJECT(data), "value_changed", (GtkSignalFunc)dr_callback, &dummy); gtk_widget_show(slider); } /* This function creates a preview. It should be called only once. */ /* This function writes all data to a global PreviewData preview_data */ static void create_preview(GimpDrawable *drawable) { gint i, j; gint x0, y0; gint x1, y1, x2, y2; gint image_width, image_height; guchar *image_bytes; gint image_bpp; gint offset; gint count; gfloat delta_pixel; GimpPixelRgn image_rgn; gimp_drawable_mask_bounds(drawable->id, &x1, &y1, &x2, &y2); image_width = (x2 - x1); image_height = (y2 - y1); image_bpp = drawable->bpp; image_bytes = (guchar *)malloc(image_bpp*image_width); if(image_width > image_height) { preview_data.scale = (gfloat)image_width/(gfloat)preview_width; preview_data.width = preview_width; preview_data.height = (gfloat)(image_height)/(preview_data.scale); x0 = 0; y0 = (preview_height - preview_data.height)/2; } else { preview_data.scale = (gfloat)image_height/(gfloat)preview_height; preview_data.height = preview_height; preview_data.width = (gfloat)(image_width)/(preview_data.scale); x0 = (preview_width - preview_data.width)/2; y0 = 0; } preview_data.bpp = 3; preview_data.bits = (guchar *)malloc(preview_data.bpp*preview_width*preview_height); /* Clear the preview area */ count = 0; for(i = 0; i < preview_data.bpp*preview_width*preview_height; i++) preview_data.bits[count++] = 0; /* Copy a thumbnail of the original image to the preview image. */ gimp_pixel_rgn_init(&image_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); for(j = 0; j < preview_data.height; j++) { offset = preview_data.bpp*((y0 + j)*preview_width + x0); count = 0; delta_pixel = 0.0; gimp_pixel_rgn_get_row(&image_rgn, image_bytes, x1, y1 + (int)(preview_data.scale*(gfloat)j), image_width); for(i = 0; i < preview_data.width; i++) { switch(image_bpp) { case 4: preview_data.bits[offset++] = image_bytes[count++]; preview_data.bits[offset++] = image_bytes[count++]; preview_data.bits[offset++] = image_bytes[count++]; delta_pixel += preview_data.scale; count = 4*(int)delta_pixel; break; case 3: preview_data.bits[offset++] = image_bytes[count++]; preview_data.bits[offset++] = image_bytes[count++]; preview_data.bits[offset++] = image_bytes[count++]; delta_pixel += preview_data.scale; count = 3*(int)delta_pixel; break; case 2: preview_data.bits[offset++] = image_bytes[count]; preview_data.bits[offset++] = image_bytes[count]; preview_data.bits[offset++] = image_bytes[count]; delta_pixel += preview_data.scale; count = 2*(int)delta_pixel; break; case 1: preview_data.bits[offset++] = image_bytes[count]; preview_data.bits[offset++] = image_bytes[count]; preview_data.bits[offset++] = image_bytes[count]; delta_pixel += preview_data.scale; count = (int)delta_pixel; break; } } } } /* This function re-calculates the preview image and displays it */ static void update_preview(GtkWidget *preview) { guchar *dest; gint i, j; gfloat u, v; gint count; if(do_update_preview != 1) return; dest = (guchar *)malloc(3*preview_width); /* Distort and display the preview */ for(j = 0; j < preview_height; j++) { count = 0; for(i = 0; i < preview_width; i++) { calculate_distortion_function(i, j, preview_width, preview_height, &u, &v); if((u >= 0) && (u < preview_width) && (v >= 0) && (v < preview_height)) { dest[count] = preview_data.bits[3*((int)v*preview_width + (int)u)]; count++; dest[count] = preview_data.bits[3*((int)v*preview_width + (int)u)+1]; count++; dest[count] = preview_data.bits[3*((int)v*preview_width + (int)u)+2]; count++; } else { dest[count] = 0; count++; dest[count] = 0; count++; dest[count] = 0; count++; } } gtk_preview_draw_row(GTK_PREVIEW(preview), dest, 0, j, preview_width); } gtk_widget_draw(preview, NULL); free(dest); } /* This function creates the complete user dialog */ static gint user_dialog() { GtkWidget *frame; GtkWidget *main_box; GtkWidget *north_box; GtkWidget *south_box; GtkWidget *west_box; GtkWidget *preview_box; GtkWidget *parameter_box; GtkWidget *cutoff_box; GtkWidget *preview_frame; GtkWidget *preview_display; GtkWidget *functions_frame; GtkWidget *functions_box; ObjectAndLabel oal; /* Create a basic dialog window */ create_base_dialog(); /* The main box -- contains the north and south box */ main_box = gtk_vbox_new(FALSE, 1); gtk_container_border_width(GTK_CONTAINER(main_box), 15); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dtd.dlg)->vbox), main_box, TRUE, TRUE, 0); /* Add the north box */ north_box = gtk_hbox_new(FALSE, 1); gtk_box_pack_start(GTK_BOX(main_box), north_box, TRUE, TRUE, 0); west_box = gtk_vbox_new(FALSE, 0); gtk_container_border_width(GTK_CONTAINER(west_box), 0); gtk_container_add(GTK_CONTAINER(north_box), west_box); /* Add the preview display */ preview_frame = gtk_frame_new("Preview image"); gtk_frame_set_shadow_type(GTK_FRAME(preview_frame), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(west_box), preview_frame, TRUE, TRUE, 0); preview_box = gtk_vbox_new(FALSE, 0); gtk_container_border_width(GTK_CONTAINER(preview_box), 10); gtk_container_add(GTK_CONTAINER(preview_frame), preview_box); frame = gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); gtk_box_pack_start(GTK_BOX(preview_box), frame, TRUE, TRUE, 0); preview_display = gtk_preview_new(GTK_PREVIEW_COLOR); gtk_preview_size(GTK_PREVIEW(preview_display), preview_width, preview_height); gtk_container_add(GTK_CONTAINER(frame), preview_display); preview_data.display = preview_display; update_preview(preview_data.display); /* Add the functions/effects frame */ functions_frame = gtk_frame_new("Functions / Effects"); gtk_frame_set_shadow_type(GTK_FRAME(functions_frame), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(west_box), functions_frame, FALSE, FALSE, 0); functions_box = gtk_vbox_new(FALSE, 0); gtk_container_border_width(GTK_CONTAINER(functions_box), 10); gtk_container_add(GTK_CONTAINER(functions_frame), functions_box); /* Add a test object to the functions/effects box (to be replaced.*/ create_functions_menu(functions_box); create_effects_menu(functions_box); gtk_widget_show(functions_box); gtk_widget_show(functions_frame); gtk_widget_show(preview_display); gtk_widget_show(frame); gtk_widget_show(preview_frame); gtk_widget_show(preview_box); gtk_widget_show(west_box); /* Create the parameter control box */ frame = gtk_frame_new("Parameter settings"); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(north_box), frame, TRUE, TRUE, 0); parameter_box = gtk_vbox_new(FALSE, 5); gtk_container_add(GTK_CONTAINER(frame), parameter_box); oal = create_slider_with_label(parameter_values.lettering01, parameter_box, (GtkSignalFunc)a1_callback, parameter_values.a1, -10.0, 10.0); widget_data.slider01 = oal.object; widget_data.label01 = oal.label; oal = create_slider_with_label(parameter_values.lettering02, parameter_box, (GtkSignalFunc)a2_callback, parameter_values.a2, -10.0, 10.0); widget_data.slider02 = oal.object; widget_data.label02 = oal.label; oal = create_slider_with_label(parameter_values.lettering03, parameter_box, (GtkSignalFunc)a3_callback, parameter_values.a3, -10.0, 10.0); widget_data.slider03 = oal.object; widget_data.label03 = oal.label; oal = create_slider_with_label(parameter_values.lettering04, parameter_box, (GtkSignalFunc)a4_callback, parameter_values.a4, -10.0, 10.0); widget_data.slider04 = oal.object; widget_data.label04 = oal.label; oal = create_slider_with_label(parameter_values.lettering05, parameter_box, (GtkSignalFunc)a5_callback, parameter_values.a5, -10.0, 10.0); widget_data.slider05 = oal.object; widget_data.label05 = oal.label; oal = create_slider_with_label(parameter_values.lettering06, parameter_box, (GtkSignalFunc)a6_callback, parameter_values.a6, -10.0, 10.0); widget_data.slider06 = oal.object; widget_data.label06 = oal.label; oal = create_slider_with_label(parameter_values.lettering07, parameter_box, (GtkSignalFunc)a7_callback, parameter_values.a7, -10.0, 10.0); widget_data.slider07 = oal.object; widget_data.label07 = oal.label; oal = create_slider_with_label(parameter_values.lettering08, parameter_box, (GtkSignalFunc)a8_callback, parameter_values.a8, -10.0, 10.0); widget_data.slider08 = oal.object; widget_data.label08 = oal.label; gtk_widget_show(parameter_box); gtk_widget_show(frame); gtk_widget_show(north_box); /* Create the south box (contains the cutoff panel)*/ south_box = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(main_box), south_box, TRUE, TRUE, 0); frame = gtk_frame_new("Cutoff function"); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(south_box), frame, TRUE, TRUE, 0); cutoff_box = gtk_hbox_new(FALSE, 5); gtk_container_border_width(GTK_CONTAINER(cutoff_box), 10); gtk_container_add(GTK_CONTAINER(frame), cutoff_box); create_cutoff_panel(cutoff_box); gtk_widget_show(cutoff_box); gtk_widget_show(frame); gtk_widget_show(south_box); gtk_widget_show(main_box); gtk_widget_show(dtd.dlg); gtk_main (); gdk_flush (); return 1; } /* Modify the dialog controls such that they resemble the actual parameter values. The parameters are modified by selecting an effect. */ static void update_dialog(void) { GtkAdjustment *adjustment; adjustment = (GtkAdjustment *)widget_data.slider01; adjustment->value = parameter_values.a1; gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); gtk_label_set(widget_data.label01, parameter_values.lettering01); adjustment = (GtkAdjustment *)widget_data.slider02; adjustment->value = parameter_values.a2; gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); gtk_label_set(widget_data.label02, parameter_values.lettering02); adjustment = (GtkAdjustment *)widget_data.slider03; adjustment->value = parameter_values.a3; gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); gtk_label_set(widget_data.label03, parameter_values.lettering03); adjustment = (GtkAdjustment *)widget_data.slider04; adjustment->value = parameter_values.a4; gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); gtk_label_set(widget_data.label04, parameter_values.lettering04); adjustment = (GtkAdjustment *)widget_data.slider05; adjustment->value = parameter_values.a5; gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); gtk_label_set(widget_data.label05, parameter_values.lettering05); adjustment = (GtkAdjustment *)widget_data.slider06; adjustment->value = parameter_values.a6; gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); gtk_label_set(widget_data.label06, parameter_values.lettering06); adjustment = (GtkAdjustment *)widget_data.slider07; adjustment->value = parameter_values.a7; gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); gtk_label_set(widget_data.label07, parameter_values.lettering07); adjustment = (GtkAdjustment *)widget_data.slider08; adjustment->value = parameter_values.a8; gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); gtk_label_set(widget_data.label08, parameter_values.lettering08); adjustment = (GtkAdjustment *)widget_data.slider09; adjustment->value = parameter_values.r; gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); adjustment = (GtkAdjustment *)widget_data.slider10; adjustment->value = parameter_values.dr; gtk_signal_emit_by_name(GTK_OBJECT(adjustment), "value_changed"); gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(widget_data.toggle01), parameter_values.use_cutoff); } /******************************************************************************/ /* Callback functions */ /******************************************************************************/ static void close_callback(GtkWidget *widget, gpointer data) { gtk_main_quit(); } static void ok_callback(GtkWidget *widget, gpointer data) { gtk_widget_destroy(GTK_WIDGET(data)); } void cancel_callback(GtkWidget *widget, gpointer data) { do_action = -1; gtk_main_quit(); } static void a1_callback(GtkAdjustment *adjustment, gpointer data) { parameter_values.a1 = adjustment->value; update_preview(preview_data.display); } static void a2_callback(GtkAdjustment *adjustment, gpointer data) { parameter_values.a2 = adjustment->value; update_preview(preview_data.display); } static void a3_callback(GtkAdjustment *adjustment, gpointer data) { parameter_values.a3 = adjustment->value; update_preview(preview_data.display); } static void a4_callback(GtkAdjustment *adjustment, gpointer data) { parameter_values.a4 = adjustment->value; update_preview(preview_data.display); } static void a5_callback(GtkAdjustment *adjustment, gpointer data) { parameter_values.a5 = adjustment->value; update_preview(preview_data.display); } static void a6_callback(GtkAdjustment *adjustment, gpointer data) { parameter_values.a6 = adjustment->value; update_preview(preview_data.display); } static void a7_callback(GtkAdjustment *adjustment, gpointer data) { parameter_values.a7 = adjustment->value; update_preview(preview_data.display); } static void a8_callback(GtkAdjustment *adjustment, gpointer data) { parameter_values.a8 = adjustment->value; update_preview(preview_data.display); } static void use_cutoff_callback(GtkWidget *widget, gpointer data) { parameter_values.use_cutoff = 0; if(GTK_TOGGLE_BUTTON(widget)->active) parameter_values.use_cutoff = 1; update_preview(preview_data.display); } static void r_callback(GtkAdjustment *adjustment, gpointer data) { parameter_values.r = adjustment->value; update_preview(preview_data.display); } static void dr_callback(GtkAdjustment *adjustment, gpointer data) { parameter_values.dr = adjustment->value; update_preview(preview_data.display); } static void effect01_callback(GtkWidget *widget, gpointer data) { gint f = parameter_values.current_function; parameter_values.a1 = EffectsParameters[f][0].a1; parameter_values.a2 = EffectsParameters[f][0].a2; parameter_values.a3 = EffectsParameters[f][0].a3; parameter_values.a4 = EffectsParameters[f][0].a4; parameter_values.a5 = EffectsParameters[f][0].a5; parameter_values.a6 = EffectsParameters[f][0].a6; parameter_values.a7 = EffectsParameters[f][0].a7; parameter_values.a8 = EffectsParameters[f][0].a8; parameter_values.use_cutoff = EffectsParameters[f][0].use_cutoff; parameter_values.r = EffectsParameters[f][0].r; parameter_values.dr = EffectsParameters[f][0].dr; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void effect02_callback(GtkWidget *widget, gpointer data) { gint f = parameter_values.current_function; parameter_values.a1 = EffectsParameters[f][1].a1; parameter_values.a2 = EffectsParameters[f][1].a2; parameter_values.a3 = EffectsParameters[f][1].a3; parameter_values.a4 = EffectsParameters[f][1].a4; parameter_values.a5 = EffectsParameters[f][1].a5; parameter_values.a6 = EffectsParameters[f][1].a6; parameter_values.a7 = EffectsParameters[f][1].a7; parameter_values.a8 = EffectsParameters[f][1].a8; parameter_values.use_cutoff = EffectsParameters[f][1].use_cutoff; parameter_values.r = EffectsParameters[f][1].r; parameter_values.dr = EffectsParameters[f][1].dr; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void effect03_callback(GtkWidget *widget, gpointer data) { gint f = parameter_values.current_function; parameter_values.a1 = EffectsParameters[f][2].a1; parameter_values.a2 = EffectsParameters[f][2].a2; parameter_values.a3 = EffectsParameters[f][2].a3; parameter_values.a4 = EffectsParameters[f][2].a4; parameter_values.a5 = EffectsParameters[f][2].a5; parameter_values.a6 = EffectsParameters[f][2].a6; parameter_values.a7 = EffectsParameters[f][2].a7; parameter_values.a8 = EffectsParameters[f][2].a8; parameter_values.use_cutoff = EffectsParameters[f][2].use_cutoff; parameter_values.r = EffectsParameters[f][2].r; parameter_values.dr = EffectsParameters[f][2].dr; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void effect04_callback(GtkWidget *widget, gpointer data) { gint f = parameter_values.current_function; parameter_values.a1 = EffectsParameters[f][3].a1; parameter_values.a2 = EffectsParameters[f][3].a2; parameter_values.a3 = EffectsParameters[f][3].a3; parameter_values.a4 = EffectsParameters[f][3].a4; parameter_values.a5 = EffectsParameters[f][3].a5; parameter_values.a6 = EffectsParameters[f][3].a6; parameter_values.a7 = EffectsParameters[f][3].a7; parameter_values.a8 = EffectsParameters[f][3].a8; parameter_values.use_cutoff = EffectsParameters[f][3].use_cutoff; parameter_values.r = EffectsParameters[f][3].r; parameter_values.dr = EffectsParameters[f][3].dr; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void effect05_callback(GtkWidget *widget, gpointer data) { gint f = parameter_values.current_function; parameter_values.a1 = EffectsParameters[f][4].a1; parameter_values.a2 = EffectsParameters[f][4].a2; parameter_values.a3 = EffectsParameters[f][4].a3; parameter_values.a4 = EffectsParameters[f][4].a4; parameter_values.a5 = EffectsParameters[f][4].a5; parameter_values.a6 = EffectsParameters[f][4].a6; parameter_values.a7 = EffectsParameters[f][4].a7; parameter_values.a8 = EffectsParameters[f][4].a8; parameter_values.use_cutoff = EffectsParameters[f][4].use_cutoff; parameter_values.r = EffectsParameters[f][4].r; parameter_values.dr = EffectsParameters[f][4].dr; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void effect06_callback(GtkWidget *widget, gpointer data) { gint f = parameter_values.current_function; parameter_values.a1 = EffectsParameters[f][5].a1; parameter_values.a2 = EffectsParameters[f][5].a2; parameter_values.a3 = EffectsParameters[f][5].a3; parameter_values.a4 = EffectsParameters[f][5].a4; parameter_values.a5 = EffectsParameters[f][5].a5; parameter_values.a6 = EffectsParameters[f][5].a6; parameter_values.a7 = EffectsParameters[f][5].a7; parameter_values.a8 = EffectsParameters[f][5].a8; parameter_values.use_cutoff = EffectsParameters[f][5].use_cutoff; parameter_values.r = EffectsParameters[f][5].r; parameter_values.dr = EffectsParameters[f][5].dr; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void effect07_callback(GtkWidget *widget, gpointer data) { gint f = parameter_values.current_function; parameter_values.a1 = EffectsParameters[f][6].a1; parameter_values.a2 = EffectsParameters[f][6].a2; parameter_values.a3 = EffectsParameters[f][6].a3; parameter_values.a4 = EffectsParameters[f][6].a4; parameter_values.a5 = EffectsParameters[f][6].a5; parameter_values.a6 = EffectsParameters[f][6].a6; parameter_values.a7 = EffectsParameters[f][6].a7; parameter_values.a8 = EffectsParameters[f][6].a8; parameter_values.use_cutoff = EffectsParameters[f][6].use_cutoff; parameter_values.r = EffectsParameters[f][6].r; parameter_values.dr = EffectsParameters[f][6].dr; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void effect08_callback(GtkWidget *widget, gpointer data) { gint f = parameter_values.current_function; parameter_values.a1 = EffectsParameters[f][7].a1; parameter_values.a2 = EffectsParameters[f][7].a2; parameter_values.a3 = EffectsParameters[f][7].a3; parameter_values.a4 = EffectsParameters[f][7].a4; parameter_values.a5 = EffectsParameters[f][7].a5; parameter_values.a6 = EffectsParameters[f][7].a6; parameter_values.a7 = EffectsParameters[f][7].a7; parameter_values.a8 = EffectsParameters[f][7].a8; parameter_values.use_cutoff = EffectsParameters[f][7].use_cutoff; parameter_values.r = EffectsParameters[f][7].r; parameter_values.dr = EffectsParameters[f][7].dr; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void effect09_callback(GtkWidget *widget, gpointer data) { gint f = parameter_values.current_function; parameter_values.a1 = EffectsParameters[f][8].a1; parameter_values.a2 = EffectsParameters[f][8].a2; parameter_values.a3 = EffectsParameters[f][8].a3; parameter_values.a4 = EffectsParameters[f][8].a4; parameter_values.a5 = EffectsParameters[f][8].a5; parameter_values.a6 = EffectsParameters[f][8].a6; parameter_values.a7 = EffectsParameters[f][8].a7; parameter_values.a8 = EffectsParameters[f][8].a8; parameter_values.use_cutoff = EffectsParameters[f][8].use_cutoff; parameter_values.r = EffectsParameters[f][8].r; parameter_values.dr = EffectsParameters[f][8].dr; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void function01_callback(GtkWidget *widget, gpointer data) { strcpy(parameter_values.lettering01, parameter_names[0].name_a1); strcpy(parameter_values.lettering02, parameter_names[0].name_a2); strcpy(parameter_values.lettering03, parameter_names[0].name_a3); strcpy(parameter_values.lettering04, parameter_names[0].name_a4); strcpy(parameter_values.lettering05, parameter_names[0].name_a5); strcpy(parameter_values.lettering06, parameter_names[0].name_a6); strcpy(parameter_values.lettering07, parameter_names[0].name_a7); strcpy(parameter_values.lettering08, parameter_names[0].name_a8); parameter_values.a1 = 0; parameter_values.a5 = 0; parameter_values.a2 = 0; parameter_values.a6 = 0; parameter_values.a3 = 0; parameter_values.a7 = 0; parameter_values.a4 = 0; parameter_values.a8 = 0; parameter_values.use_cutoff = 0; parameter_values.r = 0.5; parameter_values.dr = 0.2; parameter_values.current_function = FUNCTION_R_r; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void function02_callback(GtkWidget *widget, gpointer data) { strcpy(parameter_values.lettering01, parameter_names[1].name_a1); strcpy(parameter_values.lettering02, parameter_names[1].name_a2); strcpy(parameter_values.lettering03, parameter_names[1].name_a3); strcpy(parameter_values.lettering04, parameter_names[1].name_a4); strcpy(parameter_values.lettering05, parameter_names[1].name_a5); strcpy(parameter_values.lettering06, parameter_names[1].name_a6); strcpy(parameter_values.lettering07, parameter_names[1].name_a7); strcpy(parameter_values.lettering08, parameter_names[1].name_a8); parameter_values.a1 = 0; parameter_values.a5 = 0; parameter_values.a2 = 0; parameter_values.a6 = 0; parameter_values.a3 = 0; parameter_values.a7 = 0; parameter_values.a4 = 0; parameter_values.a8 = 0; parameter_values.use_cutoff = 0; parameter_values.r = 0.5; parameter_values.dr = 0.2; parameter_values.current_function = FUNCTION_R_phi; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void function03_callback(GtkWidget *widget, gpointer data) { strcpy(parameter_values.lettering01, parameter_names[2].name_a1); strcpy(parameter_values.lettering02, parameter_names[2].name_a2); strcpy(parameter_values.lettering03, parameter_names[2].name_a3); strcpy(parameter_values.lettering04, parameter_names[2].name_a4); strcpy(parameter_values.lettering05, parameter_names[2].name_a5); strcpy(parameter_values.lettering06, parameter_names[2].name_a6); strcpy(parameter_values.lettering07, parameter_names[2].name_a7); strcpy(parameter_values.lettering08, parameter_names[2].name_a8); parameter_values.a1 = 0; parameter_values.a5 = 0; parameter_values.a2 = 0; parameter_values.a6 = 0; parameter_values.a3 = 0; parameter_values.a7 = 0; parameter_values.a4 = 0; parameter_values.a8 = 0; parameter_values.use_cutoff = 0; parameter_values.r = 0.5; parameter_values.dr = 0.2; parameter_values.current_function = FUNCTION_Phi_r; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void function04_callback(GtkWidget *widget, gpointer data) { strcpy(parameter_values.lettering01, parameter_names[3].name_a1); strcpy(parameter_values.lettering02, parameter_names[3].name_a2); strcpy(parameter_values.lettering03, parameter_names[3].name_a3); strcpy(parameter_values.lettering04, parameter_names[3].name_a4); strcpy(parameter_values.lettering05, parameter_names[3].name_a5); strcpy(parameter_values.lettering06, parameter_names[3].name_a6); strcpy(parameter_values.lettering07, parameter_names[3].name_a7); strcpy(parameter_values.lettering08, parameter_names[3].name_a8); parameter_values.a1 = 0; parameter_values.a5 = 0; parameter_values.a2 = 0; parameter_values.a6 = 0; parameter_values.a3 = 0; parameter_values.a7 = 0; parameter_values.a4 = 0; parameter_values.a8 = 0; parameter_values.use_cutoff = 0; parameter_values.r = 0.5; parameter_values.dr = 0.2; parameter_values.current_function = FUNCTION_Phi_phi; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void function05_callback(GtkWidget *widget, gpointer data) { strcpy(parameter_values.lettering01, parameter_names[4].name_a1); strcpy(parameter_values.lettering02, parameter_names[4].name_a2); strcpy(parameter_values.lettering03, parameter_names[4].name_a3); strcpy(parameter_values.lettering04, parameter_names[4].name_a4); strcpy(parameter_values.lettering05, parameter_names[4].name_a5); strcpy(parameter_values.lettering06, parameter_names[4].name_a6); strcpy(parameter_values.lettering07, parameter_names[4].name_a7); strcpy(parameter_values.lettering08, parameter_names[4].name_a8); parameter_values.a1 = 0; parameter_values.a5 = 0; parameter_values.a2 = 0; parameter_values.a6 = 0; parameter_values.a3 = 0; parameter_values.a7 = 0; parameter_values.a4 = 0; parameter_values.a8 = 0; parameter_values.use_cutoff = 0; parameter_values.r = 0.5; parameter_values.dr = 0.2; parameter_values.current_function = FUNCTION_R_r_Phi_phi; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void function06_callback(GtkWidget *widget, gpointer data) { strcpy(parameter_values.lettering01, parameter_names[5].name_a1); strcpy(parameter_values.lettering02, parameter_names[5].name_a2); strcpy(parameter_values.lettering03, parameter_names[5].name_a3); strcpy(parameter_values.lettering04, parameter_names[5].name_a4); strcpy(parameter_values.lettering05, parameter_names[5].name_a5); strcpy(parameter_values.lettering06, parameter_names[5].name_a6); strcpy(parameter_values.lettering07, parameter_names[5].name_a7); strcpy(parameter_values.lettering08, parameter_names[5].name_a8); parameter_values.a1 = 0; parameter_values.a5 = 0; parameter_values.a2 = 0; parameter_values.a6 = 0; parameter_values.a3 = 0; parameter_values.a7 = 0; parameter_values.a4 = 0; parameter_values.a8 = 0; parameter_values.use_cutoff = 0; parameter_values.r = 0.5; parameter_values.dr = 0.2; parameter_values.current_function = FUNCTION_R_r_R_phi; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void function07_callback(GtkWidget *widget, gpointer data) { strcpy(parameter_values.lettering01, parameter_names[6].name_a1); strcpy(parameter_values.lettering02, parameter_names[6].name_a2); strcpy(parameter_values.lettering03, parameter_names[6].name_a3); strcpy(parameter_values.lettering04, parameter_names[6].name_a4); strcpy(parameter_values.lettering05, parameter_names[6].name_a5); strcpy(parameter_values.lettering06, parameter_names[6].name_a6); strcpy(parameter_values.lettering07, parameter_names[6].name_a7); strcpy(parameter_values.lettering08, parameter_names[6].name_a8); parameter_values.a1 = 0; parameter_values.a5 = 0; parameter_values.a2 = 0; parameter_values.a6 = 0; parameter_values.a3 = 0; parameter_values.a7 = 0; parameter_values.a4 = 0; parameter_values.a8 = 0; parameter_values.use_cutoff = 0; parameter_values.r = 0.5; parameter_values.dr = 0.2; parameter_values.current_function = FUNCTION_Cosines; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } static void function08_callback(GtkWidget *widget, gpointer data) { strcpy(parameter_values.lettering01, parameter_names[7].name_a1); strcpy(parameter_values.lettering02, parameter_names[7].name_a2); strcpy(parameter_values.lettering03, parameter_names[7].name_a3); strcpy(parameter_values.lettering04, parameter_names[7].name_a4); strcpy(parameter_values.lettering05, parameter_names[7].name_a5); strcpy(parameter_values.lettering06, parameter_names[7].name_a6); strcpy(parameter_values.lettering07, parameter_names[7].name_a7); strcpy(parameter_values.lettering08, parameter_names[7].name_a8); parameter_values.a1 = 0; parameter_values.a5 = 0; parameter_values.a2 = 0; parameter_values.a6 = 0; parameter_values.a3 = 0; parameter_values.a7 = 0; parameter_values.a4 = 0; parameter_values.a8 = 0; parameter_values.use_cutoff = 0; parameter_values.r = 0.5; parameter_values.dr = 0.2; parameter_values.current_function = FUNCTION_Gauss; do_update_preview = 0; update_dialog(); do_update_preview = 1; update_preview(preview_data.display); } /******************************************************************************/ /* Image manipulation functions */ /******************************************************************************/ void image_action(GimpDrawable *drawable, Parameters params) { gint width, height; gint bytes; gint x1, y1, x2, y2; GimpPixelRgn src_rgn, dest_rgn; guchar *dest; guchar *src; guchar r, g, b, a; gfloat u, v; gint image_size; gint i, j; gint count; gimp_drawable_mask_bounds(drawable->id, &x1, &y1, &x2, &y2); width = (x2 - x1); height = (y2 - y1); bytes = drawable->bpp; image_size = width*height*bytes; /* Allocate the necessary storage memory */ src = (guchar *)malloc(image_size); dest = (guchar *)malloc(width * bytes); gimp_pixel_rgn_init(&src_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); gimp_pixel_rgn_init(&dest_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, TRUE); /* Get the source image */ get_source_image(src_rgn, src, x1, y1, width, height, bytes); switch(bytes) { case 4: for(j = 0; j < height; j++) { count = 0; for(i = 0; i < width; i++) { calculate_distortion_function(i, j, width, height, &u, &v); if((u >= 0) && (u < width) && (v >= 0) && (v < height)) { calculate_pixel_color(u, v, src, width, height, bytes, &r, &g, &b, &a); dest[count] = r; count++; dest[count] = g; count++; dest[count] = b; count++; dest[count] = a; count++; } else { dest[count] = 0; count++; dest[count] = 0; count++; dest[count] = 0; count++; dest[count] = 0; count++; } } gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, j + y1, width); gimp_progress_update((double)j / (double)height); } break; case 3: for(j = 0; j < height; j++) { count = 0; for(i = 0; i < width; i++) { calculate_distortion_function(i, j, width, height, &u, &v); if((u >= 0) && (u < width) && (v >= 0) && (v < height)) { calculate_pixel_color(u, v, src, width, height, bytes, &r, &g, &b, &a); dest[count] = r; count++; dest[count] = g; count++; dest[count] = b; count++; } else { dest[count] = 0; count++; dest[count] = 0; count++; dest[count] = 0; count++; } } gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, j + y1, width); gimp_progress_update((double)j / (double)height); } break; case 2: for(j = 0; j < height; j++) { count = 0; for(i = 0; i < width; i++) { calculate_distortion_function(i, j, width, height, &u, &v); if((u >= 0) && (u < width) && (v >= 0) && (v < height)) { calculate_pixel_color(u, v, src, width, height, bytes, &r, &g, &b, &a); dest[count] = r; count++; dest[count] = a; count++; } else { dest[count] = 0; count++; dest[count] = 0; count++; } } gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, j + y1, width); gimp_progress_update((double)j / (double)height); } break; case 1: for(j = 0; j < height; j++) { count = 0; for(i = 0; i < width; i++) { calculate_distortion_function(i, j, width, height, &u, &v); if((u >= 0) && (u < width) && (v >= 0) && (v < height)) { calculate_pixel_color(u, v, src, width, height, bytes, &r, &g, &b, &a); dest[count] = r; count++; } else { dest[count] = 0; count++; } } gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, j + y1, width); gimp_progress_update((double)j / (double)height); } break; } /* merge the shadow, update the drawable */ gimp_drawable_flush(drawable); gimp_drawable_merge_shadow(drawable->id, TRUE); gimp_drawable_update(drawable->id, x1, y1, width, height); free(src); free(dest); } static void polar_coordinates(gfloat x, gfloat y, gfloat *rho, gfloat *phi) { gfloat r, p; /* Calculate the radius */ r = sqrt(x*x + y*y); p = 0.0; /* exceptions first .. */ if((x == 0.0) && (y == 0.0)) p = 0.0; else if((x < epsilon) && (x > -epsilon) && (y > 0.0)) p = TWIST_PI/2.0; else if((x < epsilon) && (x > -epsilon) && (y < 0.0)) p = 3.0*TWIST_PI/2.0; else if((x > 0.0) && (y < epsilon) && (y > -epsilon)) p = 0.0; else if((x < 0.0) && (y < epsilon) && (y > -epsilon)) p = TWIST_PI; /* simple cases in the four quadrants */ else if((x > 0.0) && (y > 0.0)) p = atan(y/x); else if((x < 0.0) && (y > 0.0)) p = TWIST_PI - atan(-y/x); else if((x < 0.0) && (y < 0.0)) p = TWIST_PI + atan(y/x); else if((x > 0.0) && (y < 0.0)) p = 2.0*TWIST_PI - atan(-y/x); /* Return the values */ *rho = r; *phi = p; } /* The distortion functions */ static void distortion_function01(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2) { gfloat r2; r2 = x1*x1; *delta_x1 = parameter_values.a1*x1 + parameter_values.a2*r2 + parameter_values.a3*r2*x1 + parameter_values.a4*r2*r2; } static void distortion_function02(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2) { *delta_x1 = parameter_values.a1*cos(x2*parameter_values.a2) + parameter_values.a3*cos(x2*parameter_values.a4); } static void distortion_function03(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2) { gfloat r2; r2 = x1*x1; *delta_x2 = parameter_values.a1*x1 + parameter_values.a2*r2 + parameter_values.a3*r2*x1 + parameter_values.a4*r2*r2; } static void distortion_function04(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2) { *delta_x2 = parameter_values.a1*cos(x2*parameter_values.a2) + parameter_values.a3*cos(x2*parameter_values.a4); } static void distortion_function05(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2) { gfloat P, Q; gfloat r2; r2 = x1*x1; P = parameter_values.a1*x1 + parameter_values.a2*r2 + parameter_values.a3*r2*x1 + parameter_values.a4*r2*r2; Q = parameter_values.a5*cos(x2*parameter_values.a6) + parameter_values.a7*cos(x2*parameter_values.a8); *delta_x2 = P*Q; } static void distortion_function06(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2) { gfloat P, Q; gfloat r2; r2 = x1*x1; P = parameter_values.a1*x1 + parameter_values.a2*r2 + parameter_values.a3*r2*x1 + parameter_values.a4*r2*r2; Q = parameter_values.a5*cos(x2*parameter_values.a6) + parameter_values.a7*cos(x2*parameter_values.a8); *delta_x2 = P*Q; } static void distortion_function07(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2) { *delta_x1 = 0.1*parameter_values.a1*sin(5.0*parameter_values.a3*x1)*cos(5.0*parameter_values.a4*x1); *delta_x2 = 0.1*parameter_values.a2*sin(5.0*parameter_values.a5*x2)*cos(5.0*parameter_values.a6*x2); } static void distortion_function08(gfloat x1, gfloat x2, gfloat *delta_x1, gfloat *delta_x2) { gfloat x0, y0; gfloat lambda1, lambda2; x0 = parameter_values.a3/10.0; y0 = parameter_values.a4/10.0; lambda1 = 30.0/(10.1 + parameter_values.a5); lambda2 = 30.0/(10.1 + parameter_values.a6); *delta_x1 = 0.5*parameter_values.a1*(x1 - x0)*exp(-lambda1*(x1 - x0)*(x1 - x0)); *delta_x2 = 0.5*parameter_values.a2*(x2 - y0)*exp(-lambda2*(x2 - y0)*(x2 - y0)); } static void calculate_distortion_function(gint i, gint j, gint width, gint height, gfloat *u, gfloat *v) { gint x, y; gfloat scale_factor; gint mx, my; gfloat scaled_x, scaled_y; gfloat delta_rho, delta_phi; gfloat delta_x, delta_y; gfloat rho, phi; gfloat damp; mx = width/2; my = height/2; /* The scale factor is chosed such that the scaled image fits into a unit square. */ scale_factor = (gfloat)MAX(width, height); x = i - mx; y = my - j; scaled_x = ((float)x)/scale_factor; scaled_y = ((float)y)/scale_factor; switch(parameter_values.current_function) { case FUNCTION_R_r: /* Calculate the (u, v) coordinates of the distorted image from the original image */ polar_coordinates(scaled_x, scaled_y, &rho, &phi); distortion_function01(rho, phi, &delta_rho, &delta_phi); /* calculate the damping factor */ damp = 1.0; if(parameter_values.use_cutoff != 0) damp = cutoff_function(scaled_x, scaled_y); *u = (float)x + (float)mx + damp*scale_factor*delta_rho*cos(phi); *v = (float)my - (float)y - damp*scale_factor*delta_rho*sin(phi); break; case FUNCTION_R_phi: /* Calculate the (u, v) coordinates of the distorted image from the original image */ polar_coordinates(scaled_x, scaled_y, &rho, &phi); distortion_function02(rho, phi, &delta_rho, &delta_phi); /* calculate the damping factor */ damp = 1.0; if(parameter_values.use_cutoff != 0) damp = cutoff_function(scaled_x, scaled_y); *u = (float)x + (float)mx + damp*scale_factor*delta_rho*cos(phi); *v = (float)my - (float)y - damp*scale_factor*delta_rho*sin(phi); break; case FUNCTION_Phi_r: /* Calculate the (u, v) coordinates of the distorted image from the original image */ polar_coordinates(scaled_x, scaled_y, &rho, &phi); distortion_function03(rho, phi, &delta_rho, &delta_phi); /* calculate the damping factor */ damp = 1.0; if(parameter_values.use_cutoff != 0) damp = cutoff_function(scaled_x, scaled_y); *u = (float)x + (float)mx + damp*scale_factor*delta_phi*sin(phi); *v = (float)my - (float)y + damp*scale_factor*delta_phi*cos(phi); break; case FUNCTION_Phi_phi: /* Calculate the (u, v) coordinates of the distorted image from the original image */ polar_coordinates(scaled_x, scaled_y, &rho, &phi); distortion_function04(rho, phi, &delta_rho, &delta_phi); /* calculate the damping factor */ damp = 1.0; if(parameter_values.use_cutoff != 0) damp = cutoff_function(scaled_x, scaled_y); *u = (float)x + (float)mx + damp*scale_factor*delta_phi*sin(phi); *v = (float)my - (float)y + damp*scale_factor*delta_phi*cos(phi); break; case FUNCTION_R_r_Phi_phi: /* Calculate the (u, v) coordinates of the distorted image from the original image */ polar_coordinates(scaled_x, scaled_y, &rho, &phi); distortion_function05(rho, phi, &delta_rho, &delta_phi); /* calculate the damping factor */ damp = 1.0; if(parameter_values.use_cutoff != 0) damp = cutoff_function(scaled_x, scaled_y); *u = (float)x + (float)mx + damp*scale_factor*delta_phi*sin(phi); *v = (float)my - (float)y + damp*scale_factor*delta_phi*cos(phi); break; case FUNCTION_R_r_R_phi: /* Calculate the (u, v) coordinates of the distorted image from the original image */ polar_coordinates(scaled_x, scaled_y, &rho, &phi); distortion_function06(rho, phi, &delta_rho, &delta_phi); /* calculate the damping factor */ damp = 1.0; if(parameter_values.use_cutoff != 0) damp = cutoff_function(scaled_x, scaled_y); *u = (float)x + (float)mx + damp*scale_factor*delta_phi*cos(phi); *v = (float)my - (float)y - damp*scale_factor*delta_phi*sin(phi); break; case FUNCTION_Cosines: /* Calculate the (u, v) coordinates of the distorted image from the original image */ distortion_function07(scaled_x, scaled_y, &delta_x, &delta_y); /* calculate the damping factor */ damp = 1.0; if(parameter_values.use_cutoff != 0) damp = cutoff_function(scaled_x, scaled_y); *u = (float)x + (float)mx + damp*scale_factor*delta_x; *v = (float)my - (float)y - damp*scale_factor*delta_y; break; case FUNCTION_Gauss: distortion_function08(scaled_x, scaled_y, &delta_x, &delta_y); /* calculate the damping factor */ damp = 1.0; if(parameter_values.use_cutoff != 0) damp = cutoff_function(scaled_x, scaled_y); *u = (float)x + (float)mx + damp*scale_factor*delta_x; *v = (float)my - (float)y - damp*scale_factor*delta_y; break; } } static gfloat cutoff_function(gfloat u, gfloat v) { gfloat radius; gfloat x; radius = sqrt(u*u + v*v); if(radius <= parameter_values.r) return(1.0); x = (radius - parameter_values.r)/(0.2*parameter_values.dr); return(exp(-x*x)); } static void calculate_pixel_color(gfloat u, gfloat v, guchar *source, gint width, gint height, gint bpp, guchar *r, guchar *g, guchar *b, guchar *a) { gint address; gfloat ru, rv; gfloat w0, w1, w2, w3; guchar red[4]; guchar green[4]; guchar blue[4]; guchar alpha[4]; if(((gint)u < width - 1) && ((gint)v < height - 1)) { ru = u - (int)u; rv = v - (int)v; /* Calculate the area weights. */ w0 = (1.0 - ru)*rv; w1 = rv*ru; w2 = (1.0 - ru)*(1.0 - rv); w3 = (1.0 - rv)*ru; /* Get the four pixel colors depending on bpp. */ switch(bpp) { case 4: address = bpp*((int)v*width + (int)u); red[0] = source[address]; green[0] = source[address +1]; blue[0] = source[address + 2]; alpha[0] = source[address + 3]; address = bpp*((int)v*width + (int)(u + 1.0)); red[1] = source[address]; green[1] = source[address + 1]; blue[1] = source[address + 2]; alpha[1] = source[address + 3]; address = bpp*((int)(v - 1.0)*width + (int)u); red[2] = source[address]; green[2] = source[address + 1]; blue[2] = source[address + 2]; alpha[2] = source[address + 3]; address = bpp*((int)(v - 1.0)*width + (int)(u + 1.0)); red[3] = source[address]; green[3] = source[address + 1]; blue[3] = source[address + 2]; alpha[3] = source[address + 3]; *r = w0*red[0] + w1*red[1] + w2*red[2] + w3*red[3]; *g = w0*green[0] + w1*green[1] + w2*green[2] + w3*green[3]; *b = w0*blue[0] + w1*blue[1] + w2*blue[2] + w3*blue[3]; *a = w0*alpha[0] + w1*alpha[1] + w2*alpha[2] + w3*alpha[3]; break; case 3: address = bpp*((int)v*width + (int)u); red[0] = source[address]; green[0] = source[address +1]; blue[0] = source[address + 2]; address = bpp*((int)v*width + (int)(u + 1.0)); red[1] = source[address]; green[1] = source[address + 1]; blue[1] = source[address + 2]; address = bpp*((int)(v - 1.0)*width + (int)u); red[2] = source[address]; green[2] = source[address + 1]; blue[2] = source[address + 2]; address = bpp*((int)(v - 1.0)*width + (int)(u + 1.0)); red[3] = source[address]; green[3] = source[address + 1]; blue[3] = source[address + 2]; *r = w0*red[0] + w1*red[1] + w2*red[2] + w3*red[3]; *g = w0*green[0] + w1*green[1] + w2*green[2] + w3*green[3]; *b = w0*blue[0] + w1*blue[1] + w2*blue[2] + w3*blue[3]; *a = 255; break; /* For grayscale images, the grayvalue is stored in the red component. */ case 2: address = bpp*((int)v*width + (int)u); red[0] = source[address]; alpha[0] = source[address+1]; address = bpp*((int)v*width + (int)(u + 1.0)); red[1] = source[address]; alpha[1] = source[address+1]; address = bpp*((int)(v - 1.0)*width + (int)u); red[2] = source[address]; alpha[2] = source[address+1]; address = bpp*((int)(v - 1.0)*width + (int)(u + 1.0)); red[3] = source[address]; alpha[3] = source[address+1]; *r = w0*red[0] + w1*red[1] + w2*red[2] + w3*red[3]; *a = w0*alpha[0] + w1*alpha[1] + w2*alpha[2] + w3*alpha[3]; break; case 1: address = bpp*((int)v*width + (int)u); red[0] = source[address]; address = bpp*((int)v*width + (int)(u + 1.0)); red[1] = source[address]; address = bpp*((int)(v - 1.0)*width + (int)u); red[2] = source[address]; address = bpp*((int)(v - 1.0)*width + (int)(u + 1.0)); red[3] = source[address]; *r = w0*red[0] + w1*red[1] + w2*red[2] + w3*red[3]; break; } } } static void get_source_image(GimpPixelRgn source_rgn, guchar *buffer, gint x, gint y, gint width, gint height, gint bytes) { gint offset; gint i, j; guchar *src_buffer; src_buffer = (guchar *)malloc(width * bytes); offset = 0; for(j = 0; j < height; j++) { gimp_pixel_rgn_get_row(&source_rgn, src_buffer, x, j + y, width); for(i = 0; i < bytes*width; i++) buffer[i + offset] = src_buffer[i]; offset += bytes*width; } free(src_buffer); }