reworked the histogram patch by Uwe Ohse, most of the code is in
authorVladimir Nadvornik <nadvornik@suse.cz>
Tue, 8 Apr 2008 20:56:50 +0000 (20:56 +0000)
committerVladimir Nadvornik <nadvornik@suse.cz>
Tue, 8 Apr 2008 20:56:50 +0000 (20:56 +0000)
separate files

doc/8_2_fullscreen.html
src/Makefile.am
src/histogram.c [new file with mode: 0644]
src/histogram.h [new file with mode: 0644]
src/image-overlay.c
src/image-overlay.h
src/image.c
src/layout.c
src/layout_util.c
src/typedefs.h

index f9243a3..1e1e31c 100644 (file)
@@ -80,9 +80,11 @@ activating.</P>
 are available when in full screen, these are the commands available:</P>
 <CENTER>
        <TABLE WIDTH=80% BORDER=1 BORDERCOLOR="#cccccc" CELLPADDING=4 CELLSPACING=0 RULES=ROWS>
+               <COLGROUP>
                <COL WIDTH=85*>
                <COL WIDTH=85*>
                <COL WIDTH=85*>
+               </COLGROUP>
                <TR VALIGN=TOP>
                        <TD WIDTH=33%>
                                <P ALIGN=CENTER><B>Keyboard</B></P>
@@ -319,7 +321,23 @@ also available through the keyboard and context menu:</P>
                                <P>I</P>
                        </TD>
                        <TD WIDTH=50%>
-                               <P>Toggle information overlay for full screen.</P>
+                               <P>Toggle information overlay for full screen: on with histogramm, on without histogramm, off.</P>
+                       </TD>
+               </TR>
+               <TR VALIGN=TOP>
+                       <TD WIDTH=50%>
+                               <P>K</P>
+                       </TD>
+                       <TD WIDTH=50%>
+                               <P>Switch between the different histogramm modes: RGB, value, maximum value, red channel, green channel, blue channel.</P>
+                       </TD>
+               </TR>
+               <TR VALIGN=TOP>
+                       <TD WIDTH=50%>
+                               <P>J</P>
+                       </TD>
+                       <TD WIDTH=50%>
+                               <P>Toogle between linear and logarithmical histogramm.</P>
                        </TD>
                </TR>
                <TR VALIGN=TOP>
index 4002634..90ef58d 100644 (file)
@@ -103,6 +103,8 @@ geeqie_SOURCES = \
        fullscreen.h    \
        globals.c       \
        gqview.h        \
+       histogram.c     \
+       histogram.h     \
        image.c         \
        image.h         \
        image-load.c    \
diff --git a/src/histogram.c b/src/histogram.c
new file mode 100644 (file)
index 0000000..38c4876
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Geeqie
+ *
+ * Author: Vladimir Nadvornik
+ * based on a patch by Uwe Ohse
+ *
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
+ */
+
+#include "gqview.h"
+#include "histogram.h"
+#include <math.h>
+
+/*
+ *----------------------------------------------------------------------------
+ * image histogram
+ *----------------------------------------------------------------------------
+ */
+
+
+Histogram *histogram_new()
+{
+       Histogram *histogram;
+
+        histogram = g_new0(Histogram, 1);
+       histogram->histogram_chan = HCHAN_RGB;
+       histogram->histogram_logmode = 1;
+
+       return histogram;
+}
+
+void histogram_free(Histogram *histogram)
+{
+       g_free(histogram);
+}
+
+
+gint histogram_set_channel(Histogram *histogram, gint chan)
+{
+       if (!histogram) return 0;
+       histogram->histogram_chan = chan;
+       return chan;
+}
+
+gint histogram_get_channel(Histogram *histogram)
+{
+       if (!histogram) return 0;
+       return histogram->histogram_chan;
+}
+
+gint histogram_set_mode(Histogram *histogram, gint mode)
+{
+       if (!histogram) return 0;
+       histogram->histogram_logmode = mode;
+       return mode;
+}
+
+gint histogram_get_mode(Histogram *histogram)
+{
+       if (!histogram) return 0;
+       return histogram->histogram_logmode;
+}
+
+const gchar *histogram_label(Histogram *histogram)
+{
+       const gchar *t1 = "";
+       if (!histogram) return NULL;
+
+       if (histogram->histogram_logmode)
+                       switch (histogram->histogram_chan) {
+                       case HCHAN_R:   t1 = _("logarithmical histogram on red"); break;
+                        case HCHAN_G:   t1 = _("logarithmical histogram on green"); break;
+                        case HCHAN_B:   t1 = _("logarithmical histogram on blue"); break;
+                        case HCHAN_VAL: t1 = _("logarithmical histogram on value"); break;
+                        case HCHAN_RGB: t1 = _("logarithmical histogram on RGB"); break;
+                        case HCHAN_MAX: t1 = _("logarithmical histogram on max value"); break;
+                        }
+                else
+                        switch (histogram->histogram_chan) {
+                        case HCHAN_R:   t1 = _("linear histogram on red"); break;
+                        case HCHAN_G:   t1 = _("linear histogram on green"); break;
+                        case HCHAN_B:   t1 = _("linear histogram on blue"); break;
+                        case HCHAN_VAL: t1 = _("linear histogram on value"); break;
+                        case HCHAN_RGB: t1 = _("linear histogram on RGB"); break;
+                        case HCHAN_MAX: t1 = _("linear histogram on max value"); break;
+                        }
+       return t1;
+}
+
+gulong histogram_read(Histogram *histogram, GdkPixbuf *imgpixbuf)
+{
+       gint w, h, i, j, srs, has_alpha;
+       guchar *s_pix;
+
+       if (!histogram) return 0;
+
+       w = gdk_pixbuf_get_width(imgpixbuf);
+       h = gdk_pixbuf_get_height(imgpixbuf);
+       srs = gdk_pixbuf_get_rowstride(imgpixbuf);
+       s_pix = gdk_pixbuf_get_pixels(imgpixbuf);
+       has_alpha = gdk_pixbuf_get_has_alpha(imgpixbuf);
+
+       for (i = 0; i < 256*4; i++) histogram->histmap[i] = 0;
+
+       for (i = 0; i < h; i++)
+               {
+               guchar *sp = s_pix + (i * srs); /* 8bit */
+               for (j = 0; j < w; j++)
+                       {
+                       histogram->histmap[sp[0]+0]++;
+                       histogram->histmap[sp[1]+256]++;
+                       histogram->histmap[sp[2]+512]++;
+                       if (histogram->histogram_chan == HCHAN_MAX)
+                               {
+                               guchar t = sp[0];
+                               if (sp[1]>t) t = sp[1];
+                               if (sp[2]>t) t = sp[2];
+                               histogram->histmap[t+768]++;
+                               }
+                       else
+                               histogram->histmap[768+(sp[0]+sp[1]+sp[2])/3]++;
+                       sp += 3;
+                       if (has_alpha) sp++;
+                       }
+               }
+
+       return w*h;
+}
+
+
+int histogram_draw(Histogram *histogram, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height)
+{
+       /* FIXME: use the coordinates correctly */
+       gint i;
+       gulong max = 0;
+       double logmax;
+
+       if (!histogram) return 0;
+
+       for (i=0; i<1024; i++) {
+               int flag = 0;
+
+               switch (histogram->histogram_chan)
+               {
+               case HCHAN_RGB: if ((i%4) != 3 ) flag = 1; break;
+               case HCHAN_R: if ((i%4) == 0) flag = 1; break;
+               case HCHAN_G: if ((i%4) == 1) flag = 1; break;
+               case HCHAN_B: if ((i%4) == 2) flag = 1; break;
+               case HCHAN_VAL: if ((i%4) == 3) flag = 1; break;
+               case HCHAN_MAX: if ((i%4) == 3) flag = 1; break;
+               }
+               if (flag && histogram->histmap[i] > max) max = histogram->histmap[i];
+       }
+
+       logmax = log(max);
+       for (i=0; i<256; i++)
+               {
+               gint j;
+               glong v[4];
+               gint rplus = 0;
+               gint gplus = 0;
+               gint bplus = 0;
+
+               v[0] = histogram->histmap[i+0*256]; // r
+               v[1] = histogram->histmap[i+1*256]; // g
+               v[2] = histogram->histmap[i+2*256]; // b
+               v[3] = histogram->histmap[i+3*256]; // value, max
+               
+               for (j=0; j<4; j++)
+                       {
+                       gint r = rplus;
+                       gint g = gplus;
+                       gint b = bplus;
+                       gint max2 = 0;
+                       gint k;
+                       gulong pt;
+
+                       for (k=1; k<4; k++)
+                               if (v[k] > v[max2]) max2 = k;
+       
+                       switch (max2)
+                       {
+                       case HCHAN_R: rplus = r = 255; break;
+                       case HCHAN_G: gplus = g = 255; break;
+                       case HCHAN_B: bplus = b = 255; break;
+                       }
+
+                       switch(histogram->histogram_chan)
+                       {
+                       case HCHAN_MAX: r = 0; b = 0; g = 0; break;
+                       case HCHAN_VAL: r = 0; b = 0; g = 0; break;
+                       case HCHAN_R: g = 0; b = 0; break;
+                       case HCHAN_G: r = 0; b = 0; break;
+                       case HCHAN_B: r = 0; g = 0; break;
+                       case HCHAN_RGB: 
+                               if (r == 255 && g == 255 && b == 255) {
+                                       r = 0; 
+                                       g = 0; 
+                                       b = 0; 
+                               }
+                               break;
+                       }
+
+                       if (v[max2] == 0)
+                               pt = 0;
+                       else if (histogram->histogram_logmode)
+                               pt = ((float)log(v[max2]))/logmax*255;
+                       else
+                               pt = ((float)v[max2])/max*255;
+                       if (histogram->histogram_chan >= HCHAN_RGB 
+                           || max2 == histogram->histogram_chan)
+                               pixbuf_draw_line(pixbuf, 
+                                       0+5, height-255, 256, 256,
+                                       i+5, height, i+5, height-pt, 
+                                       r, g, b, 255);
+                       v[max2] = -1;
+                       }
+               }
+       return TRUE;
+}
diff --git a/src/histogram.h b/src/histogram.h
new file mode 100644 (file)
index 0000000..ae8de07
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Geeqie
+ *
+ * Author: Vladimir Nadvornik
+ * based on a patch by Uwe Ohse
+ *
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
+ */
+
+
+/* Note: The order is important */
+#define HCHAN_R 0
+#define HCHAN_G 1
+#define HCHAN_B 2
+#define HCHAN_RGB 3
+#define HCHAN_VAL 4
+#define HCHAN_MAX 5
+#define HCHAN_COUNT (HCHAN_MAX+1)
+
+
+Histogram *histogram_new();
+void histogram_free(Histogram *histogram);
+gint histogram_set_channel(Histogram *histogram, gint chan);
+gint histogram_get_channel(Histogram *histogram);
+gint histogram_set_mode(Histogram *histogram, gint mode);
+gint histogram_get_mode(Histogram *histogram);
+const gchar *histogram_label(Histogram *histogram);
+gulong histogram_read(Histogram *histogram, GdkPixbuf *imgpixbuf);
+int histogram_draw(Histogram *histogram, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height);
index c619150..b5a301c 100644 (file)
@@ -20,6 +20,7 @@
 #include "layout.h"
 #include "pixbuf-renderer.h"
 #include "pixbuf_util.h"
+#include "histogram.h"
 
 
 /*
@@ -73,6 +74,50 @@ static OSDIcon osd_icons[] = {
 
 #define IMAGE_OSD_DEFAULT_DURATION 30
 
+/*
+ *----------------------------------------------------------------------------
+ * image histogram
+ *----------------------------------------------------------------------------
+ */
+
+
+#define HIST_PREPARE(imd, lw)                          \
+       LayoutWindow *lw = NULL;                        \
+       if (imd)                                        \
+               lw = layout_find_by_image(imd);
+
+void image_osd_histogram_onoff_toggle(ImageWindow *imd, gint x)
+{
+       HIST_PREPARE(imd, lw)
+       if (lw) 
+               {
+               lw->histogram_enabled = !!(x);
+               if (lw->histogram_enabled && !lw->histogram)
+                       lw->histogram = histogram_new();
+               }
+}
+
+gint image_osd_histogram_onoff_status(ImageWindow *imd)
+{
+       HIST_PREPARE(imd, lw)
+       return lw ?  lw->histogram_enabled : FALSE;
+}
+
+void image_osd_histogram_chan_toggle(ImageWindow *imd)
+{
+       HIST_PREPARE(imd, lw)
+       if (lw && lw->histogram) 
+               histogram_set_channel(lw->histogram, (histogram_get_channel(lw->histogram) +1)%HCHAN_COUNT);
+}
+
+void image_osd_histogram_log_toggle(ImageWindow *imd)
+{
+       HIST_PREPARE(imd,lw)
+       if (lw && lw->histogram) 
+               histogram_set_mode(lw->histogram, !histogram_get_mode(lw->histogram));
+}
+
+
 
 static void image_osd_timer_schedule(OverlayStateData *osd);
 
@@ -155,6 +200,9 @@ static GdkPixbuf *image_osd_info_render(ImageWindow *imd)
        gint n, t;
        CollectionData *cd;
        CollectInfo *info;
+       GdkPixbuf *imgpixbuf = NULL;
+       LayoutWindow *lw = NULL;
+       gint with_hist = 0;
        gchar *ct;
        gint w, h;
        GHashTable *vars;
@@ -184,8 +232,6 @@ static GdkPixbuf *image_osd_info_render(ImageWindow *imd)
                }
        else
                {
-               LayoutWindow *lw;
-
                lw = layout_find_by_image(imd);
                if (lw)
                        {
@@ -226,11 +272,19 @@ static GdkPixbuf *image_osd_info_render(ImageWindow *imd)
                        {
                        w = gdk_pixbuf_get_width(imd->il->pixbuf);
                        h = gdk_pixbuf_get_height(imd->il->pixbuf);
+                       imgpixbuf = imd->il->pixbuf;
                        }
                else
                        {
                        pixbuf_renderer_get_image_size(PIXBUF_RENDERER(imd->pr), &w, &h);
+                       imgpixbuf = (PIXBUF_RENDERER(imd->pr))->pixbuf;
                        }
+               if (!lw)
+                       lw = layout_find_by_image(imd);
+
+               if (imgpixbuf && lw->histogram && lw->histogram_enabled 
+                             && (!imd->il || imd->il->done)) 
+                       with_hist=1;
 
                g_hash_table_insert(vars, "width", g_strdup_printf("%d", w));
                g_hash_table_insert(vars, "height", g_strdup_printf("%d", h));
@@ -281,7 +335,10 @@ static GdkPixbuf *image_osd_info_render(ImageWindow *imd)
                                g_string_append_printf(buf, fd->marks[mark] ? " <span background='#FF00FF'>%c</span>" : " %c", '1' + mark);
                                }
 
-                       text2 = g_strdup_printf("%s\n%s", text, buf->str);
+                       if (with_hist)
+                               text2 = g_strdup_printf("%s\n%s\n%s", text, buf->str, histogram_label(lw->histogram));
+                       else
+                               text2 = g_strdup_printf("%s\n%s", text, buf->str);
                        g_string_free(buf, TRUE);
                        g_free(text);
                        }
@@ -297,6 +354,14 @@ static GdkPixbuf *image_osd_info_render(ImageWindow *imd)
        width += 10;
        height += 10;
 
+       if (with_hist)
+               {
+               histogram_read(lw->histogram, imgpixbuf);
+               if (width < 266) width = 266;
+               height += 256;
+               }
+
+
        /* TODO: make osd color configurable --Zas */
        pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
        pixbuf_set_rect_fill(pixbuf, 3, 3, width-6, height-6, 240, 240, 240, 210);
@@ -308,6 +373,9 @@ static GdkPixbuf *image_osd_info_render(ImageWindow *imd)
        pixbuf_pixel_set(pixbuf, 0, height - 1, 0, 0, 0, 0);
        pixbuf_pixel_set(pixbuf, width - 1, height - 1, 0, 0, 0, 0);
 
+       if (with_hist)
+               histogram_draw(lw->histogram, pixbuf, 0, 0, width, height);
+               
        pixbuf_draw_layout(pixbuf, layout, imd->pr, 5, 5, 0, 0, 0, 255);
 
        g_object_unref(G_OBJECT(layout));
@@ -485,7 +553,8 @@ static gint image_osd_update_cb(gpointer data)
                        }
                }
 
-       osd->changed_states = IMAGE_STATE_NONE;
+       if (osd->imd->il && osd->imd->il->done)
+               osd->changed_states = IMAGE_STATE_NONE;
        osd->idle_id = -1;
        return FALSE;
 }
index 9bb34a5..415e751 100644 (file)
@@ -31,6 +31,10 @@ void image_osd_update(ImageWindow *imd);
 
 void image_osd_icon(ImageWindow *imd, ImageOSDFlag flag, gint duration);
 
+void image_osd_histogram_onoff_toggle(ImageWindow *, gint);
+gint image_osd_histogram_onoff_status(ImageWindow *);
+void image_osd_histogram_chan_toggle(ImageWindow *);
+void image_osd_histogram_log_toggle(ImageWindow *);
 
 #endif
 
index dde6016..9e46f6e 100644 (file)
@@ -248,6 +248,7 @@ static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
                        pixbuf_desaturate_rect(pr->pixbuf,
                                               0, 0,  pr->image_width, pr->image_height);
                        image_area_changed(imd, 0, 0, pr->image_width, pr->image_height);
+                       layout_image_overlay_update(layout_find_by_image(imd));
                        break;
                case ALTER_NONE:
                default:
@@ -285,6 +286,7 @@ static void image_alter_real(ImageWindow *imd, AlterType type, gint clamp)
                }
 
        if (exif_rotate) image_state_set(imd, IMAGE_STATE_ROTATE_AUTO);
+       layout_image_overlay_update(layout_find_by_image(imd));
 }
 
 static void image_post_process_alter(ImageWindow *imd, gint clamp)
index 38c51d0..c050c96 100644 (file)
@@ -29,6 +29,7 @@
 #include "ui_menu.h"
 #include "ui_misc.h"
 #include "ui_tabcomp.h"
+#include "histogram.h"
 
 
 #define MAINWINDOW_DEF_WIDTH 700
@@ -1850,6 +1851,8 @@ void layout_free(LayoutWindow *lw)
        layout_bars_close(lw);
 
        gtk_widget_destroy(lw->window);
+       
+       histogram_free(lw->histogram);
 
        g_free(lw->path);
 
@@ -1895,6 +1898,8 @@ LayoutWindow *layout_new_with_geometry(const gchar *path, gint popped, gint hidd
        lw->bar_exif_size = -1;
        lw->bar_exif_advanced = FALSE;
 
+       lw->histogram_enabled = FALSE;
+
        /* default layout */
 
        layout_config_parse(layout_style, layout_order,
index 8bca52c..7c285de 100644 (file)
@@ -593,7 +593,38 @@ static void layout_menu_overlay_cb(GtkAction *action, gpointer data)
 {
        LayoutWindow *lw = data;
 
-       layout_image_overlay_toggle(lw);
+       if (image_osd_get(lw->image, NULL, NULL))
+               {
+               if (image_osd_histogram_onoff_status(lw->image))
+                       {
+                       image_osd_histogram_onoff_toggle(lw->image, 0);
+                       layout_image_overlay_update(lw);
+                       }
+               else
+                       layout_image_overlay_toggle(lw);
+               }
+       else
+               {
+               layout_image_overlay_toggle(lw);
+               image_osd_histogram_onoff_toggle(lw->image, 1);
+               layout_image_overlay_update(lw);
+               }
+}
+
+static void layout_menu_histogram_chan_cb(GtkAction *action, gpointer data)
+{
+       LayoutWindow *lw = data;
+
+       image_osd_histogram_chan_toggle(lw->image);
+       layout_image_overlay_update(lw);
+}
+
+static void layout_menu_histogram_log_cb(GtkAction *action, gpointer data)
+{
+       LayoutWindow *lw = data;
+
+       image_osd_histogram_log_toggle(lw->image);
+       layout_image_overlay_update(lw);
 }
 
 static void layout_menu_refresh_cb(GtkAction *action, gpointer data)
@@ -1086,6 +1117,8 @@ static GtkActionEntry menu_entries[] = {
 
   { "FullScreen",      NULL,           N_("F_ull screen"),     "F",            NULL,   CB(layout_menu_fullscreen_cb) },
   { "ImageOverlay",    NULL,           N_("_Image Overlay"),   "I",            NULL,   CB(layout_menu_overlay_cb) },
+  { "HistogramChan",   NULL,   N_("Histogram _channels"),      "K",            NULL,   CB(layout_menu_histogram_chan_cb) },
+  { "HistogramLog",    NULL,   N_("Histogram _log mode"),      "J",            NULL,   CB(layout_menu_histogram_log_cb) },
   { "HideTools",       NULL,           N_("_Hide file list"),  "<control>H",   NULL,   CB(layout_menu_hide_cb) },
   { "SlideShow",       NULL,           N_("Toggle _slideshow"),"S",            NULL,   CB(layout_menu_slideshow_cb) },
   { "Refresh", GTK_STOCK_REFRESH,      N_("_Refresh"),         "R",            NULL,   CB(layout_menu_refresh_cb) },
@@ -1220,6 +1253,8 @@ static const char *menu_ui_description =
 "      <separator/>"
 "      <menuitem action='FolderTree'/>"
 "      <menuitem action='ImageOverlay'/>"
+"      <menuitem action='HistogramChan'/>"
+"      <menuitem action='HistogramLog'/>"
 "      <menuitem action='FullScreen'/>"
 "      <separator/>"
 "      <menuitem action='FloatTools'/>"
index 891ce2c..a7f3151 100644 (file)
@@ -122,6 +122,8 @@ typedef struct _SlideShowData SlideShowData;
 typedef struct _FullScreenData FullScreenData;
 
 typedef struct _PixmapFolders PixmapFolders;
+typedef struct _Histogram Histogram;
+
 
 
 struct _ImageLoader
@@ -379,6 +381,13 @@ struct _FileData {
        gint ref;
 };
 
+struct _Histogram {
+       gulong histmap[256*4];
+       gint histogram_chan;
+       gint histogram_logmode;
+};
+
+
 struct _LayoutWindow
 {
        gchar *path;
@@ -489,6 +498,9 @@ struct _LayoutWindow
        GtkWidget *bar_exif;
        GtkWidget *bar_info;
 
+       gint histogram_enabled;
+       Histogram *histogram;
+
        gint bar_sort_enabled;
        gint bar_exif_enabled;
        gint bar_info_enabled;