mirror of https://github.com/GNOME/gimp.git
2120 lines
64 KiB
C
2120 lines
64 KiB
C
/*
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
*
|
|
* This is a plug-in for GIMP.
|
|
*
|
|
* Copyright (C) Pavel Grinfeld (pavel@ml.com)
|
|
*
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <libgimp/gimp.h>
|
|
#include <libgimp/gimpui.h>
|
|
|
|
#include "libgimp/stdplugins-intl.h"
|
|
|
|
|
|
#define PLUG_IN_PROC "plug-in-filter-pack"
|
|
#define PLUG_IN_BINARY "filter-pack"
|
|
#define PLUG_IN_ROLE "gimp-filter-pack"
|
|
|
|
#define MAX_PREVIEW_SIZE 125
|
|
#define MAX_ROUGHNESS 128
|
|
#define RANGE_HEIGHT 15
|
|
#define PR_BX_BRDR 4
|
|
#define MARGIN 4
|
|
|
|
#define RANGE_ADJUST_MASK (GDK_EXPOSURE_MASK | \
|
|
GDK_ENTER_NOTIFY_MASK | \
|
|
GDK_BUTTON_PRESS_MASK | \
|
|
GDK_BUTTON_RELEASE_MASK | \
|
|
GDK_BUTTON1_MOTION_MASK | \
|
|
GDK_POINTER_MOTION_HINT_MASK)
|
|
|
|
|
|
typedef struct
|
|
{
|
|
gboolean run;
|
|
} fpInterface;
|
|
|
|
typedef struct
|
|
{
|
|
gint width;
|
|
gint height;
|
|
guchar *rgb;
|
|
gdouble *hsv;
|
|
guchar *mask;
|
|
} ReducedImage;
|
|
|
|
typedef enum
|
|
{
|
|
SHADOWS,
|
|
MIDTONES,
|
|
HIGHLIGHTS,
|
|
INTENSITIES
|
|
} FPIntensity;
|
|
|
|
enum
|
|
{
|
|
NONEATALL = 0,
|
|
CURRENT = 1,
|
|
HUE = 2,
|
|
SATURATION = 4,
|
|
VALUE = 8
|
|
};
|
|
|
|
enum
|
|
{
|
|
BY_HUE,
|
|
BY_SAT,
|
|
BY_VAL,
|
|
JUDGE_BY
|
|
};
|
|
|
|
enum
|
|
{
|
|
RED,
|
|
GREEN,
|
|
BLUE,
|
|
CYAN,
|
|
YELLOW,
|
|
MAGENTA,
|
|
ALL_PRIMARY
|
|
};
|
|
|
|
enum
|
|
{
|
|
DOWN = -1,
|
|
UP = 1
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
GtkWidget *window;
|
|
GtkWidget *range_preview;
|
|
GtkWidget *aliasing_preview;
|
|
GtkWidget *aliasing_graph;
|
|
} AdvancedWindow;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
gdouble roughness;
|
|
gdouble aliasing;
|
|
gdouble preview_size;
|
|
FPIntensity intensity_range;
|
|
gint value_by;
|
|
gint selection_only;
|
|
guchar offset;
|
|
guchar visible_frames;
|
|
guchar cutoff[INTENSITIES];
|
|
gboolean touched[JUDGE_BY];
|
|
gint red_adjust[JUDGE_BY][256];
|
|
gint blue_adjust[JUDGE_BY][256];
|
|
gint green_adjust[JUDGE_BY][256];
|
|
gint sat_adjust[JUDGE_BY][256];
|
|
} FPValues;
|
|
|
|
typedef struct
|
|
{
|
|
GtkWidget *roughness_scale;
|
|
GtkWidget *aliasing_scale;
|
|
GtkWidget *preview_size_scale;
|
|
GtkWidget *range_label[12];
|
|
} FPWidgets;
|
|
|
|
static void fp_show_hide_frame (GtkWidget *button,
|
|
GtkWidget *frame);
|
|
|
|
static ReducedImage * fp_reduce_image (GimpDrawable *drawable,
|
|
GimpDrawable *mask,
|
|
gint longer_size,
|
|
gint selection);
|
|
|
|
static void fp_render_preview (GtkWidget *preview,
|
|
gint change_what,
|
|
gint change_which);
|
|
|
|
static void update_current_fp (gint change_what,
|
|
gint change_which);
|
|
|
|
static void fp_create_nudge (gint *adj_array);
|
|
|
|
static gboolean fp_dialog (void);
|
|
static void fp_advanced_dialog (GtkWidget *parent);
|
|
|
|
static void fp_selection_made (GtkWidget *widget,
|
|
gpointer data);
|
|
static void fp_scale_update (GtkAdjustment *adjustment,
|
|
gdouble *scale_val);
|
|
static void fp_reset_filter_packs (void);
|
|
|
|
static void fp_create_smoothness_graph (GtkWidget *preview);
|
|
|
|
static void fp_range_preview_spill (GtkWidget *preview,
|
|
gint type);
|
|
static void fp_adjust_preview_sizes (gint width,
|
|
gint height);
|
|
static void fp_redraw_all_windows (void);
|
|
static void fp_refresh_previews (gint which);
|
|
static void fp_init_filter_packs (void);
|
|
|
|
static void fp_preview_scale_update (GtkAdjustment *adjustment,
|
|
gdouble *scale_val);
|
|
|
|
static void fp (GimpDrawable *drawable);
|
|
static GtkWidget * fp_create_bna (void);
|
|
static GtkWidget * fp_create_rough (void);
|
|
static GtkWidget * fp_create_range (void);
|
|
static GtkWidget * fp_create_circle_palette (GtkWidget *parent);
|
|
static GtkWidget * fp_create_lnd (GtkWidget *parent);
|
|
static GtkWidget * fp_create_show (void);
|
|
static GtkWidget * fp_create_msnls (GtkWidget *parent);
|
|
static GtkWidget * fp_create_pixels_select_by (void);
|
|
static void update_range_labels (void);
|
|
static gboolean fp_range_change_events (GtkWidget *widget,
|
|
GdkEvent *event,
|
|
FPValues *current);
|
|
|
|
static void fp_create_preview (GtkWidget **preview,
|
|
GtkWidget **frame,
|
|
gint preview_width,
|
|
gint preview_height);
|
|
|
|
static void fp_create_table_entry (GtkWidget **box,
|
|
GtkWidget *smaller_frame,
|
|
const gchar *description);
|
|
|
|
static void fp_frames_checkbutton_in_box (GtkWidget *vbox,
|
|
const gchar *label,
|
|
GCallback func,
|
|
GtkWidget *frame,
|
|
gboolean clicked);
|
|
|
|
static void fp_preview_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation);
|
|
|
|
#define RESPONSE_RESET 1
|
|
|
|
/* These values are translated for the GUI but also used internally
|
|
to figure out which button the user pushed, etc.
|
|
Not my design, please don't blame me -- njl */
|
|
|
|
static const gchar *hue_red = N_("Red:");
|
|
static const gchar *hue_green = N_("Green:");
|
|
static const gchar *hue_blue = N_("Blue:");
|
|
static const gchar *hue_cyan = N_("Cyan:");
|
|
static const gchar *hue_yellow = N_("Yellow:");
|
|
static const gchar *hue_magenta = N_("Magenta:");
|
|
|
|
static const gchar *val_darker = N_("Darker:");
|
|
static const gchar *val_lighter = N_("Lighter:");
|
|
|
|
static const gchar *sat_more = N_("More Sat:");
|
|
static const gchar *sat_less = N_("Less Sat:");
|
|
|
|
static const gchar *current_val = N_("Current:");
|
|
|
|
static const gint colorSign[3][ALL_PRIMARY]=
|
|
{{1,-1,-1,-1,1,1},{-1,1,-1,1,1,-1},{-1,-1,1,1,-1,1}};
|
|
|
|
static AdvancedWindow AW = { NULL, NULL, NULL, NULL };
|
|
|
|
static FPWidgets fp_widgets = { NULL, NULL, NULL };
|
|
|
|
static gint nudgeArray[256];
|
|
|
|
static GtkWidget *origPreview, *curPreview;
|
|
static GtkWidget *rPreview, *gPreview, *bPreview;
|
|
static GtkWidget *cPreview, *yPreview, *mPreview;
|
|
static GtkWidget *centerPreview;
|
|
static GtkWidget *darkerPreview, *lighterPreview, *middlePreview;
|
|
static GtkWidget *dlg;
|
|
static GtkWidget *plusSatPreview, *SatPreview, *minusSatPreview;
|
|
|
|
static struct
|
|
{
|
|
GtkWidget *bna;
|
|
GtkWidget *palette;
|
|
GtkWidget *rough;
|
|
GtkWidget *range;
|
|
GtkWidget *show;
|
|
GtkWidget *lnd;
|
|
GtkWidget *pixelsBy;
|
|
GtkWidget *frameSelect;
|
|
GtkWidget *satur;
|
|
} fp_frames;
|
|
|
|
static fpInterface FPint =
|
|
{
|
|
FALSE /* run */
|
|
};
|
|
|
|
static ReducedImage *reduced;
|
|
|
|
static FPValues fpvals =
|
|
{
|
|
.25, /* Initial Roughness */
|
|
.6, /* Initial Degree of Aliasing */
|
|
80, /* Initial preview size */
|
|
MIDTONES, /* Initial Range */
|
|
BY_VAL, /* Initial God knows what */
|
|
TRUE, /* Selection Only */
|
|
0, /* Offset */
|
|
0, /* Visible frames */
|
|
{ 32, 224, 255 }, /* cutoffs */
|
|
{ FALSE, FALSE, FALSE } /* touched */
|
|
};
|
|
|
|
static GimpDrawable *drawable = NULL;
|
|
static GimpDrawable *mask = NULL;
|
|
|
|
static void query (void);
|
|
static void run (const gchar *name,
|
|
gint nparams,
|
|
const GimpParam *param,
|
|
gint *nreturn_vals,
|
|
GimpParam **return_vals);
|
|
|
|
const GimpPlugInInfo PLUG_IN_INFO =
|
|
{
|
|
NULL, /* init_proc */
|
|
NULL, /* quit_proc */
|
|
query, /* query_proc */
|
|
run, /* run_proc */
|
|
};
|
|
|
|
MAIN()
|
|
|
|
static void
|
|
query (void)
|
|
{
|
|
GimpParamDef args[] =
|
|
{
|
|
{ GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
|
|
{ GIMP_PDB_IMAGE, "image", "Input image (used for indexed images)" },
|
|
{ GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }
|
|
};
|
|
|
|
gimp_install_procedure (PLUG_IN_PROC,
|
|
N_("Interactively modify the image colors"),
|
|
"Interactively modify the image colors.",
|
|
"Pavel Grinfeld (pavel@ml.com)",
|
|
"Pavel Grinfeld (pavel@ml.com)",
|
|
"27th March 1997",
|
|
N_("_Filter Pack..."),
|
|
"RGB*",
|
|
GIMP_PLUGIN,
|
|
G_N_ELEMENTS (args), 0,
|
|
args, NULL);
|
|
}
|
|
|
|
/********************************STANDARD RUN*************************/
|
|
|
|
static void
|
|
run (const gchar *name,
|
|
gint nparams,
|
|
const GimpParam *param,
|
|
gint *nreturn_vals,
|
|
GimpParam **return_vals)
|
|
{
|
|
static GimpParam values[1];
|
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
|
GimpRunMode run_mode;
|
|
|
|
*nreturn_vals = 1;
|
|
*return_vals = values;
|
|
|
|
run_mode = param[0].data.d_int32;
|
|
|
|
INIT_I18N ();
|
|
|
|
values[0].type = GIMP_PDB_STATUS;
|
|
values[0].data.d_status = status;
|
|
|
|
fp_init_filter_packs();
|
|
|
|
drawable = gimp_drawable_get (param[2].data.d_drawable);
|
|
|
|
if (gimp_selection_is_empty (param[1].data.d_image))
|
|
mask = NULL;
|
|
else
|
|
mask = gimp_drawable_get (gimp_image_get_selection (param[1].data.d_image));
|
|
|
|
switch (run_mode)
|
|
{
|
|
case GIMP_RUN_INTERACTIVE:
|
|
/* Possibly retrieve data */
|
|
gimp_get_data (PLUG_IN_PROC, &fpvals);
|
|
|
|
if (gimp_drawable_is_indexed (drawable->drawable_id) ||
|
|
gimp_drawable_is_gray (drawable->drawable_id) )
|
|
{
|
|
gimp_message (_("FP can only be used on RGB images."));
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
|
}
|
|
else if (! fp_dialog())
|
|
{
|
|
status = GIMP_PDB_CANCEL;
|
|
}
|
|
break;
|
|
|
|
case GIMP_RUN_NONINTERACTIVE:
|
|
gimp_message (_("FP can only be run interactively."));
|
|
status = GIMP_PDB_CALLING_ERROR;
|
|
break;
|
|
|
|
case GIMP_RUN_WITH_LAST_VALS:
|
|
/* Possibly retrieve data */
|
|
gimp_get_data (PLUG_IN_PROC, &fpvals);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (status == GIMP_PDB_SUCCESS)
|
|
{
|
|
/* Make sure that the drawable is gray or RGB color */
|
|
if (gimp_drawable_is_rgb (drawable->drawable_id))
|
|
{
|
|
gimp_progress_init (_("Applying filter pack"));
|
|
gimp_tile_cache_ntiles (2 * (drawable->width /
|
|
gimp_tile_width () + 1));
|
|
fp (drawable);
|
|
|
|
/* Store data */
|
|
if (run_mode == GIMP_RUN_INTERACTIVE)
|
|
gimp_set_data (PLUG_IN_PROC, &fpvals, sizeof (FPValues));
|
|
|
|
gimp_displays_flush ();
|
|
}
|
|
else
|
|
{
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
|
}
|
|
}
|
|
|
|
gimp_drawable_detach (drawable);
|
|
if (mask)
|
|
gimp_drawable_detach (mask);
|
|
|
|
values[0].data.d_status = status;
|
|
}
|
|
|
|
static void
|
|
fp_func (const guchar *src,
|
|
guchar *dest,
|
|
gint bpp,
|
|
gpointer data)
|
|
{
|
|
gint bytenum, k;
|
|
gint JudgeBy, Intensity = 0, P[3];
|
|
GimpRGB rgb;
|
|
GimpHSV hsv;
|
|
gint M, m, middle;
|
|
|
|
P[0] = src[0];
|
|
P[1] = src[1];
|
|
P[2] = src[2];
|
|
|
|
gimp_rgb_set_uchar (&rgb, (guchar) P[0], (guchar) P[1], (guchar) P[2]);
|
|
gimp_rgb_to_hsv (&rgb, &hsv);
|
|
|
|
for (JudgeBy = BY_HUE; JudgeBy < JUDGE_BY; JudgeBy++)
|
|
{
|
|
if (!fpvals.touched[JudgeBy])
|
|
continue;
|
|
|
|
switch (JudgeBy)
|
|
{
|
|
case BY_HUE:
|
|
Intensity = 255 * hsv.h;
|
|
break;
|
|
|
|
case BY_SAT:
|
|
Intensity = 255 * hsv.s;
|
|
break;
|
|
|
|
case BY_VAL:
|
|
Intensity = 255 * hsv.v;
|
|
break;
|
|
}
|
|
|
|
|
|
/* It's important to take care of Saturation first!!! */
|
|
|
|
m = MIN (MIN (P[0], P[1]), P[2]);
|
|
M = MAX (MAX (P[0], P[1]), P[2]);
|
|
middle = (M + m) / 2;
|
|
|
|
for (k = 0; k < 3; k++)
|
|
if (P[k] != m && P[k] != M)
|
|
middle = P[k];
|
|
|
|
for (k = 0; k < 3; k++)
|
|
if (M != m)
|
|
{
|
|
if (P[k] == M)
|
|
P[k] = MAX (P[k] + fpvals.sat_adjust[JudgeBy][Intensity], middle);
|
|
else if (P[k] == m)
|
|
P[k] = MIN (P[k] - fpvals.sat_adjust[JudgeBy][Intensity], middle);
|
|
}
|
|
|
|
P[0] += fpvals.red_adjust[JudgeBy][Intensity];
|
|
P[1] += fpvals.green_adjust[JudgeBy][Intensity];
|
|
P[2] += fpvals.blue_adjust[JudgeBy][Intensity];
|
|
|
|
P[0] = CLAMP0255(P[0]);
|
|
P[1] = CLAMP0255(P[1]);
|
|
P[2] = CLAMP0255(P[2]);
|
|
}
|
|
|
|
dest[0] = P[0];
|
|
dest[1] = P[1];
|
|
dest[2] = P[2];
|
|
|
|
for (bytenum = 3; bytenum < bpp; bytenum++)
|
|
dest[bytenum] = src[bytenum];
|
|
}
|
|
|
|
static void
|
|
fp (GimpDrawable *drawable)
|
|
{
|
|
gimp_rgn_iterate2 (drawable, 0 /* unused */, fp_func, NULL);
|
|
}
|
|
|
|
/***********************************************************/
|
|
/************ Main Dialog Window ******************/
|
|
/***********************************************************/
|
|
|
|
static GtkWidget *
|
|
fp_create_bna (void)
|
|
{
|
|
GtkWidget *table;
|
|
GtkWidget *label;
|
|
GtkWidget *bframe, *aframe;
|
|
|
|
fp_create_preview (&origPreview, &bframe, reduced->width, reduced->height);
|
|
fp_create_preview (&curPreview, &aframe, reduced->width, reduced->height);
|
|
|
|
table = gtk_table_new (2, 2, FALSE);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
|
|
|
label = gtk_label_new (_("Original:"));
|
|
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
|
|
GTK_SHRINK, GTK_SHRINK, 0, 0);
|
|
gtk_widget_show (label);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), bframe, 0, 1, 1, 2,
|
|
GTK_EXPAND, 0, 0, 0);
|
|
|
|
label = gtk_label_new (_("Current:"));
|
|
gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
|
|
GTK_SHRINK, GTK_SHRINK, 0, 0);
|
|
gtk_widget_show (label);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), aframe, 1, 2, 1, 2,
|
|
GTK_EXPAND, 0, 0, 0);
|
|
|
|
gtk_widget_show (table);
|
|
|
|
return table;
|
|
}
|
|
|
|
/* close a sub dialog (from window manager) by simulating toggle click */
|
|
static gboolean
|
|
sub_dialog_destroy (GtkWidget *dialog,
|
|
GdkEvent *ev,
|
|
gpointer dummy)
|
|
{
|
|
GtkWidget *button =
|
|
GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "ctrlButton"));
|
|
|
|
gtk_button_clicked (GTK_BUTTON (button));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_circle_palette (GtkWidget *parent)
|
|
{
|
|
GtkWidget *table;
|
|
GtkWidget *rVbox, *rFrame;
|
|
GtkWidget *gVbox, *gFrame;
|
|
GtkWidget *bVbox, *bFrame;
|
|
GtkWidget *cVbox, *cFrame;
|
|
GtkWidget *yVbox, *yFrame;
|
|
GtkWidget *mVbox, *mFrame;
|
|
GtkWidget *centerVbox, *centerFrame;
|
|
GtkWidget *win;
|
|
|
|
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
gimp_help_connect (win, gimp_standard_help_func, PLUG_IN_PROC, NULL);
|
|
|
|
gtk_window_set_title (GTK_WINDOW (win), _("Hue Variations"));
|
|
gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (parent));
|
|
|
|
g_signal_connect (win, "delete-event",
|
|
G_CALLBACK (sub_dialog_destroy),
|
|
NULL);
|
|
|
|
table = gtk_table_new (11, 11, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
|
|
gtk_container_set_border_width (GTK_CONTAINER (table), 12);
|
|
gtk_container_add (GTK_CONTAINER (win), table);
|
|
gtk_widget_show (table);
|
|
|
|
fp_create_preview (&rPreview, &rFrame, reduced->width, reduced->height);
|
|
fp_create_preview (&gPreview, &gFrame, reduced->width, reduced->height);
|
|
fp_create_preview (&bPreview, &bFrame, reduced->width, reduced->height);
|
|
fp_create_preview (&cPreview, &cFrame, reduced->width, reduced->height);
|
|
fp_create_preview (&yPreview, &yFrame, reduced->width, reduced->height);
|
|
fp_create_preview (&mPreview, &mFrame, reduced->width, reduced->height);
|
|
fp_create_preview (¢erPreview, ¢erFrame,
|
|
reduced->width, reduced->height);
|
|
|
|
fp_create_table_entry (&rVbox, rFrame, hue_red);
|
|
fp_create_table_entry (&gVbox, gFrame, hue_green);
|
|
fp_create_table_entry (&bVbox, bFrame, hue_blue);
|
|
fp_create_table_entry (&cVbox, cFrame, hue_cyan);
|
|
fp_create_table_entry (&yVbox, yFrame, hue_yellow);
|
|
fp_create_table_entry (&mVbox, mFrame, hue_magenta);
|
|
fp_create_table_entry (¢erVbox, centerFrame, current_val);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), rVbox, 8, 11 ,4 , 7,
|
|
GTK_EXPAND , GTK_EXPAND, 0 ,0);
|
|
gtk_table_attach (GTK_TABLE (table), gVbox, 2, 5, 0, 3,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
gtk_table_attach (GTK_TABLE (table), bVbox, 2, 5, 8, 11,
|
|
GTK_EXPAND, GTK_EXPAND,0,0);
|
|
gtk_table_attach (GTK_TABLE (table), cVbox, 0, 3, 4, 7,
|
|
GTK_EXPAND, GTK_EXPAND, 0 ,0);
|
|
gtk_table_attach (GTK_TABLE (table), yVbox, 6, 9, 0, 3,
|
|
GTK_EXPAND, GTK_EXPAND, 0 ,0);
|
|
gtk_table_attach (GTK_TABLE (table), mVbox, 6, 9, 8, 11,
|
|
GTK_EXPAND, GTK_EXPAND, 0 ,0);
|
|
gtk_table_attach (GTK_TABLE (table), centerVbox, 4, 7, 4, 7,
|
|
GTK_EXPAND, GTK_EXPAND, 0 ,0);
|
|
|
|
return win;
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_rough (void)
|
|
{
|
|
GtkWidget *frame, *vbox, *scale;
|
|
GtkAdjustment *data;
|
|
|
|
frame = gimp_frame_new (_("Roughness"));
|
|
gtk_widget_show (frame);
|
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
|
gtk_widget_show (vbox);
|
|
|
|
data = (GtkAdjustment *)
|
|
gtk_adjustment_new (fpvals.roughness, 0, 1.0, 0.05, 0.01, 0.0);
|
|
fp_widgets.roughness_scale = scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL,
|
|
data);
|
|
|
|
gtk_widget_set_size_request (scale, 60, -1);
|
|
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
|
|
gtk_scale_set_digits (GTK_SCALE (scale), 2);
|
|
gtk_widget_show (scale);
|
|
|
|
g_signal_connect (data, "value-changed",
|
|
G_CALLBACK (fp_scale_update),
|
|
&fpvals.roughness);
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static void
|
|
fp_change_current_range (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gimp_radio_button_update (widget, data);
|
|
|
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
|
|
{
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
if (AW.window && gtk_widget_get_visible (AW.window))
|
|
fp_create_smoothness_graph (AW.aliasing_preview);
|
|
}
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_range (void)
|
|
{
|
|
GtkWidget *frame;
|
|
|
|
frame = gimp_int_radio_group_new (TRUE, _("Affected Range"),
|
|
G_CALLBACK (fp_change_current_range),
|
|
&fpvals.intensity_range, fpvals.intensity_range,
|
|
|
|
_("Sha_dows"), SHADOWS, NULL,
|
|
_("_Midtones"), MIDTONES, NULL,
|
|
_("H_ighlights"), HIGHLIGHTS, NULL,
|
|
|
|
NULL);
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_control (void)
|
|
{
|
|
GtkWidget *frame, *box;
|
|
|
|
frame = gimp_frame_new (_("Windows"));
|
|
|
|
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
|
gtk_container_add (GTK_CONTAINER (frame), box);
|
|
gtk_widget_show (box);
|
|
|
|
fp_frames_checkbutton_in_box (box, _("_Hue"),
|
|
G_CALLBACK (fp_show_hide_frame),
|
|
fp_frames.palette,
|
|
fpvals.visible_frames & HUE);
|
|
fp_frames_checkbutton_in_box (box, _("_Saturation"),
|
|
G_CALLBACK (fp_show_hide_frame),
|
|
fp_frames.satur,
|
|
fpvals.visible_frames & SATURATION);
|
|
fp_frames_checkbutton_in_box (box, _("_Value"),
|
|
G_CALLBACK (fp_show_hide_frame),
|
|
fp_frames.lnd,
|
|
fpvals.visible_frames & VALUE);
|
|
fp_frames_checkbutton_in_box (box, _("A_dvanced"),
|
|
G_CALLBACK (fp_show_hide_frame),
|
|
AW.window,
|
|
FALSE);
|
|
gtk_widget_show (frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_lnd (GtkWidget *parent)
|
|
{
|
|
GtkWidget *table, *lighterFrame, *middleFrame, *darkerFrame;
|
|
GtkWidget *lighterVbox, *middleVbox, *darkerVbox;
|
|
GtkWidget *win;
|
|
|
|
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
gimp_help_connect (win, gimp_standard_help_func, PLUG_IN_PROC, NULL);
|
|
|
|
gtk_window_set_title (GTK_WINDOW (win), _("Value Variations"));
|
|
gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (parent));
|
|
|
|
g_signal_connect (win, "delete-event",
|
|
G_CALLBACK (sub_dialog_destroy),
|
|
NULL);
|
|
|
|
fp_create_preview (&lighterPreview, &lighterFrame,
|
|
reduced->width, reduced->height);
|
|
fp_create_preview (&middlePreview, &middleFrame,
|
|
reduced->width, reduced->height);
|
|
fp_create_preview (&darkerPreview, &darkerFrame,
|
|
reduced->width, reduced->height);
|
|
|
|
fp_create_table_entry (&lighterVbox, lighterFrame, val_lighter);
|
|
fp_create_table_entry (&middleVbox, middleFrame, current_val);
|
|
fp_create_table_entry (&darkerVbox, darkerFrame, val_darker);
|
|
|
|
table = gtk_table_new (1, 11, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
|
gtk_container_set_border_width (GTK_CONTAINER (table), 12);
|
|
gtk_container_add (GTK_CONTAINER (win), table);
|
|
gtk_widget_show (table);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), lighterVbox, 0, 3, 0, 1,
|
|
GTK_EXPAND , GTK_EXPAND, 0, 0);
|
|
gtk_table_attach (GTK_TABLE (table), middleVbox, 4, 7, 0, 1,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
gtk_table_attach (GTK_TABLE (table), darkerVbox, 8, 11, 0, 1,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
|
|
return win;
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_msnls (GtkWidget *parent)
|
|
{
|
|
GtkWidget *table, *lessFrame, *middleFrame, *moreFrame;
|
|
GtkWidget *lessVbox, *middleVbox, *moreVbox;
|
|
GtkWidget *win;
|
|
|
|
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
gimp_help_connect (win, gimp_standard_help_func, PLUG_IN_PROC, NULL);
|
|
|
|
gtk_window_set_title (GTK_WINDOW (win), _("Saturation Variations"));
|
|
gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (parent));
|
|
|
|
g_signal_connect (win, "delete-event",
|
|
G_CALLBACK (sub_dialog_destroy),
|
|
NULL);
|
|
|
|
fp_create_preview (&minusSatPreview, &lessFrame,
|
|
reduced->width, reduced->height);
|
|
fp_create_preview (&SatPreview, &middleFrame,
|
|
reduced->width, reduced->height);
|
|
fp_create_preview (&plusSatPreview, &moreFrame,
|
|
reduced->width, reduced->height);
|
|
|
|
fp_create_table_entry (&moreVbox, moreFrame, sat_more);
|
|
fp_create_table_entry (&middleVbox, middleFrame, current_val);
|
|
fp_create_table_entry (&lessVbox, lessFrame, sat_less);
|
|
|
|
table = gtk_table_new (1, 11, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
|
gtk_container_set_border_width (GTK_CONTAINER (table), 12);
|
|
gtk_container_add (GTK_CONTAINER (win), table);
|
|
gtk_widget_show (table);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), moreVbox, 0, 3, 0, 1,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
gtk_table_attach (GTK_TABLE (table), middleVbox, 4, 7, 0, 1,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
gtk_table_attach (GTK_TABLE (table), lessVbox, 8, 11, 0, 1,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
|
|
return win;
|
|
}
|
|
|
|
static void
|
|
fp_change_current_pixels_by (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gimp_radio_button_update (widget, data);
|
|
|
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
|
|
{
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
if (AW.window && gtk_widget_get_visible (AW.window) && AW.range_preview)
|
|
fp_range_preview_spill (AW.range_preview,fpvals.value_by);
|
|
}
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_pixels_select_by (void)
|
|
{
|
|
GtkWidget *frame;
|
|
|
|
frame = gimp_int_radio_group_new (TRUE, _("Select Pixels By"),
|
|
G_CALLBACK (fp_change_current_pixels_by),
|
|
&fpvals.value_by,
|
|
fpvals.value_by,
|
|
|
|
_("H_ue"), 0, NULL,
|
|
_("Satu_ration"), 1, NULL,
|
|
_("V_alue"), 2, NULL,
|
|
|
|
NULL);
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static void
|
|
fp_change_selection (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gimp_radio_button_update (widget, data);
|
|
|
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
|
|
{
|
|
fp_redraw_all_windows ();
|
|
}
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_show (void)
|
|
{
|
|
GtkWidget *frame;
|
|
|
|
frame = gimp_int_radio_group_new (TRUE, _("Show"),
|
|
G_CALLBACK (fp_change_selection),
|
|
&fpvals.selection_only,
|
|
fpvals.selection_only,
|
|
|
|
_("_Entire image"), 0, NULL,
|
|
_("Se_lection only"), 1, NULL,
|
|
_("Selec_tion in context"), 2, NULL,
|
|
|
|
NULL);
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static void
|
|
fp_create_preview (GtkWidget **preview,
|
|
GtkWidget **frame,
|
|
gint preview_width,
|
|
gint preview_height)
|
|
{
|
|
*frame = gtk_frame_new (NULL);
|
|
gtk_frame_set_shadow_type (GTK_FRAME (*frame), GTK_SHADOW_IN);
|
|
gtk_widget_show (*frame);
|
|
|
|
*preview = gimp_preview_area_new ();
|
|
gtk_widget_set_size_request (*preview, preview_width, preview_height);
|
|
g_signal_connect (*preview, "size-allocate",
|
|
G_CALLBACK (fp_preview_size_allocate), NULL);
|
|
gtk_widget_show (*preview);
|
|
gtk_container_add (GTK_CONTAINER (*frame), *preview);
|
|
}
|
|
|
|
static void
|
|
fp_frames_checkbutton_in_box (GtkWidget *vbox,
|
|
const gchar *label,
|
|
GCallback function,
|
|
GtkWidget *frame,
|
|
gboolean clicked)
|
|
{
|
|
GtkWidget *button;
|
|
|
|
button = gtk_check_button_new_with_mnemonic (label);
|
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
|
g_object_set_data (G_OBJECT (frame), "ctrlButton", (gpointer) button);
|
|
gtk_widget_show (button);
|
|
|
|
g_signal_connect (button, "clicked",
|
|
function,
|
|
frame);
|
|
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), clicked);
|
|
}
|
|
|
|
static void
|
|
fp_create_table_entry (GtkWidget **box,
|
|
GtkWidget *smaller_frame,
|
|
const gchar *description)
|
|
{
|
|
GtkWidget *label;
|
|
GtkWidget *button;
|
|
GtkWidget *table;
|
|
|
|
*box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1);
|
|
gtk_container_set_border_width (GTK_CONTAINER (*box), PR_BX_BRDR);
|
|
gtk_widget_show (*box);
|
|
|
|
/* Delayed translation applied here */
|
|
label = gtk_label_new (gettext (description));
|
|
|
|
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
|
|
gtk_widget_show (label);
|
|
|
|
table = gtk_table_new (2, 1, FALSE);
|
|
gtk_widget_show (table);
|
|
|
|
gtk_box_pack_start (GTK_BOX (*box), table, TRUE, TRUE, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
|
|
0, 0, 0, 0);
|
|
|
|
if (description != current_val)
|
|
{
|
|
button = gtk_button_new ();
|
|
gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2,
|
|
0, 0, 0, 4);
|
|
gtk_widget_show (button);
|
|
|
|
gtk_container_add (GTK_CONTAINER (button), smaller_frame);
|
|
|
|
g_signal_connect (button, "clicked",
|
|
G_CALLBACK (fp_selection_made),
|
|
(gchar *) description);
|
|
}
|
|
else
|
|
{
|
|
gtk_table_attach (GTK_TABLE (table), smaller_frame, 0, 1, 1, 2,
|
|
0, 0, 0, 4);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_redraw_all_windows (void)
|
|
{
|
|
if (reduced)
|
|
{
|
|
g_free (reduced->rgb);
|
|
g_free (reduced->hsv);
|
|
g_free (reduced->mask);
|
|
|
|
g_free (reduced);
|
|
}
|
|
|
|
reduced = fp_reduce_image (drawable, mask,
|
|
fpvals.preview_size,
|
|
fpvals.selection_only);
|
|
|
|
fp_adjust_preview_sizes (reduced->width, reduced->height);
|
|
|
|
gtk_widget_queue_draw (fp_frames.palette);
|
|
gtk_widget_queue_draw (fp_frames.satur);
|
|
gtk_widget_queue_draw (fp_frames.lnd);
|
|
gtk_widget_queue_draw (dlg);
|
|
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
}
|
|
|
|
static void
|
|
fp_show_hide_frame (GtkWidget *button,
|
|
GtkWidget *frame)
|
|
{
|
|
gint prev = fpvals.visible_frames;
|
|
|
|
if (frame == NULL)
|
|
return;
|
|
|
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
|
|
{
|
|
if (! gtk_widget_get_visible (frame))
|
|
{
|
|
gtk_widget_show (frame);
|
|
|
|
if (frame==fp_frames.palette)
|
|
fpvals.visible_frames |= HUE;
|
|
else if (frame==fp_frames.satur)
|
|
fpvals.visible_frames |= SATURATION;
|
|
else if (frame==fp_frames.lnd)
|
|
fpvals.visible_frames |= VALUE;
|
|
|
|
fp_refresh_previews (fpvals.visible_frames & ~prev);
|
|
fp_create_smoothness_graph (AW.aliasing_preview);
|
|
fp_range_preview_spill (AW.range_preview,fpvals.value_by);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (gtk_widget_get_visible (frame))
|
|
{
|
|
gtk_widget_hide (frame);
|
|
|
|
if (frame==fp_frames.palette)
|
|
fpvals.visible_frames &= ~HUE;
|
|
else if (frame==fp_frames.satur)
|
|
fpvals.visible_frames &= ~SATURATION;
|
|
else if (frame==fp_frames.lnd)
|
|
fpvals.visible_frames &= ~VALUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_adjust_preview_sizes (gint width,
|
|
gint height)
|
|
{
|
|
gtk_widget_set_size_request (origPreview, width, height);
|
|
gtk_widget_set_size_request (curPreview, width, height);
|
|
gtk_widget_set_size_request (rPreview, width, height);
|
|
gtk_widget_set_size_request (gPreview, width, height);
|
|
gtk_widget_set_size_request (bPreview, width, height);
|
|
gtk_widget_set_size_request (cPreview, width, height);
|
|
gtk_widget_set_size_request (yPreview, width, height);
|
|
gtk_widget_set_size_request (mPreview, width, height);
|
|
gtk_widget_set_size_request (centerPreview, width, height);
|
|
gtk_widget_set_size_request (lighterPreview, width, height);
|
|
gtk_widget_set_size_request (darkerPreview, width, height);
|
|
gtk_widget_set_size_request (middlePreview, width, height);
|
|
gtk_widget_set_size_request (minusSatPreview, width, height);
|
|
gtk_widget_set_size_request (SatPreview, width, height);
|
|
gtk_widget_set_size_request (plusSatPreview, width, height);
|
|
|
|
}
|
|
|
|
static void
|
|
fp_selection_made (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
fpvals.touched[fpvals.value_by] = TRUE;
|
|
|
|
if (data == (gpointer) hue_red)
|
|
{
|
|
update_current_fp (HUE, RED);
|
|
}
|
|
else if (data == (gpointer) hue_green)
|
|
{
|
|
update_current_fp (HUE, GREEN);
|
|
}
|
|
else if (data == (gpointer) hue_blue)
|
|
{
|
|
update_current_fp (HUE, BLUE);
|
|
}
|
|
else if (data == (gpointer) hue_cyan)
|
|
{
|
|
update_current_fp (HUE, CYAN);
|
|
}
|
|
else if (data == (gpointer) hue_yellow)
|
|
{
|
|
update_current_fp (HUE, YELLOW);
|
|
}
|
|
else if (data == (gpointer) hue_magenta)
|
|
{
|
|
update_current_fp (HUE, MAGENTA);
|
|
}
|
|
else if (data == (gpointer) val_darker)
|
|
{
|
|
update_current_fp (VALUE, DOWN);
|
|
}
|
|
else if (data == (gpointer) val_lighter)
|
|
{
|
|
update_current_fp (VALUE, UP);
|
|
}
|
|
else if (data == (gpointer) sat_more)
|
|
{
|
|
update_current_fp (SATURATION, UP);
|
|
}
|
|
else if (data == (gpointer) sat_less)
|
|
{
|
|
update_current_fp (SATURATION, DOWN);
|
|
}
|
|
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
}
|
|
|
|
static void
|
|
fp_refresh_previews (gint which)
|
|
{
|
|
fp_create_nudge (nudgeArray);
|
|
fp_render_preview (origPreview, NONEATALL, 0);
|
|
fp_render_preview (curPreview, CURRENT, 0);
|
|
|
|
if (which & HUE)
|
|
{
|
|
fp_render_preview (rPreview, HUE, RED);
|
|
fp_render_preview (gPreview, HUE, GREEN);
|
|
fp_render_preview (bPreview, HUE, BLUE);
|
|
fp_render_preview (cPreview, HUE, CYAN);
|
|
fp_render_preview (yPreview, HUE, YELLOW);
|
|
fp_render_preview (mPreview, HUE, MAGENTA);
|
|
fp_render_preview (centerPreview, CURRENT, 0);
|
|
}
|
|
|
|
if (which & VALUE)
|
|
{
|
|
fp_render_preview (lighterPreview, VALUE, UP);
|
|
fp_render_preview (middlePreview, CURRENT, 0);
|
|
fp_render_preview (darkerPreview, VALUE, DOWN);
|
|
}
|
|
|
|
if (which & SATURATION)
|
|
{
|
|
fp_render_preview (plusSatPreview, SATURATION, UP);
|
|
fp_render_preview (SatPreview, CURRENT, 0);
|
|
fp_render_preview (minusSatPreview, SATURATION, DOWN);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_response (GtkWidget *widget,
|
|
gint response_id,
|
|
gpointer data)
|
|
{
|
|
switch (response_id)
|
|
{
|
|
case RESPONSE_RESET:
|
|
fp_reset_filter_packs ();
|
|
break;
|
|
|
|
case GTK_RESPONSE_OK:
|
|
FPint.run = TRUE;
|
|
gtk_widget_destroy (widget);
|
|
break;
|
|
|
|
default:
|
|
gtk_widget_destroy (widget);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_scale_update (GtkAdjustment *adjustment,
|
|
gdouble *scale_val)
|
|
{
|
|
static gdouble prevValue = 0.25;
|
|
|
|
*scale_val = gtk_adjustment_get_value (adjustment);
|
|
|
|
if (prevValue != gtk_adjustment_get_value (adjustment))
|
|
{
|
|
fp_create_nudge (nudgeArray);
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
|
|
if (AW.window != NULL && gtk_widget_get_visible (AW.window))
|
|
fp_create_smoothness_graph (AW.aliasing_preview);
|
|
|
|
prevValue = gtk_adjustment_get_value (adjustment);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
fp_dialog (void)
|
|
{
|
|
GtkWidget *bna;
|
|
GtkWidget *palette;
|
|
GtkWidget *lnd;
|
|
GtkWidget *show;
|
|
GtkWidget *rough;
|
|
GtkWidget *range;
|
|
GtkWidget *pixelsBy;
|
|
GtkWidget *satur;
|
|
GtkWidget *control;
|
|
GtkWidget *table;
|
|
|
|
reduced = fp_reduce_image (drawable, mask,
|
|
fpvals.preview_size,
|
|
fpvals.selection_only);
|
|
|
|
gimp_ui_init (PLUG_IN_BINARY, FALSE);
|
|
|
|
dlg = gimp_dialog_new (_("Filter Pack Simulation"), PLUG_IN_ROLE,
|
|
NULL, 0,
|
|
gimp_standard_help_func, PLUG_IN_PROC,
|
|
|
|
GIMP_STOCK_RESET, RESPONSE_RESET,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_OK, GTK_RESPONSE_OK,
|
|
|
|
NULL);
|
|
|
|
gtk_dialog_set_alternative_button_order (GTK_DIALOG (dlg),
|
|
RESPONSE_RESET,
|
|
GTK_RESPONSE_OK,
|
|
GTK_RESPONSE_CANCEL,
|
|
-1);
|
|
|
|
gimp_window_set_transient (GTK_WINDOW (dlg));
|
|
|
|
g_signal_connect (dlg, "response",
|
|
G_CALLBACK (fp_response),
|
|
dlg);
|
|
|
|
g_signal_connect (dlg, "destroy",
|
|
G_CALLBACK (gtk_main_quit),
|
|
NULL);
|
|
|
|
fp_advanced_dialog (dlg);
|
|
|
|
fp_frames.bna = bna = fp_create_bna ();
|
|
fp_frames.rough = rough = fp_create_rough ();
|
|
fp_frames.range = range = fp_create_range ();
|
|
fp_frames.palette = palette = fp_create_circle_palette (dlg);
|
|
fp_frames.lnd = lnd = fp_create_lnd (dlg);
|
|
fp_frames.show = show = fp_create_show ();
|
|
fp_frames.satur = satur = fp_create_msnls (dlg);
|
|
fp_frames.pixelsBy = pixelsBy = fp_create_pixels_select_by ();
|
|
control = fp_create_control ();
|
|
/********************************************************************/
|
|
/******************** PUT EVERYTHING TOGETHER ******************/
|
|
|
|
table = gtk_table_new (4, 2, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
|
|
gtk_container_set_border_width (GTK_CONTAINER (table), 12);
|
|
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
|
|
table, TRUE, TRUE, 0);
|
|
gtk_widget_show (table);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), bna, 0, 2, 0, 1,
|
|
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), control, 1, 2, 1, 3,
|
|
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), rough, 1, 2, 3, 4,
|
|
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), show, 0, 1, 1, 2,
|
|
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), range, 0, 1, 2, 3,
|
|
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), pixelsBy, 0, 1, 3, 4,
|
|
GTK_FILL | GTK_SHRINK, GTK_FILL | GTK_SHRINK, 0, 0);
|
|
|
|
gtk_widget_show (dlg);
|
|
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
|
|
gtk_main ();
|
|
|
|
return FPint.run;
|
|
}
|
|
|
|
/***********************************************************/
|
|
/************ Advanced Options Window ******************/
|
|
/***********************************************************/
|
|
|
|
static void
|
|
fp_preview_scale_update (GtkAdjustment *adjustment,
|
|
gdouble *scale_val)
|
|
{
|
|
fpvals.preview_size = gtk_adjustment_get_value (adjustment);
|
|
fp_redraw_all_windows();
|
|
}
|
|
|
|
static void
|
|
fp_advanced_dialog (GtkWidget *parent)
|
|
{
|
|
const gchar *rangeNames[] = { N_("Shadows:"),
|
|
N_("Midtones:"),
|
|
N_("Highlights:") };
|
|
GtkWidget *frame, *hbox;
|
|
GtkAdjustment *smoothnessData;
|
|
GtkWidget *graphFrame, *scale;
|
|
GtkWidget *vbox, *label, *labelTable, *alignment;
|
|
GtkWidget *inner_vbox, *innermost_vbox;
|
|
gint i;
|
|
|
|
AW.window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
gimp_help_connect (AW.window, gimp_standard_help_func, PLUG_IN_PROC, NULL);
|
|
|
|
gtk_window_set_title (GTK_WINDOW (AW.window),
|
|
_("Advanced Filter Pack Options"));
|
|
gtk_window_set_transient_for (GTK_WINDOW (AW.window), GTK_WINDOW (parent));
|
|
|
|
g_signal_connect (AW.window, "delete-event",
|
|
G_CALLBACK (sub_dialog_destroy),
|
|
NULL);
|
|
|
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
|
|
gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
|
|
gtk_container_add (GTK_CONTAINER (AW.window), hbox);
|
|
gtk_widget_show (hbox);
|
|
|
|
frame = gimp_frame_new (_("Affected Range"));
|
|
gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
|
|
gtk_widget_show (frame);
|
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
|
gtk_widget_show (vbox);
|
|
|
|
graphFrame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1, TRUE);
|
|
gtk_frame_set_shadow_type (GTK_FRAME (graphFrame), GTK_SHADOW_IN);
|
|
gtk_container_set_border_width (GTK_CONTAINER (graphFrame), 0);
|
|
gtk_box_pack_start (GTK_BOX (vbox), graphFrame, FALSE, FALSE, 0);
|
|
gtk_widget_show (graphFrame);
|
|
|
|
inner_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_container_add (GTK_CONTAINER (graphFrame), inner_vbox);
|
|
gtk_widget_show (inner_vbox);
|
|
|
|
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
|
|
gtk_box_pack_start (GTK_BOX (inner_vbox), alignment, TRUE, TRUE, 0);
|
|
gtk_widget_show (alignment);
|
|
|
|
innermost_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_container_add (GTK_CONTAINER (alignment), innermost_vbox);
|
|
gtk_widget_show (innermost_vbox);
|
|
|
|
AW.aliasing_preview = gimp_preview_area_new ();
|
|
gtk_widget_set_size_request (AW.aliasing_preview, 256, MAX_ROUGHNESS);
|
|
gtk_box_pack_start (GTK_BOX (innermost_vbox),
|
|
AW.aliasing_preview, TRUE, TRUE, 0);
|
|
gtk_widget_show (AW.aliasing_preview);
|
|
|
|
fp_create_smoothness_graph (AW.aliasing_preview);
|
|
|
|
AW.range_preview = gimp_preview_area_new ();
|
|
gtk_widget_set_size_request (AW.range_preview, 256, RANGE_HEIGHT);
|
|
gtk_box_pack_start(GTK_BOX (innermost_vbox),
|
|
AW.range_preview, TRUE, TRUE, 0);
|
|
gtk_widget_show (AW.range_preview);
|
|
|
|
fp_range_preview_spill (AW.range_preview, fpvals.value_by);
|
|
|
|
labelTable = gtk_table_new (3, 4, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (labelTable), 6);
|
|
gtk_table_set_row_spacings (GTK_TABLE (labelTable), 6);
|
|
gtk_box_pack_start (GTK_BOX (vbox), labelTable, FALSE, FALSE, 0);
|
|
gtk_widget_show (labelTable);
|
|
|
|
/************************************************************/
|
|
|
|
AW.aliasing_graph = gtk_drawing_area_new ();
|
|
gtk_widget_set_size_request (AW.aliasing_graph,
|
|
2 * MARGIN + 256,
|
|
RANGE_HEIGHT);
|
|
gtk_box_pack_start (GTK_BOX (inner_vbox), AW.aliasing_graph, TRUE, TRUE, 0);
|
|
gtk_widget_show (AW.aliasing_graph);
|
|
gtk_widget_set_events (AW.aliasing_graph, RANGE_ADJUST_MASK);
|
|
|
|
g_signal_connect (AW.aliasing_graph, "event",
|
|
G_CALLBACK (fp_range_change_events),
|
|
&fpvals);
|
|
|
|
/************************************************************/
|
|
|
|
for (i = 0; i < 12; i++)
|
|
{
|
|
label = fp_widgets.range_label[i] = gtk_label_new ("-");
|
|
|
|
if (!(i % 4))
|
|
{
|
|
gtk_label_set_text (GTK_LABEL(label), gettext (rangeNames[i/4]));
|
|
gimp_label_set_attributes (GTK_LABEL (label),
|
|
PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
|
|
-1);
|
|
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
|
|
}
|
|
|
|
gtk_widget_show (label);
|
|
gtk_table_attach (GTK_TABLE (labelTable), label, i%4, i%4+1, i/4, i/4+1,
|
|
GTK_EXPAND | GTK_FILL, 0, 0, 0);
|
|
}
|
|
|
|
smoothnessData = (GtkAdjustment *)
|
|
gtk_adjustment_new (fpvals.aliasing,
|
|
0, 1.0, 0.05, 0.01, 0.0);
|
|
|
|
fp_widgets.aliasing_scale = scale =
|
|
gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, smoothnessData);
|
|
gtk_widget_set_size_request (scale, 200, -1);
|
|
gtk_scale_set_digits (GTK_SCALE (scale), 2);
|
|
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
|
|
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
|
|
gtk_widget_show (scale);
|
|
|
|
g_signal_connect (smoothnessData, "value-changed",
|
|
G_CALLBACK (fp_scale_update),
|
|
&fpvals.aliasing);
|
|
|
|
/******************* MISC OPTIONS ***************************/
|
|
|
|
frame = gimp_frame_new (_("Preview Size"));
|
|
gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
|
|
gtk_widget_show (frame);
|
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
|
gtk_widget_show (vbox);
|
|
|
|
smoothnessData = (GtkAdjustment *)
|
|
gtk_adjustment_new (fpvals.preview_size,
|
|
50, MAX_PREVIEW_SIZE,
|
|
5, 5, 0.0);
|
|
|
|
fp_widgets.preview_size_scale = scale =
|
|
gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, smoothnessData);
|
|
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
|
|
gtk_widget_set_size_request (scale, 100, -1);
|
|
gtk_scale_set_digits (GTK_SCALE (scale), 0);
|
|
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
|
|
gtk_widget_show (scale);
|
|
|
|
g_signal_connect (smoothnessData, "value-changed",
|
|
G_CALLBACK (fp_preview_scale_update),
|
|
&fpvals.preview_size);
|
|
|
|
update_range_labels ();
|
|
}
|
|
|
|
static void
|
|
slider_erase (GdkWindow *window,
|
|
int xpos)
|
|
{
|
|
gdk_window_clear_area (window, MARGIN + xpos - (RANGE_HEIGHT - 1) / 2, 0,
|
|
RANGE_HEIGHT, RANGE_HEIGHT);
|
|
}
|
|
|
|
static void
|
|
draw_slider (cairo_t *cr,
|
|
GdkColor *border_color,
|
|
GdkColor *fill_color,
|
|
gint xpos)
|
|
{
|
|
cairo_move_to (cr, MARGIN + xpos, 0);
|
|
cairo_line_to (cr, MARGIN + xpos - (RANGE_HEIGHT - 1) / 2, RANGE_HEIGHT - 1);
|
|
cairo_line_to (cr, MARGIN + xpos + (RANGE_HEIGHT - 1) / 2, RANGE_HEIGHT - 1);
|
|
cairo_line_to (cr, MARGIN + xpos, 0);
|
|
|
|
gdk_cairo_set_source_color (cr, fill_color);
|
|
cairo_fill_preserve (cr);
|
|
|
|
gdk_cairo_set_source_color (cr, border_color);
|
|
cairo_stroke (cr);
|
|
}
|
|
|
|
static void
|
|
draw_it (GtkWidget *widget)
|
|
{
|
|
GtkStyle *style = gtk_widget_get_style (AW.aliasing_graph);
|
|
cairo_t *cr = gdk_cairo_create (gtk_widget_get_window (AW.aliasing_graph));
|
|
|
|
cairo_translate (cr, 0.5, 0.5);
|
|
cairo_set_line_width (cr, 1.0);
|
|
|
|
draw_slider (cr,
|
|
&style->black,
|
|
&style->dark[GTK_STATE_NORMAL],
|
|
fpvals.cutoff[SHADOWS]);
|
|
|
|
draw_slider (cr,
|
|
&style->black,
|
|
&style->dark[GTK_STATE_NORMAL],
|
|
fpvals.cutoff[MIDTONES]);
|
|
|
|
draw_slider (cr,
|
|
&style->black,
|
|
&style->dark[GTK_STATE_SELECTED],
|
|
fpvals.offset);
|
|
|
|
cairo_destroy (cr);
|
|
}
|
|
|
|
static gboolean
|
|
fp_range_change_events (GtkWidget *widget,
|
|
GdkEvent *event,
|
|
FPValues *current)
|
|
{
|
|
GdkEventButton *bevent;
|
|
GdkEventMotion *mevent;
|
|
gint shad, mid, offset, min;
|
|
static guchar *new;
|
|
gint x;
|
|
|
|
switch (event->type)
|
|
{
|
|
case GDK_EXPOSE:
|
|
draw_it (NULL);
|
|
break;
|
|
|
|
case GDK_BUTTON_PRESS:
|
|
bevent= (GdkEventButton *) event;
|
|
|
|
shad = abs (bevent->x - fpvals.cutoff[SHADOWS]);
|
|
mid = abs (bevent->x - fpvals.cutoff[MIDTONES]);
|
|
offset = abs (bevent->x - fpvals.offset);
|
|
|
|
min = MIN (MIN (shad, mid), offset);
|
|
|
|
if (bevent->x >0 && bevent->x<256)
|
|
{
|
|
if (min == shad)
|
|
new = &fpvals.cutoff[SHADOWS];
|
|
else if (min == mid)
|
|
new = &fpvals.cutoff[MIDTONES];
|
|
else
|
|
new = &fpvals.offset;
|
|
|
|
slider_erase (gtk_widget_get_window (AW.aliasing_graph), *new);
|
|
*new = bevent->x;
|
|
}
|
|
|
|
draw_it (NULL);
|
|
|
|
fp_range_preview_spill (AW.range_preview, fpvals.value_by);
|
|
update_range_labels ();
|
|
fp_create_smoothness_graph (AW.aliasing_preview);
|
|
break;
|
|
|
|
case GDK_BUTTON_RELEASE:
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
break;
|
|
|
|
case GDK_MOTION_NOTIFY:
|
|
mevent = (GdkEventMotion *) event;
|
|
x = mevent->x;
|
|
|
|
if (x >= 0 && x < 256)
|
|
{
|
|
slider_erase (gtk_widget_get_window (AW.aliasing_graph), *new);
|
|
*new = x;
|
|
draw_it (NULL);
|
|
fp_range_preview_spill (AW.range_preview, fpvals.value_by);
|
|
update_range_labels ();
|
|
fp_create_smoothness_graph (AW.aliasing_preview);
|
|
}
|
|
|
|
gdk_event_request_motions (mevent);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
update_range_labels (void)
|
|
{
|
|
gchar buffer[4];
|
|
|
|
gtk_label_set_text (GTK_LABEL(fp_widgets.range_label[1]), "0");
|
|
|
|
g_snprintf (buffer, sizeof (buffer), "%d", fpvals.cutoff[SHADOWS]);
|
|
gtk_label_set_text (GTK_LABEL (fp_widgets.range_label[3]), buffer);
|
|
gtk_label_set_text (GTK_LABEL (fp_widgets.range_label[5]), buffer);
|
|
|
|
g_snprintf (buffer, sizeof (buffer), "%d", fpvals.cutoff[MIDTONES]);
|
|
gtk_label_set_text (GTK_LABEL (fp_widgets.range_label[7]), buffer);
|
|
gtk_label_set_text (GTK_LABEL (fp_widgets.range_label[9]), buffer);
|
|
|
|
gtk_label_set_text (GTK_LABEL(fp_widgets.range_label[11]), "255");
|
|
}
|
|
|
|
static void
|
|
fp_init_filter_packs (void)
|
|
{
|
|
gint i, j;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
for (j = BY_HUE; j < JUDGE_BY; j++)
|
|
{
|
|
fpvals.red_adjust [j][i] = 0;
|
|
fpvals.green_adjust [j][i] = 0;
|
|
fpvals.blue_adjust [j][i] = 0;
|
|
fpvals.sat_adjust [j][i] = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_reset_filter_packs (void)
|
|
{
|
|
fp_init_filter_packs ();
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
}
|
|
|
|
static ReducedImage *
|
|
fp_reduce_image (GimpDrawable *drawable,
|
|
GimpDrawable *mask,
|
|
gint longer_size,
|
|
gint selection)
|
|
{
|
|
gint RH, RW, bytes = drawable->bpp;
|
|
gint x, y, width, height;
|
|
ReducedImage *temp = g_new0 (ReducedImage, 1);
|
|
guchar *tempRGB, *src_row, *tempmask, *src_mask_row, R, G, B;
|
|
gint i, j, whichcol, whichrow;
|
|
GimpPixelRgn srcPR, srcMask;
|
|
gdouble *tempHSV;
|
|
GimpRGB rgb;
|
|
GimpHSV hsv;
|
|
|
|
switch (selection)
|
|
{
|
|
case 0:
|
|
x = 0;
|
|
width = drawable->width;
|
|
y = 0;
|
|
height = drawable->height;
|
|
break;
|
|
|
|
case 1:
|
|
if (! gimp_drawable_mask_intersect (drawable->drawable_id,
|
|
&x, &y, &width, &height))
|
|
return temp;
|
|
break;
|
|
|
|
case 2:
|
|
if (! gimp_drawable_mask_intersect (drawable->drawable_id,
|
|
&x, &y, &width, &height) ||
|
|
! gimp_rectangle_intersect (x - width / 2, y - height / 2,
|
|
2 * width, 2 * height,
|
|
0, 0, drawable->width, drawable->height,
|
|
&x, &y, &width, &height))
|
|
return temp;
|
|
break;
|
|
|
|
default:
|
|
return temp;
|
|
}
|
|
|
|
if (width > height)
|
|
{
|
|
RW = longer_size;
|
|
RH = (gdouble) height * (gdouble) longer_size / (gdouble) width;
|
|
}
|
|
else
|
|
{
|
|
RH = longer_size;
|
|
RW = (gdouble) width * (gdouble) longer_size / (gdouble) height;
|
|
}
|
|
|
|
tempRGB = g_new (guchar, RW * RH * bytes);
|
|
tempHSV = g_new (gdouble, RW * RH * bytes);
|
|
tempmask = g_new (guchar, RW * RH);
|
|
|
|
src_row = g_new (guchar, width * bytes);
|
|
src_mask_row = g_new (guchar, width);
|
|
|
|
gimp_pixel_rgn_init (&srcPR, drawable, x, y, width, height, FALSE, FALSE);
|
|
|
|
if (mask)
|
|
{
|
|
gimp_pixel_rgn_init (&srcMask, mask, x, y, width, height, FALSE, FALSE);
|
|
}
|
|
else
|
|
{
|
|
memset (src_mask_row, 255, width);
|
|
}
|
|
|
|
for (i = 0; i < RH; i++)
|
|
{
|
|
whichrow = (gdouble) i * (gdouble) height / (gdouble) RH;
|
|
|
|
gimp_pixel_rgn_get_row (&srcPR, src_row, x, y + whichrow, width);
|
|
|
|
if (mask)
|
|
gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x, y + whichrow, width);
|
|
|
|
for (j = 0; j < RW; j++)
|
|
{
|
|
whichcol = (gdouble) j * (gdouble) width / (gdouble) RW;
|
|
|
|
tempmask[i * RW + j] = src_mask_row[whichcol];
|
|
|
|
R = src_row[whichcol * bytes + 0];
|
|
G = src_row[whichcol * bytes + 1];
|
|
B = src_row[whichcol * bytes + 2];
|
|
|
|
gimp_rgb_set_uchar (&rgb, R, G, B);
|
|
gimp_rgb_to_hsv (&rgb, &hsv);
|
|
|
|
tempRGB[i * RW * bytes + j * bytes + 0] = R;
|
|
tempRGB[i * RW * bytes + j * bytes + 1] = G;
|
|
tempRGB[i * RW * bytes + j * bytes + 2] = B;
|
|
|
|
tempHSV[i * RW * bytes + j * bytes + 0] = hsv.h;
|
|
tempHSV[i * RW * bytes + j * bytes + 1] = hsv.s;
|
|
tempHSV[i * RW * bytes + j * bytes + 2] = hsv.v;
|
|
|
|
if (bytes == 4)
|
|
{
|
|
tempRGB[i * RW * bytes + j * bytes + 3] =
|
|
src_row[whichcol * bytes + 3];
|
|
}
|
|
}
|
|
}
|
|
|
|
g_free (src_row);
|
|
g_free (src_mask_row);
|
|
|
|
temp->width = RW;
|
|
temp->height = RH;
|
|
temp->rgb = tempRGB;
|
|
temp->hsv = tempHSV;
|
|
temp->mask = tempmask;
|
|
|
|
return temp;
|
|
}
|
|
|
|
static void
|
|
fp_render_preview (GtkWidget *preview,
|
|
gint change_what,
|
|
gint change_which)
|
|
{
|
|
guchar *a;
|
|
gint Inten;
|
|
gint bytes = drawable->bpp;
|
|
gint i, j, k, nudge, M, m, middle, JudgeBy;
|
|
gdouble partial;
|
|
gint RW = reduced->width;
|
|
gint RH = reduced->height;
|
|
gint backupP[3];
|
|
gint P[3];
|
|
gint tempSat[JUDGE_BY][256];
|
|
|
|
a = g_new (guchar, 4 * RW * RH);
|
|
|
|
if (change_what == SATURATION)
|
|
for (k = 0; k < 256; k++)
|
|
{
|
|
for (JudgeBy = BY_HUE; JudgeBy < JUDGE_BY; JudgeBy++)
|
|
tempSat[JudgeBy][k] = 0;
|
|
|
|
tempSat[fpvals.value_by][k] +=
|
|
change_which * nudgeArray[(k + fpvals.offset) % 256];
|
|
}
|
|
|
|
for (i = 0; i < RH; i++)
|
|
{
|
|
for (j = 0; j < RW; j++)
|
|
{
|
|
backupP[0] = P[0] = reduced->rgb[i * RW * bytes + j * bytes + 0];
|
|
backupP[1] = P[1] = reduced->rgb[i * RW * bytes + j * bytes + 1];
|
|
backupP[2] = P[2] = reduced->rgb[i * RW * bytes + j * bytes + 2];
|
|
|
|
m = MIN (MIN (P[0], P[1]), P[2]);
|
|
M = MAX (MAX (P[0], P[1]), P[2]);
|
|
|
|
middle = (M + m) / 2;
|
|
|
|
for (k = 0; k < 3; k++)
|
|
if (P[k] != m && P[k] != M) middle = P[k];
|
|
|
|
partial = reduced->mask[i * RW + j] / 255.0;
|
|
|
|
for (JudgeBy = BY_HUE; JudgeBy < JUDGE_BY; JudgeBy++)
|
|
{
|
|
if (!fpvals.touched[JudgeBy])
|
|
continue;
|
|
|
|
Inten =
|
|
reduced->hsv[i * RW * bytes + j * bytes + JudgeBy] * 255.0;
|
|
|
|
/*DO SATURATION FIRST*/
|
|
if (change_what != NONEATALL)
|
|
{
|
|
gint adjust = partial * fpvals.sat_adjust[JudgeBy][Inten];
|
|
|
|
if (M != m)
|
|
{
|
|
for (k = 0; k < 3; k++)
|
|
if (backupP[k] == M)
|
|
{
|
|
P[k] = MAX (P[k] + adjust, middle);
|
|
}
|
|
else if (backupP[k] == m)
|
|
{
|
|
P[k] = MIN (P[k] - adjust, middle);
|
|
}
|
|
}
|
|
|
|
P[0] += partial * fpvals.red_adjust[JudgeBy][Inten];
|
|
P[1] += partial * fpvals.green_adjust[JudgeBy][Inten];
|
|
P[2] += partial * fpvals.blue_adjust[JudgeBy][Inten];
|
|
}
|
|
}
|
|
|
|
Inten =
|
|
reduced->hsv[i * RW * bytes + j * bytes + fpvals.value_by] * 255.0;
|
|
nudge = partial * nudgeArray[(Inten + fpvals.offset) % 256];
|
|
|
|
switch (change_what)
|
|
{
|
|
case HUE:
|
|
P[0] += colorSign[RED][change_which] * nudge;
|
|
P[1] += colorSign[GREEN][change_which] * nudge;
|
|
P[2] += colorSign[BLUE][change_which] * nudge;
|
|
break;
|
|
|
|
case SATURATION:
|
|
for (JudgeBy = BY_HUE; JudgeBy < JUDGE_BY; JudgeBy++)
|
|
{
|
|
gint adjust = partial * tempSat[JudgeBy][Inten];
|
|
|
|
for (k = 0; k < 3; k++)
|
|
if (M != m)
|
|
{
|
|
if (backupP[k] == M)
|
|
{
|
|
P[k] = MAX (P[k] + adjust, middle);
|
|
}
|
|
else if (backupP[k] == m)
|
|
{
|
|
P[k] = MIN (P[k] - adjust, middle);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VALUE:
|
|
P[0] += change_which * nudge;
|
|
P[1] += change_which * nudge;
|
|
P[2] += change_which * nudge;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
a[(i * RW + j) * 4 + 0] = CLAMP0255 (P[0]);
|
|
a[(i * RW + j) * 4 + 1] = CLAMP0255 (P[1]);
|
|
a[(i * RW + j) * 4 + 2] = CLAMP0255 (P[2]);
|
|
|
|
if (bytes == 4)
|
|
a[(i * RW + j) * 4 + 3] = reduced->rgb[i * RW * bytes + j * bytes + 3];
|
|
else
|
|
a[(i * RW + j) * 4 + 3] = 255;
|
|
}
|
|
}
|
|
|
|
gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
|
|
0, 0, RW, RH,
|
|
GIMP_RGBA_IMAGE,
|
|
a,
|
|
RW * 4);
|
|
g_free (a);
|
|
}
|
|
|
|
static void
|
|
update_current_fp (gint change_what,
|
|
gint change_which)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
gint nudge;
|
|
|
|
fp_create_nudge (nudgeArray);
|
|
nudge = nudgeArray[(i + fpvals.offset) % 256];
|
|
|
|
switch (change_what) {
|
|
case HUE:
|
|
fpvals.red_adjust[fpvals.value_by][i] +=
|
|
colorSign[RED][change_which] * nudge;
|
|
|
|
fpvals.green_adjust[fpvals.value_by][i] +=
|
|
colorSign[GREEN][change_which] * nudge;
|
|
|
|
fpvals.blue_adjust[fpvals.value_by][i] +=
|
|
colorSign[BLUE][change_which] * nudge;
|
|
break;
|
|
|
|
case SATURATION:
|
|
fpvals.sat_adjust[fpvals.value_by][i] += change_which * nudge;
|
|
break;
|
|
|
|
case VALUE:
|
|
fpvals.red_adjust[fpvals.value_by][i] += change_which * nudge;
|
|
fpvals.green_adjust[fpvals.value_by][i] += change_which * nudge;
|
|
fpvals.blue_adjust[fpvals.value_by][i] += change_which * nudge;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_create_smoothness_graph (GtkWidget *preview)
|
|
{
|
|
guchar data[256 * MAX_ROUGHNESS * 3];
|
|
gint nArray[256];
|
|
gint i, j;
|
|
gboolean toBeBlack;
|
|
|
|
fp_create_nudge(nArray);
|
|
|
|
for (i = 0; i < MAX_ROUGHNESS; i++)
|
|
{
|
|
gint coor = MAX_ROUGHNESS - i;
|
|
|
|
for (j = 0; j < 256; j++)
|
|
{
|
|
data[3 * (i * 256 + j) + 0] = 255;
|
|
data[3 * (i * 256 + j) + 1] = 255;
|
|
data[3 * (i * 256 + j) + 2] = 255;
|
|
|
|
if (!(i % (MAX_ROUGHNESS / 4)))
|
|
{
|
|
data[3 * (i * 256 + j) + 0] = 255;
|
|
data[3 * (i * 256 + j) + 1] = 128;
|
|
data[3 * (i * 256 + j) + 2] = 128;
|
|
}
|
|
|
|
if (!((j + 1) % 32))
|
|
{
|
|
data[3 * (i * 256 + j) + 0] = 255;
|
|
data[3 * (i * 256 + j) + 1] = 128;
|
|
data[3 * (i * 256 + j) + 2] = 128;
|
|
}
|
|
|
|
toBeBlack = FALSE;
|
|
|
|
if (nArray[j] == coor)
|
|
toBeBlack = TRUE;
|
|
|
|
if (j < 255)
|
|
{
|
|
gint jump = abs (nArray[j] - nArray[j+1]);
|
|
|
|
if (abs (coor - nArray[j]) < jump &&
|
|
abs (coor - nArray[j + 1]) < jump)
|
|
toBeBlack = TRUE;
|
|
}
|
|
|
|
if (toBeBlack)
|
|
{
|
|
data[3 * (i * 256 + j) + 0] = 0;
|
|
data[3 * (i * 256 + j) + 1] = 0;
|
|
data[3 * (i * 256 + j) + 2] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
|
|
0, 0, 256, MAX_ROUGHNESS,
|
|
GIMP_RGB_IMAGE,
|
|
data,
|
|
256 * 3);
|
|
}
|
|
|
|
static void
|
|
fp_range_preview_spill (GtkWidget *preview,
|
|
gint type)
|
|
{
|
|
gint i, j;
|
|
guchar data[256 * RANGE_HEIGHT * 3];
|
|
|
|
for (i = 0; i < RANGE_HEIGHT; i++)
|
|
{
|
|
for (j = 0; j < 256; j++)
|
|
{
|
|
GimpRGB rgb;
|
|
GimpHSV hsv;
|
|
|
|
if (! ((j + 1) % 32))
|
|
{
|
|
data[3 * (i * 256 + j) + 0] = 255;
|
|
data[3 * (i * 256 + j) + 1] = 128;
|
|
data[3 * (i * 256 + j) + 2] = 128;
|
|
}
|
|
else
|
|
{
|
|
switch (type)
|
|
{
|
|
case BY_VAL:
|
|
data[3 * (i * 256 + j) + 0] = j - fpvals.offset;
|
|
data[3 * (i * 256 + j) + 1] = j - fpvals.offset;
|
|
data[3 * (i * 256 + j) + 2] = j - fpvals.offset;
|
|
break;
|
|
|
|
case BY_HUE:
|
|
gimp_hsv_set (&hsv,
|
|
((j - fpvals.offset + 256) % 256) / 255.0,
|
|
1.0,
|
|
0.5);
|
|
gimp_hsv_to_rgb (&hsv, &rgb);
|
|
gimp_rgb_get_uchar (&rgb,
|
|
&data[3 * (i * 256 + j) + 0],
|
|
&data[3 * (i * 256 + j) + 1],
|
|
&data[3 * (i * 256 + j) + 2]);
|
|
break;
|
|
|
|
case BY_SAT:
|
|
gimp_hsv_set (&hsv,
|
|
0.5,
|
|
((j - (gint) fpvals.offset + 256) % 256) / 255.0,
|
|
0.5);
|
|
gimp_hsv_to_rgb (&hsv, &rgb);
|
|
gimp_rgb_get_uchar (&rgb,
|
|
&data[3 * (i * 256 + j) + 0],
|
|
&data[3 * (i * 256 + j) + 1],
|
|
&data[3 * (i * 256 + j) + 2]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
|
|
0, 0, 256, RANGE_HEIGHT,
|
|
GIMP_RGB_IMAGE,
|
|
data,
|
|
256 * 3);
|
|
}
|
|
|
|
static void
|
|
fp_create_nudge (gint *adj_array)
|
|
{
|
|
gint left, right, middle,i;
|
|
/* The following function was determined by trial and error */
|
|
gdouble Steepness = pow (1 - fpvals.aliasing, 4) * .8;
|
|
|
|
left = (fpvals.intensity_range == SHADOWS) ? 0 : fpvals.cutoff[fpvals.intensity_range - 1];
|
|
right = fpvals.cutoff[fpvals.intensity_range];
|
|
middle = (left + right)/2;
|
|
|
|
if (fpvals.aliasing)
|
|
for (i = 0; i < 256; i++)
|
|
if (i <= middle)
|
|
adj_array[i] = MAX_ROUGHNESS *
|
|
fpvals.roughness * (1 + tanh (Steepness * (i - left))) / 2;
|
|
else
|
|
adj_array[i] = MAX_ROUGHNESS *
|
|
fpvals.roughness * (1 + tanh (Steepness * (right - i))) / 2;
|
|
else
|
|
for (i = 0; i < 256; i++)
|
|
adj_array[i] = (left <= i && i <= right)
|
|
? MAX_ROUGHNESS * fpvals.roughness : 0;
|
|
}
|
|
|
|
static void
|
|
fp_preview_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation)
|
|
{
|
|
gint which = fpvals.visible_frames;
|
|
|
|
if (widget == origPreview)
|
|
fp_render_preview (origPreview, NONEATALL, 0);
|
|
else if (widget == curPreview)
|
|
fp_render_preview (curPreview, CURRENT, 0);
|
|
|
|
if (which & HUE)
|
|
{
|
|
if (widget == rPreview)
|
|
fp_render_preview (rPreview, HUE, RED);
|
|
else if (widget == gPreview)
|
|
fp_render_preview (gPreview, HUE, GREEN);
|
|
else if (widget == bPreview)
|
|
fp_render_preview (bPreview, HUE, BLUE);
|
|
else if (widget == cPreview)
|
|
fp_render_preview (cPreview, HUE, CYAN);
|
|
else if (widget == yPreview)
|
|
fp_render_preview (yPreview, HUE, YELLOW);
|
|
else if (widget == mPreview)
|
|
fp_render_preview (mPreview, HUE, MAGENTA);
|
|
else if (widget == centerPreview)
|
|
fp_render_preview (centerPreview, CURRENT, 0);
|
|
}
|
|
|
|
if (which & VALUE)
|
|
{
|
|
if (widget == lighterPreview)
|
|
fp_render_preview (lighterPreview, VALUE, UP);
|
|
else if (widget == middlePreview)
|
|
fp_render_preview (middlePreview, CURRENT, 0);
|
|
else if (widget == darkerPreview)
|
|
fp_render_preview (darkerPreview, VALUE, DOWN);
|
|
}
|
|
|
|
if (which & SATURATION)
|
|
{
|
|
if (widget == plusSatPreview)
|
|
fp_render_preview (plusSatPreview, SATURATION, UP);
|
|
else if (widget == SatPreview)
|
|
fp_render_preview (SatPreview, CURRENT, 0);
|
|
else if (widget == minusSatPreview)
|
|
fp_render_preview (minusSatPreview, SATURATION, DOWN);
|
|
}
|
|
}
|