[gthumb] unify equalize histogram and adjust contrast
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] unify equalize histogram and adjust contrast
- Date: Tue, 23 Dec 2014 11:33:16 +0000 (UTC)
commit c9c54e9ad5252982949efab46c4344112cf190b6
Author: Paolo Bacchilega <paobac src gnome org>
Date: Sun Dec 21 19:58:23 2014 +0100
unify equalize histogram and adjust contrast
show a preview of the various contrast filters
extensions/file_tools/Makefile.am | 2 -
extensions/file_tools/data/ui/Makefile.am | 1 +
.../file_tools/data/ui/adjust-contrast-options.ui | 101 ++++
.../file_tools/gth-file-tool-adjust-contrast.c | 615 ++++++++++++++++----
.../file_tools/gth-file-tool-adjust-contrast.h | 4 +-
extensions/file_tools/gth-file-tool-equalize.c | 187 ------
extensions/file_tools/gth-file-tool-equalize.h | 52 --
extensions/file_tools/main.c | 2 -
gthumb/gth-histogram.c | 77 +++-
gthumb/gth-histogram.h | 5 +
po/POTFILES.in | 3 +-
11 files changed, 682 insertions(+), 367 deletions(-)
---
diff --git a/extensions/file_tools/Makefile.am b/extensions/file_tools/Makefile.am
index 6626529..26d6a2e 100644
--- a/extensions/file_tools/Makefile.am
+++ b/extensions/file_tools/Makefile.am
@@ -13,7 +13,6 @@ HEADER_FILES = \
gth-file-tool-adjust-colors.h \
gth-file-tool-adjust-contrast.h \
gth-file-tool-crop.h \
- gth-file-tool-equalize.h \
gth-file-tool-flip.h \
gth-file-tool-grayscale.h \
gth-file-tool-mirror.h \
@@ -62,7 +61,6 @@ libfile_tools_la_SOURCES = \
gth-file-tool-adjust-colors.c \
gth-file-tool-adjust-contrast.c \
gth-file-tool-crop.c \
- gth-file-tool-equalize.c \
gth-file-tool-flip.c \
gth-file-tool-grayscale.c \
gth-file-tool-mirror.c \
diff --git a/extensions/file_tools/data/ui/Makefile.am b/extensions/file_tools/data/ui/Makefile.am
index 47e64d1..d5bfe37 100644
--- a/extensions/file_tools/data/ui/Makefile.am
+++ b/extensions/file_tools/data/ui/Makefile.am
@@ -1,6 +1,7 @@
uidir = $(pkgdatadir)/ui
ui_DATA = \
adjust-colors-options.ui \
+ adjust-contrast-options.ui \
crop-options.ui \
grayscale-options.ui \
resize-options.ui \
diff --git a/extensions/file_tools/data/ui/adjust-contrast-options.ui
b/extensions/file_tools/data/ui/adjust-contrast-options.ui
new file mode 100644
index 0000000..bf34634
--- /dev/null
+++ b/extensions/file_tools/data/ui/adjust-contrast-options.ui
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
+<interface>
+ <requires lib="gtk+" version="3.12"/>
+ <object class="GtkAlignment" id="options">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">12</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkBox" id="filter_grid_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator" id="separator1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="padding">6</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButtonBox" id="buttonbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">12</property>
+ <property name="homogeneous">True</property>
+ <property name="layout_style">center</property>
+ <child>
+ <object class="GtkButton" id="ok_button">
+ <property name="label">gtk-ok</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="label">gtk-cancel</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">6</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/extensions/file_tools/gth-file-tool-adjust-contrast.c
b/extensions/file_tools/gth-file-tool-adjust-contrast.c
index ef8f36d..b89844e 100644
--- a/extensions/file_tools/gth-file-tool-adjust-contrast.c
+++ b/extensions/file_tools/gth-file-tool-adjust-contrast.c
@@ -3,7 +3,7 @@
/*
* GThumb
*
- * Copyright (C) 2012 Free Software Foundation, Inc.
+ * Copyright (C) 2011-2014 Free Software Foundation, Inc.
*
* 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
@@ -21,91 +21,199 @@
#include <config.h>
#include <math.h>
+#include <gthumb.h>
+#include <extensions/image_viewer/image-viewer.h>
#include "gth-file-tool-adjust-contrast.h"
+#include "gth-preview-tool.h"
-#define HISTOGRAM_CROP 0.005
+#define GET_WIDGET(x) (_gtk_builder_get_widget (self->priv->builder, (x)))
+#define APPLY_DELAY 150
+#define PREVIEW_SIZE 0.9
+#define HISTOGRAM_CROP 0.005 /* ignores the 0.5% on each side of the adjust_contrast */
+#define HISTOGRAM_CROP_MAX 0.015 /* ignores the 1.5% on each side of the adjust_contrast */
G_DEFINE_TYPE (GthFileToolAdjustContrast, gth_file_tool_adjust_contrast, GTH_TYPE_IMAGE_VIEWER_PAGE_TOOL)
+typedef enum {
+ METHOD_STRETCH,
+ METHOD_STRETCH_MAX,
+ METHOD_EQUALIZE_LINEAR,
+ METHOD_EQUALIZE_SQUARE_ROOT
+} Method;
+
+
+struct _GthFileToolAdjustContrastPrivate {
+ cairo_surface_t *destination;
+ cairo_surface_t *preview;
+ GtkBuilder *builder;
+ GthTask *image_task;
+ GthImageViewerTool *preview_tool;
+ guint apply_event;
+ gboolean apply_to_original;
+ gboolean closing;
+ Method method;
+ Method last_applied_method;
+ gboolean view_original;
+};
+
+
+/* equalize histogram */
+
+
typedef struct {
- GtkWidget *viewer_page;
- int *lowest;
- int *highest;
- double *factor;
-} AdjustContrastData;
+ Method method;
+ long **value_map;
+} EqualizeData;
static void
-adjust_contrast_setup (AdjustContrastData *adjust_data,
- cairo_surface_t *source)
+value_map_free (long **value_map)
{
- GthHistogram *histogram;
- long **cumulative;
- int c, v;
- glong n_pixels;
- double lower_threshold;
- double higher_threshold;
+ int c;
- /* histogram */
+ for (c = 0; c < GTH_HISTOGRAM_N_CHANNELS; c++)
+ g_free (value_map[c]);
+ g_free (value_map);
+}
- histogram = gth_histogram_new ();
- gth_histogram_calculate_for_image (histogram, source);
- cumulative = gth_histogram_get_cumulative (histogram);
- /* lowest and highest values for each channel */
+static double
+get_histogram_value (GthHistogram *histogram,
+ GthHistogramChannel channel,
+ int bin,
+ Method method)
+{
+ double h = gth_histogram_get_value (histogram, channel, bin);
+ if (method == METHOD_EQUALIZE_SQUARE_ROOT)
+ return (h >= 2) ? sqrt (h) : h;
+ else
+ return h;
+}
+
+
+static long **
+get_value_map_for_equalize (GthHistogram *histogram,
+ Method method)
+{
+ long **value_map;
+ int c, v;
+
+ value_map = g_new (long *, GTH_HISTOGRAM_N_CHANNELS);
+ for (c = 0; c < GTH_HISTOGRAM_N_CHANNELS; c++) {
+ double sum;
+ double scale;
+
+ sum = 0.0;
+ for (v = 0; v < 255; v++)
+ sum += 2 * get_histogram_value (histogram, c, v, method);
+ sum += get_histogram_value (histogram, c, 255, method);
+ scale = 255 / sum;
+
+ value_map[c] = g_new (long, 256);
+ value_map[c][0] = 0;
+ sum = get_histogram_value (histogram, c, 0, method);
+ for (v = 1; v < 255; v++) {
+ double delta = get_histogram_value (histogram, c, v, method);
+ sum += delta;
+ value_map[c][v] = (int) round (sum * scale);
+ sum += delta;
+ }
+ value_map[c][255] = 255;
+ }
+
+ return value_map;
+}
- adjust_data->lowest = g_new (int, GTH_HISTOGRAM_N_CHANNELS);
- adjust_data->highest = g_new (int, GTH_HISTOGRAM_N_CHANNELS);
- n_pixels = cairo_image_surface_get_width (source) * cairo_image_surface_get_height (source);
- lower_threshold = HISTOGRAM_CROP * n_pixels;
- higher_threshold = (1.0 - HISTOGRAM_CROP) * n_pixels;
+static long **
+get_value_map_for_stretch (GthHistogram *histogram,
+ Method method)
+{
+ long **value_map;
+ int n_pixels, lower_limit, higher_limit;
+ int c, v;
+
+ n_pixels = gth_histogram_get_n_pixels (histogram);
+ if (method == METHOD_STRETCH) {
+ lower_limit = n_pixels * HISTOGRAM_CROP;
+ higher_limit = n_pixels * (1 - HISTOGRAM_CROP);
+ }
+ else {
+ lower_limit = n_pixels * HISTOGRAM_CROP_MAX;
+ higher_limit = n_pixels * (1 - HISTOGRAM_CROP_MAX);
+ }
+ value_map = g_new (long *, GTH_HISTOGRAM_N_CHANNELS);
for (c = 0; c < GTH_HISTOGRAM_N_CHANNELS; c++) {
- gboolean lowest_set = FALSE;
+ guchar min, max;
+ double sum, scale;
+ min = 0;
+ sum = 0;
for (v = 0; v < 256; v++) {
- if (! lowest_set && (cumulative[c][v] >= lower_threshold)) {
- adjust_data->lowest[c] = v;
- lowest_set = TRUE;
+ sum += gth_histogram_get_value (histogram, c, v);
+ if (sum >= lower_limit) {
+ min = v;
+ break;
}
+ }
- if (cumulative[c][v] <= higher_threshold)
- adjust_data->highest[c] = v;
+ max = 0;
+ sum = 0;
+ for (v = 0; v < 256; v++) {
+ sum += gth_histogram_get_value (histogram, c, v);
+ if (sum <= higher_limit)
+ max = v;
}
- }
- /* stretch factor */
+ scale = 255.0 / (max - min);
- adjust_data->factor = g_new (double, GTH_HISTOGRAM_N_CHANNELS);
- for (c = 0; c < GTH_HISTOGRAM_N_CHANNELS; c++) {
- if (adjust_data->highest[c] != adjust_data->lowest[c])
- adjust_data->factor[c] = 255.0 / ((double) adjust_data->highest[c] -
adjust_data->lowest[c]);
- else
- adjust_data->factor[c] = 0.0;
+ value_map[c] = g_new (long, 256);
+ for (v = 0; v <= min; v++)
+ value_map[c][v] = 0;
+ for (v = min + 1; v < max; v++)
+ value_map[c][v] = (int) round (scale * (v - min));
+ for (v = max; v <= 255; v++)
+ value_map[c][v] = 255;
}
- /**/
+ return value_map;
+}
+
+
+static void
+adjust_contrast_setup (EqualizeData *equalize_data,
+ cairo_surface_t *source)
+{
+ GthHistogram *histogram;
+ int c;
+
+ histogram = gth_histogram_new ();
+ gth_histogram_calculate_for_image (histogram, source);
+ switch (equalize_data->method) {
+ case METHOD_STRETCH:
+ case METHOD_STRETCH_MAX:
+ equalize_data->value_map = get_value_map_for_stretch (histogram, equalize_data->method);
+ break;
+ case METHOD_EQUALIZE_LINEAR:
+ case METHOD_EQUALIZE_SQUARE_ROOT:
+ equalize_data->value_map = get_value_map_for_equalize (histogram, equalize_data->method);
+ break;
+ }
- gth_cumulative_histogram_free (cumulative);
g_object_unref (histogram);
}
-static guchar
-adjust_contrast_func (AdjustContrastData *adjust_data,
- int n_channel,
- guchar value)
+static inline guchar
+adjust_contrast_func (EqualizeData *equalize_data,
+ int n_channel,
+ guchar value)
{
- if (value <= adjust_data->lowest[n_channel])
- return 0;
- else if (value >= adjust_data->highest[n_channel])
- return 255;
- else
- return (int) (adjust_data->factor[n_channel] * (value - adjust_data->lowest[n_channel]));
+ return (guchar) equalize_data->value_map[n_channel][value];
}
@@ -113,27 +221,27 @@ static gpointer
adjust_contrast_exec (GthAsyncTask *task,
gpointer user_data)
{
- AdjustContrastData *adjust_data = user_data;
- cairo_surface_t *source;
- cairo_format_t format;
- int width;
- int height;
- int source_stride;
- cairo_surface_t *destination;
- int destination_stride;
- unsigned char *p_source_line;
- unsigned char *p_destination_line;
- unsigned char *p_source;
- unsigned char *p_destination;
- gboolean cancelled;
- double progress;
- int x, y;
- unsigned char red, green, blue, alpha;
-
- /* initialize some extra data */
+ EqualizeData *equalize_data = user_data;
+ cairo_surface_t *source;
+ cairo_format_t format;
+ int width;
+ int height;
+ int source_stride;
+ cairo_surface_t *destination;
+ int destination_stride;
+ unsigned char *p_source_line;
+ unsigned char *p_destination_line;
+ unsigned char *p_source;
+ unsigned char *p_destination;
+ gboolean cancelled;
+ double progress;
+ int x, y;
+ unsigned char red, green, blue, alpha;
+
+ /* initialize the extra data */
source = gth_image_task_get_source_surface (GTH_IMAGE_TASK (task));
- adjust_contrast_setup (adjust_data, source);
+ adjust_contrast_setup (equalize_data, source);
/* convert the image */
@@ -158,9 +266,9 @@ adjust_contrast_exec (GthAsyncTask *task,
p_destination = p_destination_line;
for (x = 0; x < width; x++) {
CAIRO_GET_RGBA (p_source, red, green, blue, alpha);
- red = adjust_contrast_func (adjust_data, GTH_HISTOGRAM_CHANNEL_RED, red);
- green = adjust_contrast_func (adjust_data, GTH_HISTOGRAM_CHANNEL_GREEN, green);
- blue = adjust_contrast_func (adjust_data, GTH_HISTOGRAM_CHANNEL_BLUE, blue);
+ red = adjust_contrast_func (equalize_data, GTH_HISTOGRAM_CHANNEL_RED, red);
+ green = adjust_contrast_func (equalize_data, GTH_HISTOGRAM_CHANNEL_GREEN, green);
+ blue = adjust_contrast_func (equalize_data, GTH_HISTOGRAM_CHANNEL_BLUE, blue);
CAIRO_SET_RGBA (p_destination, red, green, blue, alpha);
p_source += 4;
@@ -181,76 +289,357 @@ adjust_contrast_exec (GthAsyncTask *task,
static void
-adjust_contrast_after (GthAsyncTask *task,
- GError *error,
- gpointer user_data)
+adjust_contrast_data_destroy (gpointer user_data)
+{
+ EqualizeData *equalize_data = user_data;
+
+ if (equalize_data->value_map != NULL)
+ value_map_free (equalize_data->value_map);
+ g_free (equalize_data);
+}
+
+
+static void apply_changes (GthFileToolAdjustContrast *self);
+
+
+static void
+image_task_completed_cb (GthTask *task,
+ GError *error,
+ gpointer user_data)
+{
+ GthFileToolAdjustContrast *self = user_data;
+ GthImage *destination_image;
+
+ self->priv->image_task = NULL;
+
+ if (self->priv->closing) {
+ g_object_unref (task);
+ gth_image_viewer_page_tool_reset_image (GTH_IMAGE_VIEWER_PAGE_TOOL (self));
+ return;
+ }
+
+ if (error != NULL) {
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ apply_changes (self);
+ g_object_unref (task);
+ return;
+ }
+
+ destination_image = gth_image_task_get_destination (GTH_IMAGE_TASK (task));
+ if (destination_image == NULL) {
+ g_object_unref (task);
+ return;
+ }
+
+ cairo_surface_destroy (self->priv->destination);
+ self->priv->destination = gth_image_get_cairo_surface (destination_image);
+ self->priv->last_applied_method = self->priv->method;
+
+ if (self->priv->apply_to_original) {
+ if (self->priv->destination != NULL) {
+ GtkWidget *window;
+ GtkWidget *viewer_page;
+
+ window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
+ viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
+ gth_image_viewer_page_set_image (GTH_IMAGE_VIEWER_PAGE (viewer_page),
self->priv->destination, TRUE);
+ }
+
+ gth_file_tool_hide_options (GTH_FILE_TOOL (self));
+ }
+ else {
+ if (! self->priv->view_original)
+ gth_preview_tool_set_image (GTH_PREVIEW_TOOL (self->priv->preview_tool),
self->priv->destination);
+ }
+
+ g_object_unref (task);
+}
+
+
+static GthTask *
+get_image_task_for_method (Method method)
+{
+ EqualizeData *equalize_data;
+
+ equalize_data = g_new (EqualizeData, 1);
+ equalize_data->method = method;
+ equalize_data->value_map = NULL;
+
+ return gth_image_task_new (_("Applying changes"),
+ NULL,
+ adjust_contrast_exec,
+ NULL,
+ equalize_data,
+ adjust_contrast_data_destroy);
+}
+
+
+static gboolean
+apply_cb (gpointer user_data)
+{
+ GthFileToolAdjustContrast *self = user_data;
+ GtkWidget *window;
+
+ if (self->priv->apply_event != 0) {
+ g_source_remove (self->priv->apply_event);
+ self->priv->apply_event = 0;
+ }
+
+ if (self->priv->image_task != NULL) {
+ gth_task_cancel (self->priv->image_task);
+ return FALSE;
+ }
+
+ window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
+
+ self->priv->image_task = get_image_task_for_method (self->priv->method);
+ if (self->priv->apply_to_original)
+ gth_image_task_set_source_surface (GTH_IMAGE_TASK (self->priv->image_task),
gth_image_viewer_page_tool_get_source (GTH_IMAGE_VIEWER_PAGE_TOOL (self)));
+ else
+ gth_image_task_set_source_surface (GTH_IMAGE_TASK (self->priv->image_task),
self->priv->preview);
+
+ g_signal_connect (self->priv->image_task,
+ "completed",
+ G_CALLBACK (image_task_completed_cb),
+ self);
+ gth_browser_exec_task (GTH_BROWSER (window), self->priv->image_task, FALSE);
+
+ return FALSE;
+}
+
+
+static void
+apply_changes (GthFileToolAdjustContrast *self)
{
- AdjustContrastData *adjust_data = user_data;
+ if (self->priv->apply_event != 0) {
+ g_source_remove (self->priv->apply_event);
+ self->priv->apply_event = 0;
+ }
+ self->priv->apply_event = g_timeout_add (APPLY_DELAY, apply_cb, self);
+}
+
+
+static void
+gth_file_tool_adjust_contrast_reset_image (GthImageViewerPageTool *base)
+{
+ GthFileToolAdjustContrast *self = GTH_FILE_TOOL_ADJUST_CONTRAST (base);
+
+ if (self->priv->image_task != NULL) {
+ self->priv->closing = TRUE;
+ return;
+ }
- g_free (adjust_data->lowest);
- adjust_data->lowest = NULL;
+ if (self->priv->apply_event != 0) {
+ g_source_remove (self->priv->apply_event);
+ self->priv->apply_event = 0;
+ }
- g_free (adjust_data->highest);
- adjust_data->highest = NULL;
+ gth_image_viewer_page_reset (GTH_IMAGE_VIEWER_PAGE (gth_image_viewer_page_tool_get_page
(GTH_IMAGE_VIEWER_PAGE_TOOL (self))));
+ gth_file_tool_hide_options (GTH_FILE_TOOL (self));
}
static void
-adjust_contrast_data_free (gpointer user_data)
+ok_button_clicked_cb (GtkButton *button,
+ gpointer user_data)
{
- AdjustContrastData *adjust_contrast_data = user_data;
+ GthFileToolAdjustContrast *self = user_data;
- g_object_unref (adjust_contrast_data->viewer_page);
- g_free (adjust_contrast_data);
+ self->priv->apply_to_original = TRUE;
+ apply_changes (self);
}
static void
-gth_file_tool_adjust_contrast_activate (GthFileTool *base)
+filter_grid_activated_cb (GthFilterGrid *filter_grid,
+ int filter_id,
+ gpointer user_data)
+{
+ GthFileToolAdjustContrast *self = user_data;
+
+ self->priv->view_original = (filter_id == GTH_FILTER_GRID_NO_ACTIVE_FILTER);
+ if (self->priv->view_original) {
+ gth_preview_tool_set_image (GTH_PREVIEW_TOOL (self->priv->preview_tool), self->priv->preview);
+ }
+ else if (filter_id == self->priv->last_applied_method) {
+ gth_preview_tool_set_image (GTH_PREVIEW_TOOL (self->priv->preview_tool),
self->priv->destination);
+ }
+ else {
+ self->priv->method = filter_id;
+ apply_changes (self);
+ }
+}
+
+
+static GtkWidget *
+gth_file_tool_adjust_contrast_get_options (GthFileTool *base)
{
- GtkWidget *window;
- GtkWidget *viewer_page;
- AdjustContrastData *adjust_contrast_data;
- GthTask *task;
+ GthFileToolAdjustContrast *self;
+ GtkWidget *window;
+ GtkWidget *viewer_page;
+ GtkWidget *viewer;
+ cairo_surface_t *source;
+ GtkWidget *options;
+ int width, height;
+ GtkAllocation allocation;
+ GtkWidget *filter_grid;
+
+ self = (GthFileToolAdjustContrast *) base;
window = gth_file_tool_get_window (base);
viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
if (! GTH_IS_IMAGE_VIEWER_PAGE (viewer_page))
- return;
+ return NULL;
- adjust_contrast_data = g_new0 (AdjustContrastData, 1);
- adjust_contrast_data->viewer_page = g_object_ref (viewer_page);
- adjust_contrast_data->lowest = NULL;
- adjust_contrast_data->highest = NULL;
- adjust_contrast_data->factor = NULL;
- task = gth_image_viewer_task_new (GTH_IMAGE_VIEWER_PAGE (viewer_page),
- _("Applying changes"),
- NULL,
- adjust_contrast_exec,
- adjust_contrast_after,
- adjust_contrast_data,
- adjust_contrast_data_free);
- g_signal_connect (task,
- "completed",
- G_CALLBACK (gth_image_viewer_task_set_destination),
- NULL);
- gth_browser_exec_task (GTH_BROWSER (window), task, FALSE);
+ _cairo_clear_surface (&self->priv->preview);
+ _cairo_clear_surface (&self->priv->destination);
+
+ viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
+ source = gth_image_viewer_page_tool_get_source (GTH_IMAGE_VIEWER_PAGE_TOOL (self));
+ if (source == NULL)
+ return NULL;
+
+ width = cairo_image_surface_get_width (source);
+ height = cairo_image_surface_get_height (source);
+ gtk_widget_get_allocation (GTK_WIDGET (viewer), &allocation);
+ if (scale_keeping_ratio (&width, &height, PREVIEW_SIZE * allocation.width, PREVIEW_SIZE *
allocation.height, FALSE))
+ self->priv->preview = _cairo_image_surface_scale_bilinear (source, width, height);
+ else
+ self->priv->preview = cairo_surface_reference (source);
+
+ self->priv->destination = cairo_surface_reference (self->priv->preview);
+ self->priv->apply_to_original = FALSE;
+ self->priv->closing = FALSE;
+
+ self->priv->builder = _gtk_builder_new_from_file ("adjust-contrast-options.ui", "file_tools");
+ options = _gtk_builder_get_widget (self->priv->builder, "options");
+ gtk_widget_show (options);
+
+ filter_grid = gth_filter_grid_new ();
+ gth_filter_grid_add_filter (GTH_FILTER_GRID (filter_grid), METHOD_STRETCH, NULL, _("Stretch (0.5%)"),
NULL);
+ gth_filter_grid_add_filter (GTH_FILTER_GRID (filter_grid), METHOD_STRETCH_MAX, NULL, _("Stretch
(1.0%)"), NULL);
+ gth_filter_grid_add_filter (GTH_FILTER_GRID (filter_grid), METHOD_EQUALIZE_SQUARE_ROOT, NULL,
_("Equalize"), NULL);
+ gth_filter_grid_add_filter (GTH_FILTER_GRID (filter_grid), METHOD_EQUALIZE_LINEAR, NULL, _("Equalize
(Linear)"), NULL);
+
+ g_signal_connect (filter_grid,
+ "activated",
+ G_CALLBACK (filter_grid_activated_cb),
+ self);
+
+ gtk_widget_show (filter_grid);
+ gtk_box_pack_start (GTK_BOX (GET_WIDGET ("filter_grid_box")), filter_grid, TRUE, FALSE, 0);
+
+ g_signal_connect (GET_WIDGET ("ok_button"),
+ "clicked",
+ G_CALLBACK (ok_button_clicked_cb),
+ self);
+ g_signal_connect_swapped (GET_WIDGET ("cancel_button"),
+ "clicked",
+ G_CALLBACK (gth_file_tool_cancel),
+ self);
+
+ self->priv->preview_tool = gth_preview_tool_new ();
+ gth_preview_tool_set_image (GTH_PREVIEW_TOOL (self->priv->preview_tool), self->priv->preview);
+ gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), self->priv->preview_tool);
+ gth_filter_grid_activate (GTH_FILTER_GRID (filter_grid), METHOD_STRETCH);
+
+ gth_filter_grid_generate_previews (GTH_FILTER_GRID (filter_grid),
+ source,
+ METHOD_EQUALIZE_SQUARE_ROOT,
+ get_image_task_for_method (METHOD_EQUALIZE_SQUARE_ROOT),
+ METHOD_STRETCH,
+ get_image_task_for_method (METHOD_STRETCH),
+ METHOD_STRETCH_MAX,
+ get_image_task_for_method (METHOD_STRETCH_MAX),
+ METHOD_EQUALIZE_LINEAR,
+ get_image_task_for_method (METHOD_EQUALIZE_LINEAR),
+ -1);
+
+ return options;
}
static void
-gth_file_tool_adjust_contrast_init (GthFileToolAdjustContrast *self)
+gth_file_tool_adjust_contrast_destroy_options (GthFileTool *base)
{
- gth_file_tool_construct (GTH_FILE_TOOL (self), "image-adjust-contrast-symbolic", _("Adjust
Contrast"), GTH_TOOLBOX_SECTION_COLORS);
- gtk_widget_set_tooltip_text (GTK_WIDGET (self), _("Automatic contrast adjustment"));
+ GthFileToolAdjustContrast *self;
+ GtkWidget *window;
+ GtkWidget *viewer_page;
+
+ self = (GthFileToolAdjustContrast *) base;
+
+ if (self->priv->apply_event != 0) {
+ g_source_remove (self->priv->apply_event);
+ self->priv->apply_event = 0;
+ }
+
+ window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
+ viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
+ gth_image_viewer_page_reset_viewer_tool (GTH_IMAGE_VIEWER_PAGE (viewer_page));
+ gth_viewer_page_update_sensitivity (GTH_VIEWER_PAGE (viewer_page));
+
+ _cairo_clear_surface (&self->priv->preview);
+ _cairo_clear_surface (&self->priv->destination);
+ _g_clear_object (&self->priv->builder);
+
+ self->priv->method = -1;
+ self->priv->last_applied_method = -1;
+}
+
+
+static void
+gth_file_tool_adjust_contrast_finalize (GObject *object)
+{
+ GthFileToolAdjustContrast *self;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GTH_IS_FILE_TOOL_ADJUST_CONTRAST (object));
+
+ self = (GthFileToolAdjustContrast *) object;
+
+ _cairo_clear_surface (&self->priv->preview);
+ _cairo_clear_surface (&self->priv->destination);
+ _g_clear_object (&self->priv->builder);
+
+ G_OBJECT_CLASS (gth_file_tool_adjust_contrast_parent_class)->finalize (object);
}
static void
gth_file_tool_adjust_contrast_class_init (GthFileToolAdjustContrastClass *klass)
{
- GthFileToolClass *file_tool_class;
+ GObjectClass *gobject_class;
+ GthFileToolClass *file_tool_class;
+ GthImageViewerPageToolClass *image_viewer_page_tool_class;
+
+ g_type_class_add_private (klass, sizeof (GthFileToolAdjustContrastPrivate));
+
+ gobject_class = (GObjectClass*) klass;
+ gobject_class->finalize = gth_file_tool_adjust_contrast_finalize;
file_tool_class = GTH_FILE_TOOL_CLASS (klass);
- file_tool_class->activate = gth_file_tool_adjust_contrast_activate;
+ file_tool_class->get_options = gth_file_tool_adjust_contrast_get_options;
+ file_tool_class->destroy_options = gth_file_tool_adjust_contrast_destroy_options;
+
+ image_viewer_page_tool_class = (GthImageViewerPageToolClass *) klass;
+ image_viewer_page_tool_class->reset_image = gth_file_tool_adjust_contrast_reset_image;
+}
+
+
+static void
+gth_file_tool_adjust_contrast_init (GthFileToolAdjustContrast *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_FILE_TOOL_ADJUST_CONTRAST,
GthFileToolAdjustContrastPrivate);
+ self->priv->preview = NULL;
+ self->priv->destination = NULL;
+ self->priv->builder = NULL;
+ self->priv->method = -1;
+ self->priv->last_applied_method = -1;
+ self->priv->view_original = FALSE;
+
+ gth_file_tool_construct (GTH_FILE_TOOL (self),
+ "image-adjust-contrast-symbolic",
+ _("Adjust Contrast"),
+ GTH_TOOLBOX_SECTION_COLORS);
+ gtk_widget_set_tooltip_text (GTK_WIDGET (self), _("Automatic contrast adjustment"));
}
diff --git a/extensions/file_tools/gth-file-tool-adjust-contrast.h
b/extensions/file_tools/gth-file-tool-adjust-contrast.h
index d878020..20b7578 100644
--- a/extensions/file_tools/gth-file-tool-adjust-contrast.h
+++ b/extensions/file_tools/gth-file-tool-adjust-contrast.h
@@ -3,7 +3,7 @@
/*
* GThumb
*
- * Copyright (C) 2012 Free Software Foundation, Inc.
+ * Copyright (C) 2014 Free Software Foundation, Inc.
*
* 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
@@ -36,9 +36,11 @@ G_BEGIN_DECLS
typedef struct _GthFileToolAdjustContrast GthFileToolAdjustContrast;
typedef struct _GthFileToolAdjustContrastClass GthFileToolAdjustContrastClass;
+typedef struct _GthFileToolAdjustContrastPrivate GthFileToolAdjustContrastPrivate;
struct _GthFileToolAdjustContrast {
GthImageViewerPageTool parent_instance;
+ GthFileToolAdjustContrastPrivate *priv;
};
struct _GthFileToolAdjustContrastClass {
diff --git a/extensions/file_tools/main.c b/extensions/file_tools/main.c
index b8d2a29..2a9c4bb 100644
--- a/extensions/file_tools/main.c
+++ b/extensions/file_tools/main.c
@@ -27,7 +27,6 @@
#include "gth-file-tool-adjust-colors.h"
#include "gth-file-tool-adjust-contrast.h"
#include "gth-file-tool-crop.h"
-#include "gth-file-tool-equalize.h"
#include "gth-file-tool-flip.h"
#include "gth-file-tool-grayscale.h"
#include "gth-file-tool-mirror.h"
@@ -54,7 +53,6 @@ gthumb_extension_activate (void)
gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_ADJUST_CONTRAST);
gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_ADJUST_COLORS);
gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_SHARPEN);
- gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_EQUALIZE);
gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_GRAYSCALE);
gth_main_register_type ("file-tools", GTH_TYPE_FILE_TOOL_NEGATIVE);
diff --git a/gthumb/gth-histogram.c b/gthumb/gth-histogram.c
index 727f387..ae4da47 100644
--- a/gthumb/gth-histogram.c
+++ b/gthumb/gth-histogram.c
@@ -20,6 +20,7 @@
*/
+#include <math.h>
#include <string.h>
#include "cairo-utils.h"
#include "gth-histogram.h"
@@ -33,9 +34,12 @@ enum {
struct _GthHistogramPrivate {
- int **values;
- int *values_max;
- int n_channels;
+ int **values;
+ int *values_max;
+ int n_pixels;
+ int n_channels;
+ guchar *min_value;
+ guchar *max_value;
};
@@ -57,6 +61,8 @@ gth_histogram_finalize (GObject *object)
g_free (self->priv->values[i]);
g_free (self->priv->values);
g_free (self->priv->values_max);
+ g_free (self->priv->min_value);
+ g_free (self->priv->max_value);
G_OBJECT_CLASS (gth_histogram_parent_class)->finalize (object);
}
@@ -96,6 +102,8 @@ gth_histogram_init (GthHistogram *self)
for (i = 0; i < GTH_HISTOGRAM_N_CHANNELS + 1; i++)
self->priv->values[i] = g_new0 (int, 256);
self->priv->values_max = g_new0 (int, GTH_HISTOGRAM_N_CHANNELS + 1);
+ self->priv->min_value = g_new0 (guchar, GTH_HISTOGRAM_N_CHANNELS + 1);
+ self->priv->max_value = g_new0 (guchar, GTH_HISTOGRAM_N_CHANNELS + 1);
}
@@ -114,6 +122,8 @@ histogram_reset_values (GthHistogram *self)
for (i = 0; i < GTH_HISTOGRAM_N_CHANNELS + 1; i++) {
memset (self->priv->values[i], 0, sizeof (int) * 256);
self->priv->values_max[i] = 0;
+ self->priv->min_value[i] = 0;
+ self->priv->max_value[i] = 0;
}
}
@@ -134,7 +144,7 @@ gth_histogram_calculate_for_image (GthHistogram *self,
int width, height, has_alpha;
int rowstride;
guchar *line, *pixel;
- int i, j, max;
+ int i, j, value;
guchar red, green, blue, alpha;
g_return_if_fail (GTH_IS_HISTOGRAM (self));
@@ -155,6 +165,7 @@ gth_histogram_calculate_for_image (GthHistogram *self,
width = cairo_image_surface_get_width (image);
height = cairo_image_surface_get_height (image);
+ self->priv->n_pixels = width * height;
self->priv->n_channels = (has_alpha ? 4 : 3) + 1;
histogram_reset_values (self);
@@ -174,12 +185,28 @@ gth_histogram_calculate_for_image (GthHistogram *self,
/* count value for Value channel */
- max = MAX (MAX (red, green), blue);
- values[GTH_HISTOGRAM_CHANNEL_VALUE][max] += 1;
+ value = MAX (MAX (red, green), blue);
+ values[GTH_HISTOGRAM_CHANNEL_VALUE][value] += 1;
+
+ /* min and max pixel values */
+
+ self->priv->min_value[GTH_HISTOGRAM_CHANNEL_VALUE] = MIN
(self->priv->min_value[GTH_HISTOGRAM_CHANNEL_VALUE], value);
+ self->priv->min_value[GTH_HISTOGRAM_CHANNEL_RED] = MIN
(self->priv->min_value[GTH_HISTOGRAM_CHANNEL_RED], red);
+ self->priv->min_value[GTH_HISTOGRAM_CHANNEL_GREEN] = MIN
(self->priv->min_value[GTH_HISTOGRAM_CHANNEL_GREEN], green);
+ self->priv->min_value[GTH_HISTOGRAM_CHANNEL_BLUE] = MIN
(self->priv->min_value[GTH_HISTOGRAM_CHANNEL_BLUE], blue);
+ if (has_alpha)
+ self->priv->min_value[GTH_HISTOGRAM_CHANNEL_ALPHA] = MIN
(self->priv->min_value[GTH_HISTOGRAM_CHANNEL_ALPHA], alpha);
+
+ self->priv->max_value[GTH_HISTOGRAM_CHANNEL_VALUE] = MAX
(self->priv->max_value[GTH_HISTOGRAM_CHANNEL_VALUE], value);
+ self->priv->max_value[GTH_HISTOGRAM_CHANNEL_RED] = MAX
(self->priv->max_value[GTH_HISTOGRAM_CHANNEL_RED], red);
+ self->priv->max_value[GTH_HISTOGRAM_CHANNEL_GREEN] = MAX
(self->priv->max_value[GTH_HISTOGRAM_CHANNEL_GREEN], green);
+ self->priv->max_value[GTH_HISTOGRAM_CHANNEL_BLUE] = MAX
(self->priv->max_value[GTH_HISTOGRAM_CHANNEL_BLUE], blue);
+ if (has_alpha)
+ self->priv->max_value[GTH_HISTOGRAM_CHANNEL_ALPHA] = MAX
(self->priv->max_value[GTH_HISTOGRAM_CHANNEL_ALPHA], alpha);
- /* track max value for each channel */
+ /* track min and max value for each channel */
- values_max[GTH_HISTOGRAM_CHANNEL_VALUE] = MAX
(values_max[GTH_HISTOGRAM_CHANNEL_VALUE], values[GTH_HISTOGRAM_CHANNEL_VALUE][max]);
+ values_max[GTH_HISTOGRAM_CHANNEL_VALUE] = MAX
(values_max[GTH_HISTOGRAM_CHANNEL_VALUE], values[GTH_HISTOGRAM_CHANNEL_VALUE][value]);
values_max[GTH_HISTOGRAM_CHANNEL_RED] = MAX (values_max[GTH_HISTOGRAM_CHANNEL_RED],
values[GTH_HISTOGRAM_CHANNEL_RED][red]);
values_max[GTH_HISTOGRAM_CHANNEL_GREEN] = MAX
(values_max[GTH_HISTOGRAM_CHANNEL_GREEN], values[GTH_HISTOGRAM_CHANNEL_GREEN][green]);
values_max[GTH_HISTOGRAM_CHANNEL_BLUE] = MAX (values_max[GTH_HISTOGRAM_CHANNEL_BLUE],
values[GTH_HISTOGRAM_CHANNEL_BLUE][blue]);
@@ -269,6 +296,40 @@ gth_histogram_get_max (GthHistogram *self)
}
+guchar
+gth_histogram_get_min_value (GthHistogram *self,
+ GthHistogramChannel channel)
+{
+ g_return_val_if_fail (self != NULL, 0.0);
+
+ if (channel < self->priv->n_channels)
+ return self->priv->min_value[channel];
+
+ return 0;
+}
+
+
+guchar
+gth_histogram_get_max_value (GthHistogram *self,
+ GthHistogramChannel channel)
+{
+ g_return_val_if_fail (self != NULL, 0.0);
+
+ if (channel < self->priv->n_channels)
+ return self->priv->max_value[channel];
+
+ return 0;
+}
+
+
+int
+gth_histogram_get_n_pixels (GthHistogram *self)
+{
+ g_return_val_if_fail (self != NULL, 0.0);
+ return self->priv->n_pixels;
+}
+
+
int
gth_histogram_get_nchannels (GthHistogram *self)
{
diff --git a/gthumb/gth-histogram.h b/gthumb/gth-histogram.h
index 63c191f..f776103 100644
--- a/gthumb/gth-histogram.h
+++ b/gthumb/gth-histogram.h
@@ -78,6 +78,11 @@ double gth_histogram_get_channel (GthHistogram *self,
double gth_histogram_get_channel_max (GthHistogram *self,
GthHistogramChannel channel);
double gth_histogram_get_max (GthHistogram *self);
+guchar gth_histogram_get_min_value (GthHistogram *self,
+ GthHistogramChannel channel);
+guchar gth_histogram_get_max_value (GthHistogram *self,
+ GthHistogramChannel channel);
+int gth_histogram_get_n_pixels (GthHistogram *self);
int gth_histogram_get_nchannels (GthHistogram *self);
long ** gth_histogram_get_cumulative (GthHistogram *self);
void gth_cumulative_histogram_free (long **cumulative);
diff --git a/po/POTFILES.in b/po/POTFILES.in
index ca4646b..7bef56c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -269,6 +269,7 @@ extensions/file_tools/cairo-rotate.h
extensions/file_tools/callbacks.c
extensions/file_tools/callbacks.h
[type: gettext/glade]extensions/file_tools/data/ui/adjust-colors-options.ui
+[type: gettext/glade]extensions/file_tools/data/ui/adjust-contrast-options.ui
[type: gettext/glade]extensions/file_tools/data/ui/crop-options.ui
[type: gettext/glade]extensions/file_tools/data/ui/grayscale-options.ui
[type: gettext/glade]extensions/file_tools/data/ui/resize-options.ui
@@ -281,8 +282,6 @@ extensions/file_tools/gth-file-tool-adjust-contrast.c
extensions/file_tools/gth-file-tool-adjust-contrast.h
extensions/file_tools/gth-file-tool-crop.c
extensions/file_tools/gth-file-tool-crop.h
-extensions/file_tools/gth-file-tool-equalize.c
-extensions/file_tools/gth-file-tool-equalize.h
extensions/file_tools/gth-file-tool-flip.c
extensions/file_tools/gth-file-tool-flip.h
extensions/file_tools/gth-file-tool-grayscale.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]