Commit ef885f76 authored by Sven Neumann's avatar Sven Neumann Committed by Sven Neumann

Added an RGB histogram based on a patch by Tor Lillqvist. Fixes bug

2004-07-06  Sven Neumann  <sven@gimp.org>

	Added an RGB histogram based on a patch by Tor Lillqvist. Fixes
	bug #145401.

	* app/base/base-enums.[ch]: added GIMP_HISTOGRAM_RGB, don't export
	it to the PDB.

	* app/base/gimphistogram.c: implemented histogram functions for
	the RGB mode.

	* app/base/levels.c
	* app/tools/gimpcurvestool.c
	* app/tools/gimplevelstool.c
	* app/widgets/gimpcolorbar.c
	* app/widgets/gimphistogrameditor.c: handle the new enum value.

	* app/widgets/gimphistogramview.c: for GIMP_HISTOGRAM_RGB mode,
	draw a histogram that shows the RGB channels simultaneously
parent 5b5e8c05
2004-07-06 Sven Neumann <sven@gimp.org>
Added an RGB histogram based on a patch by Tor Lillqvist. Fixes
bug #145401.
* app/base/base-enums.[ch]: added GIMP_HISTOGRAM_RGB, don't export
it to the PDB.
* app/base/gimphistogram.c: implemented histogram functions for
the RGB mode.
* app/base/levels.c
* app/tools/gimpcurvestool.c
* app/tools/gimplevelstool.c
* app/widgets/gimpcolorbar.c
* app/widgets/gimphistogrameditor.c: handle the new enum value.
* app/widgets/gimphistogramview.c: for GIMP_HISTOGRAM_RGB mode,
draw a histogram that shows the RGB channels simultaneously
2004-07-06 Sven Neumann <sven@gimp.org>
* libgimpmodule/gimpmodule.c: comply with C99 aliasing rules.
......
......@@ -77,6 +77,7 @@ static const GEnumValue gimp_histogram_channel_enum_values[] =
{ GIMP_HISTOGRAM_GREEN, N_("Green"), "green" },
{ GIMP_HISTOGRAM_BLUE, N_("Blue"), "blue" },
{ GIMP_HISTOGRAM_ALPHA, N_("Alpha"), "alpha" },
{ GIMP_HISTOGRAM_RGB, N_("RGB"), "rgb" },
{ 0, NULL, NULL }
};
......
......@@ -83,7 +83,8 @@ typedef enum
GIMP_HISTOGRAM_RED = 1, /*< desc="Red" >*/
GIMP_HISTOGRAM_GREEN = 2, /*< desc="Green" >*/
GIMP_HISTOGRAM_BLUE = 3, /*< desc="Blue" >*/
GIMP_HISTOGRAM_ALPHA = 4 /*< desc="Alpha" >*/
GIMP_HISTOGRAM_ALPHA = 4, /*< desc="Alpha" >*/
GIMP_HISTOGRAM_RGB = 5 /*< desc="RGB", pdb-skip >*/
} GimpHistogramChannel;
......
......@@ -178,12 +178,21 @@ gimp_histogram_get_maximum (GimpHistogram *histogram,
if (histogram->n_channels == 3 && channel == GIMP_HISTOGRAM_ALPHA)
channel = 1;
if (! histogram->values || channel >= histogram->n_channels)
if (! histogram->values ||
(channel != GIMP_HISTOGRAM_RGB && channel >= histogram->n_channels))
return 0.0;
for (x = 0; x < 256; x++)
if (histogram->values[channel][x] > max)
max = histogram->values[channel][x];
if (channel == GIMP_HISTOGRAM_RGB)
for (x = 0; x < 256; x++)
{
max = MAX (max, histogram->values[GIMP_HISTOGRAM_RED][x]);
max = MAX (max, histogram->values[GIMP_HISTOGRAM_GREEN][x]);
max = MAX (max, histogram->values[GIMP_HISTOGRAM_BLUE][x]);
}
else
for (x = 0; x < 256; x++)
if (histogram->values[channel][x] > max)
max = histogram->values[channel][x];
return max;
}
......@@ -199,12 +208,22 @@ gimp_histogram_get_value (GimpHistogram *histogram,
if (histogram->n_channels == 3 && channel == GIMP_HISTOGRAM_ALPHA)
channel = 1;
if (histogram->values &&
channel < histogram->n_channels &&
bin >= 0 && bin < 256)
return histogram->values[channel][bin];
if (! histogram->values ||
bin < 0 || bin >= 256 ||
(channel == GIMP_HISTOGRAM_RGB && histogram->n_channels < 4) ||
(channel != GIMP_HISTOGRAM_RGB && channel >= histogram->n_channels))
return 0.0;
if (channel == GIMP_HISTOGRAM_RGB)
{
gdouble min = histogram->values[GIMP_HISTOGRAM_RED][bin];
min = MIN (min, histogram->values[GIMP_HISTOGRAM_GREEN][bin]);
return 0.0;
return MIN (min, histogram->values[GIMP_HISTOGRAM_BLUE][bin]);
}
else
return histogram->values[channel][bin];
}
gdouble
......@@ -243,9 +262,22 @@ gimp_histogram_get_count (GimpHistogram *histogram,
if (histogram->n_channels == 3 && channel == GIMP_HISTOGRAM_ALPHA)
channel = 1;
if (! histogram->values || channel >= histogram->n_channels)
if (channel == GIMP_HISTOGRAM_RGB)
return (gimp_histogram_get_count (histogram,
GIMP_HISTOGRAM_RED, start, end) +
gimp_histogram_get_count (histogram,
GIMP_HISTOGRAM_GREEN, start, end) +
gimp_histogram_get_count (histogram,
GIMP_HISTOGRAM_BLUE, start, end));
if (! histogram->values ||
start > end ||
channel >= histogram->n_channels)
return 0.0;
start = CLAMP (start, 0, 255);
end = CLAMP (end, 0, 255);
for (i = start; i <= end; i++)
count += histogram->values[channel][i];
......@@ -268,11 +300,27 @@ gimp_histogram_get_mean (GimpHistogram *histogram,
if (histogram->n_channels == 3 && channel == GIMP_HISTOGRAM_ALPHA)
channel = 1;
if (! histogram->values || channel >= histogram->n_channels)
if (! histogram->values ||
start > end ||
(channel == GIMP_HISTOGRAM_RGB && histogram->n_channels < 4) ||
(channel != GIMP_HISTOGRAM_RGB && channel >= histogram->n_channels))
return 0.0;
for (i = start; i <= end; i++)
mean += i * histogram->values[channel][i];
start = CLAMP (start, 0, 255);
end = CLAMP (end, 0, 255);
if (channel == GIMP_HISTOGRAM_RGB)
{
for (i = start; i <= end; i++)
mean += (i * histogram->values[GIMP_HISTOGRAM_RED][i] +
i * histogram->values[GIMP_HISTOGRAM_GREEN][i] +
i * histogram->values[GIMP_HISTOGRAM_BLUE][i]);
}
else
{
for (i = start; i <= end; i++)
mean += i * histogram->values[channel][i];
}
count = gimp_histogram_get_count (histogram, channel, start, end);
......@@ -298,18 +346,35 @@ gimp_histogram_get_median (GimpHistogram *histogram,
if (histogram->n_channels == 3 && channel == GIMP_HISTOGRAM_ALPHA)
channel = 1;
if (! histogram->values || channel >= histogram->n_channels)
if (! histogram->values ||
start > end ||
(channel == GIMP_HISTOGRAM_RGB && histogram->n_channels < 4) ||
(channel != GIMP_HISTOGRAM_RGB && channel >= histogram->n_channels))
return 0;
start = CLAMP (start, 0, 255);
end = CLAMP (end, 0, 255);
count = gimp_histogram_get_count (histogram, channel, start, end);
for (i = start; i <= end; i++)
{
sum += histogram->values[channel][i];
if (channel == GIMP_HISTOGRAM_RGB)
for (i = start; i <= end; i++)
{
sum += (histogram->values[GIMP_HISTOGRAM_RED][i] +
histogram->values[GIMP_HISTOGRAM_GREEN][i] +
histogram->values[GIMP_HISTOGRAM_BLUE][i]);
if (sum * 2 > count)
return i;
}
if (sum * 2 > count)
return i;
}
else
for (i = start; i <= end; i++)
{
sum += histogram->values[channel][i];
if (sum * 2 > count)
return i;
}
return -1;
}
......@@ -331,7 +396,10 @@ gimp_histogram_get_std_dev (GimpHistogram *histogram,
if (histogram->n_channels == 3 && channel == GIMP_HISTOGRAM_ALPHA)
channel = 1;
if (! histogram->values || channel >= histogram->n_channels)
if (! histogram->values ||
start > end ||
(channel == GIMP_HISTOGRAM_RGB && histogram->n_channels < 4) ||
(channel != GIMP_HISTOGRAM_RGB && channel >= histogram->n_channels))
return 0.0;
mean = gimp_histogram_get_mean (histogram, channel, start, end);
......@@ -452,7 +520,7 @@ gimp_histogram_calculate_sub_region (GimpHistogram *histogram,
}
break;
case 3: /* calculate seperate value values */
case 3: /* calculate separate value values */
while (w--)
{
masked = m[0] / 255.0;
......@@ -471,7 +539,7 @@ gimp_histogram_calculate_sub_region (GimpHistogram *histogram,
}
break;
case 4: /* calculate seperate value values */
case 4: /* calculate separate value values */
while (w--)
{
masked = m[0] / 255.0;
......@@ -524,7 +592,7 @@ gimp_histogram_calculate_sub_region (GimpHistogram *histogram,
}
break;
case 3: /* calculate seperate value values */
case 3: /* calculate separate value values */
while (w--)
{
values[1][s[0]] += 1.0;
......@@ -541,7 +609,7 @@ gimp_histogram_calculate_sub_region (GimpHistogram *histogram,
}
break;
case 4: /* calculate seperate value values */
case 4: /* calculate separate value values */
while (w--)
{
values[1][s[0]] += 1.0;
......
......@@ -163,6 +163,8 @@ levels_input_from_color (GimpHistogramChannel channel,
return color[BLUE_PIX];
case GIMP_HISTOGRAM_ALPHA:
return color[ALPHA_PIX];
case GIMP_HISTOGRAM_RGB:
return MIN (MIN (color[RED_PIX], color[GREEN_PIX]), color[BLUE_PIX]);
}
return 0; /* just to please the compiler */
......
......@@ -774,6 +774,7 @@ curves_update (GimpCurvesTool *tool,
{
case GIMP_HISTOGRAM_VALUE:
case GIMP_HISTOGRAM_ALPHA:
case GIMP_HISTOGRAM_RGB:
gimp_color_bar_set_buffers (GIMP_COLOR_BAR (tool->xrange),
tool->curves->curve[tool->channel],
tool->curves->curve[tool->channel],
......@@ -853,6 +854,9 @@ curves_menu_visible_func (GtkTreeModel *model,
case GIMP_HISTOGRAM_ALPHA:
return tool->alpha;
case GIMP_HISTOGRAM_RGB:
return FALSE;
}
return FALSE;
......
......@@ -870,6 +870,7 @@ levels_update (GimpLevelsTool *tool,
{
case GIMP_HISTOGRAM_VALUE:
case GIMP_HISTOGRAM_ALPHA:
case GIMP_HISTOGRAM_RGB:
gimp_color_bar_set_buffers (GIMP_COLOR_BAR (tool->input_bar),
tool->levels->input[tool->channel],
tool->levels->input[tool->channel],
......@@ -954,6 +955,9 @@ levels_menu_visible_func (GtkTreeModel *model,
case GIMP_HISTOGRAM_ALPHA:
return tool->alpha;
case GIMP_HISTOGRAM_RGB:
return FALSE;
}
return FALSE;
......
......@@ -278,6 +278,7 @@ gimp_color_bar_set_channel (GimpColorBar *bar,
{
case GIMP_HISTOGRAM_VALUE:
case GIMP_HISTOGRAM_ALPHA:
case GIMP_HISTOGRAM_RGB:
gimp_rgb_set (&color, 1.0, 1.0, 1.0);
break;
case GIMP_HISTOGRAM_RED:
......
......@@ -403,6 +403,7 @@ gimp_histogram_editor_item_visible (GtkTreeModel *model,
case GIMP_HISTOGRAM_RED:
case GIMP_HISTOGRAM_GREEN:
case GIMP_HISTOGRAM_BLUE:
case GIMP_HISTOGRAM_RGB:
return editor->drawable && gimp_drawable_is_rgb (editor->drawable);
case GIMP_HISTOGRAM_ALPHA:
......
......@@ -72,6 +72,16 @@ static gboolean gimp_histogram_view_button_release (GtkWidget *widget,
static gboolean gimp_histogram_view_motion_notify (GtkWidget *widget,
GdkEventMotion *bevent);
static void gimp_histogram_view_draw_spike (GimpHistogramView *view,
GimpHistogramChannel channel,
GdkGC *gc,
gint x,
gint i,
gint j,
gint max,
gint height,
gint border);
static guint histogram_view_signals[LAST_SIGNAL] = { 0 };
......@@ -245,17 +255,42 @@ gimp_histogram_view_size_request (GtkWidget *widget,
requisition->height = MIN_HEIGHT + 2 * view->border_width;
}
static gdouble
gimp_histogram_view_get_maximum (GimpHistogramView *view,
GimpHistogramChannel channel)
{
gdouble max = gimp_histogram_get_maximum (view->histogram, channel);
switch (view->scale)
{
case GIMP_HISTOGRAM_SCALE_LINEAR:
break;
case GIMP_HISTOGRAM_SCALE_LOGARITHMIC:
if (max > 0.0)
max = log (max);
else
max = 1.0;
break;
}
return max;
}
static gboolean
gimp_histogram_view_expose (GtkWidget *widget,
GdkEventExpose *event)
{
GimpHistogramView *view = GIMP_HISTOGRAM_VIEW (widget);
gint x, y;
gint x;
gint x1, x2;
gint border;
gint width, height;
gdouble max;
gint xstop;
GdkGC *gc_in;
GdkGC *gc_out;
GdkGC *rgb_gc[3] = { NULL, NULL, NULL };
if (! view->histogram)
return FALSE;
......@@ -264,26 +299,9 @@ gimp_histogram_view_expose (GtkWidget *widget,
width = widget->allocation.width - 2 * border;
height = widget->allocation.height - 2 * border;
/* find the maximum value */
max = gimp_histogram_get_maximum (view->histogram, view->channel);
switch (view->scale)
{
case GIMP_HISTOGRAM_SCALE_LINEAR:
break;
case GIMP_HISTOGRAM_SCALE_LOGARITHMIC:
if (max > 0.0)
max = log (max);
else
max = 1.0;
break;
}
x1 = CLAMP (MIN (view->start, view->end), 0, 255);
x2 = CLAMP (MAX (view->start, view->end), 0, 255);
/* Draw the background */
gdk_draw_rectangle (widget->window,
widget->style->base_gc[GTK_STATE_NORMAL], TRUE,
0, 0,
......@@ -296,31 +314,51 @@ gimp_histogram_view_expose (GtkWidget *widget,
border, border,
width - 1, height - 1);
/* Draw the spikes */
max = gimp_histogram_view_get_maximum (view, view->channel);
gc_in = (view->light_histogram ?
widget->style->mid_gc[GTK_STATE_SELECTED] :
widget->style->text_gc[GTK_STATE_SELECTED]);
gc_out = (view->light_histogram ?
widget->style->mid_gc[GTK_STATE_NORMAL] :
widget->style->text_gc[GTK_STATE_NORMAL]);
if (view->channel == GIMP_HISTOGRAM_RGB)
{
GdkGCValues values;
GdkColor color;
values.function = GDK_OR;
for (x = 0; x < 3; x++)
{
rgb_gc[x] = gdk_gc_new_with_values (widget->window,
&values, GDK_GC_FUNCTION);
color.red = (x == 0 ? 0xFFFF : 0x0);
color.green = (x == 1 ? 0xFFFF : 0x0);
color.blue = (x == 2 ? 0xFFFF : 0x0);
gdk_gc_set_rgb_fg_color (rgb_gc[x], &color);
}
}
xstop = 1;
for (x = 0; x < width; x++)
{
gdouble value = 0.0;
gint i, j;
gboolean in_selection = FALSE;
GdkGC *spike_gc;
i = (x * 256) / width;
j = ((x + 1) * 256) / width;
gint i = (x * 256) / width;
gint j = ((x + 1) * 256) / width;
do
if (! (x1 == 0 && x2 == 255))
{
gdouble v;
if (! in_selection)
in_selection = ((x1 != 0 || x2 != 255) && x1 <= i && i <= x2);
v = gimp_histogram_get_value (view->histogram, view->channel, i++);
gint k;
if (v > value)
value = v;
for (k = i; k < j && !in_selection; k++)
in_selection = (x1 <= k && k <= x2);
}
while (i < j);
if (view->subdivisions > 1 && x >= (xstop * width / view->subdivisions))
{
......@@ -338,48 +376,81 @@ gimp_histogram_view_expose (GtkWidget *widget,
x + border, border + height - 1);
}
if (value <= 0.0)
continue;
switch (view->scale)
if (view->channel == GIMP_HISTOGRAM_RGB)
{
case GIMP_HISTOGRAM_SCALE_LINEAR:
y = (gint) (((height - 1) * value) / max);
break;
case GIMP_HISTOGRAM_SCALE_LOGARITHMIC:
y = (gint) (((height - 1) * log (value)) / max);
break;
gint c;
default:
y = 0;
break;
}
for (c = 0; c < 3; c++)
gimp_histogram_view_draw_spike (view, GIMP_HISTOGRAM_RED + c,
widget->style->black_gc,
x, i, j, max, height, border);
if (in_selection)
{
if (view->light_histogram)
spike_gc = widget->style->mid_gc[GTK_STATE_SELECTED];
else
spike_gc = widget->style->text_gc[GTK_STATE_SELECTED];
}
else
{
if (view->light_histogram)
spike_gc = widget->style->mid_gc[GTK_STATE_NORMAL];
else
spike_gc = widget->style->text_gc[GTK_STATE_NORMAL];
for (c = 0; c < 3; c++)
gimp_histogram_view_draw_spike (view, GIMP_HISTOGRAM_RED + c,
rgb_gc[c],
x, i, j, max, height, border);
}
gdk_draw_line (widget->window,
spike_gc,
x + border, height + border - 1,
x + border, height + border - y - 1);
gimp_histogram_view_draw_spike (view, view->channel,
in_selection ? gc_in : gc_out,
x, i, j, max, height, border);
}
if (view->channel == GIMP_HISTOGRAM_RGB)
{
for (x = 0; x < 3; x++)
g_object_unref (rgb_gc[x]);
}
return FALSE;
}
static void
gimp_histogram_view_draw_spike (GimpHistogramView *view,
GimpHistogramChannel channel,
GdkGC *gc,
gint x,
gint i,
gint j,
gint max,
gint height,
gint border)
{
gdouble value = 0.0;
gint y;
do
{
gdouble v = gimp_histogram_get_value (view->histogram, channel, i++);
if (v > value)
value = v;
}
while (i < j);
if (value <= 0.0)
return;
switch (view->scale)
{
case GIMP_HISTOGRAM_SCALE_LINEAR:
y = (gint) (((height - 1) * value) / max);
break;
case GIMP_HISTOGRAM_SCALE_LOGARITHMIC:
y = (gint) (((height - 1) * log (value)) / max);
break;
default:
y = 0;
break;
}
gdk_draw_line (GTK_WIDGET (view)->window, gc,
x + border, height + border - 1,
x + border, height + border - y - 1);
}
static gboolean
gimp_histogram_view_button_press (GtkWidget *widget,
GdkEventButton *bevent)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment