[gthumb] unify equalize histogram and adjust contrast



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]