changeset 273:e0e2c2b72c5a

reworked the histogram patch by Uwe Ohse, most of the code is in separate files
author nadvornik
date Tue, 08 Apr 2008 20:56:50 +0000
parents fbbb960a3857
children 2710d14f6a28
files doc/8_2_fullscreen.html src/Makefile.am src/histogram.c src/histogram.h src/image-overlay.c src/image-overlay.h src/image.c src/layout.c src/layout_util.c src/typedefs.h
diffstat 10 files changed, 406 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- 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:</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 @@
 				<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>
--- 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	\
--- /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 <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;
+}
--- /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);
--- 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] ? " <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 @@
 	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;
 }
--- 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
 
--- 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)
--- 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,
--- 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"),	"<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 @@
 "      <separator/>"
 "      <menuitem action='FolderTree'/>"
 "      <menuitem action='ImageOverlay'/>"
+"      <menuitem action='HistogramChan'/>"
+"      <menuitem action='HistogramLog'/>"
 "      <menuitem action='FullScreen'/>"
 "      <separator/>"
 "      <menuitem action='FloatTools'/>"
--- 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;