# HG changeset patch
# User nadvornik
# Date 1207688210 0
# Node ID e0e2c2b72c5a671197d3d2426d94794a41d5710f
# Parent fbbb960a3857fd190e974ba2e48aff8bcb3228f2
reworked the histogram patch by Uwe Ohse, most of the code is in
separate files
diff -r fbbb960a3857 -r e0e2c2b72c5a doc/8_2_fullscreen.html
--- a/doc/8_2_fullscreen.html Tue Apr 08 17:26:13 2008 +0000
+++ b/doc/8_2_fullscreen.html Tue Apr 08 20:56:50 2008 +0000
@@ -80,9 +80,11 @@
are available when in full screen, these are the commands available:
+
+
Keyboard
@@ -319,7 +321,23 @@
I
|
- Toggle information overlay for full screen.
+ Toggle information overlay for full screen: on with histogramm, on without histogramm, off.
+ |
+
+
+
+ K
+ |
+
+ Switch between the different histogramm modes: RGB, value, maximum value, red channel, green channel, blue channel.
+ |
+
+
+
+ J
+ |
+
+ Toogle between linear and logarithmical histogramm.
|
diff -r fbbb960a3857 -r e0e2c2b72c5a src/Makefile.am
--- a/src/Makefile.am Tue Apr 08 17:26:13 2008 +0000
+++ b/src/Makefile.am Tue Apr 08 20:56:50 2008 +0000
@@ -103,6 +103,8 @@
fullscreen.h \
globals.c \
gqview.h \
+ histogram.c \
+ histogram.h \
image.c \
image.h \
image-load.c \
diff -r fbbb960a3857 -r e0e2c2b72c5a src/histogram.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/histogram.c Tue Apr 08 20:56:50 2008 +0000
@@ -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
+
+/*
+ *----------------------------------------------------------------------------
+ * 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 -r fbbb960a3857 -r e0e2c2b72c5a src/histogram.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/histogram.h Tue Apr 08 20:56:50 2008 +0000
@@ -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);
diff -r fbbb960a3857 -r e0e2c2b72c5a src/image-overlay.c
--- a/src/image-overlay.c Tue Apr 08 17:26:13 2008 +0000
+++ b/src/image-overlay.c Tue Apr 08 20:56:50 2008 +0000
@@ -20,6 +20,7 @@
#include "layout.h"
#include "pixbuf-renderer.h"
#include "pixbuf_util.h"
+#include "histogram.h"
/*
@@ -73,6 +74,50 @@
#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 @@
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 @@
}
else
{
- LayoutWindow *lw;
-
lw = layout_find_by_image(imd);
if (lw)
{
@@ -226,11 +272,19 @@
{
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 @@
g_string_append_printf(buf, fd->marks[mark] ? " %c" : " %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 @@
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 @@
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 @@
}
}
- 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;
}
diff -r fbbb960a3857 -r e0e2c2b72c5a src/image-overlay.h
--- a/src/image-overlay.h Tue Apr 08 17:26:13 2008 +0000
+++ b/src/image-overlay.h Tue Apr 08 20:56:50 2008 +0000
@@ -31,6 +31,10 @@
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
diff -r fbbb960a3857 -r e0e2c2b72c5a src/image.c
--- a/src/image.c Tue Apr 08 17:26:13 2008 +0000
+++ b/src/image.c Tue Apr 08 20:56:50 2008 +0000
@@ -248,6 +248,7 @@
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 @@
}
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)
diff -r fbbb960a3857 -r e0e2c2b72c5a src/layout.c
--- a/src/layout.c Tue Apr 08 17:26:13 2008 +0000
+++ b/src/layout.c Tue Apr 08 20:56:50 2008 +0000
@@ -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 @@
layout_bars_close(lw);
gtk_widget_destroy(lw->window);
+
+ histogram_free(lw->histogram);
g_free(lw->path);
@@ -1895,6 +1898,8 @@
lw->bar_exif_size = -1;
lw->bar_exif_advanced = FALSE;
+ lw->histogram_enabled = FALSE;
+
/* default layout */
layout_config_parse(layout_style, layout_order,
diff -r fbbb960a3857 -r e0e2c2b72c5a src/layout_util.c
--- a/src/layout_util.c Tue Apr 08 17:26:13 2008 +0000
+++ b/src/layout_util.c Tue Apr 08 20:56:50 2008 +0000
@@ -593,7 +593,38 @@
{
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 @@
{ "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"), "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 @@
" "
" "
" "
+" "
+" "
" "
" "
" "
diff -r fbbb960a3857 -r e0e2c2b72c5a src/typedefs.h
--- a/src/typedefs.h Tue Apr 08 17:26:13 2008 +0000
+++ b/src/typedefs.h Tue Apr 08 20:56:50 2008 +0000
@@ -122,6 +122,8 @@
typedef struct _FullScreenData FullScreenData;
typedef struct _PixmapFolders PixmapFolders;
+typedef struct _Histogram Histogram;
+
struct _ImageLoader
@@ -379,6 +381,13 @@
gint ref;
};
+struct _Histogram {
+ gulong histmap[256*4];
+ gint histogram_chan;
+ gint histogram_logmode;
+};
+
+
struct _LayoutWindow
{
gchar *path;
@@ -489,6 +498,9 @@
GtkWidget *bar_exif;
GtkWidget *bar_info;
+ gint histogram_enabled;
+ Histogram *histogram;
+
gint bar_sort_enabled;
gint bar_exif_enabled;
gint bar_info_enabled;