changeset 1294:7ac9664242b2

histogram caching histogram interface prepared for histogram pane
author nadvornik
date Sun, 15 Feb 2009 13:11:21 +0000
parents 48e064b37ba6
children 8c59e6e50bd8
files src/filedata.c src/histogram.c src/histogram.h src/image-overlay.c src/image.c src/main.c src/typedefs.h
diffstat 7 files changed, 104 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- a/src/filedata.c	Sun Feb 15 09:36:53 2009 +0000
+++ b/src/filedata.c	Sun Feb 15 13:11:21 2009 +0000
@@ -515,7 +515,8 @@
 	g_free(fd->collate_key_name);
 	g_free(fd->collate_key_name_nocase);
 	if (fd->thumb_pixbuf) g_object_unref(fd->thumb_pixbuf);
-
+	g_free(fd->histmap);
+	
 	g_assert(fd->sidecar_files == NULL); /* sidecar files must be freed before calling this */
 
 	file_data_change_info_free(NULL, fd);
--- a/src/histogram.c	Sun Feb 15 09:36:53 2009 +0000
+++ b/src/histogram.c	Sun Feb 15 13:11:21 2009 +0000
@@ -23,10 +23,22 @@
  *----------------------------------------------------------------------------
  */
 
-#define HISTOGRAM_SIZE 256
+#define HISTMAP_SIZE 256
+typedef enum {
+	HISTMAP_CHANNEL_R = 0,
+	HISTMAP_CHANNEL_G,
+	HISTMAP_CHANNEL_B,
+	HISTMAP_CHANNEL_AVG,
+	HISTMAP_CHANNEL_MAX,
+	HISTMAP_CHANNELS
+} HistMapChannels;
+
+struct _HistMap {
+	gulong histmap[HISTMAP_SIZE * HISTMAP_CHANNELS];
+	gulong area;
+};
 
 struct _Histogram {
-	gulong histmap[HISTOGRAM_SIZE*4];
 	gint histogram_chan;
 	gint histogram_logmode;
 };
@@ -104,83 +116,83 @@
 	return t1;
 }
 
-gulong histogram_read(Histogram *histogram, GdkPixbuf *imgpixbuf)
+static HistMap *histmap_read(GdkPixbuf *imgpixbuf)
 {
 	gint w, h, i, j, srs, has_alpha, step;
 	guchar *s_pix;
 
-	if (!histogram) return 0;
-
+	HistMap *histmap;
+	
 	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);
 
-	memset(histogram->histmap, 0, sizeof(histogram->histmap));
+	histmap = g_new0(HistMap, 1);
 
-	/* code duplication is here to speed up the calculation */
 	step = 3 + !!(has_alpha);
-	if (histogram->histogram_chan == HCHAN_MAX)
+	for (i = 0; i < h; i++)
 		{
-		for (i = 0; i < h; i++)
+		guchar *sp = s_pix + (i * srs); /* 8bit */
+		for (j = 0; j < w; j++)
 			{
-			guchar *sp = s_pix + (i * srs); /* 8bit */
-			for (j = 0; j < w; j++)
-				{
-				guchar t = sp[0];
-				if (sp[1]>t) t = sp[1];
-				if (sp[2]>t) t = sp[2];
+			guint avg = (sp[0] + sp[1] + sp[2]) / 3;
+			guint max = sp[0];
+			if (sp[1] > max) max = sp[1];
+			if (sp[2] > max) max = sp[2];
 
-				histogram->histmap[sp[0] + 0 * HISTOGRAM_SIZE]++;
-				histogram->histmap[sp[1] + 1 * HISTOGRAM_SIZE]++;
-				histogram->histmap[sp[2] + 2 * HISTOGRAM_SIZE]++;
-				histogram->histmap[t + 3 * HISTOGRAM_SIZE]++;
-				sp += step;
-				}
+			histmap->histmap[sp[0] * HISTMAP_CHANNELS + HISTMAP_CHANNEL_R]++;
+			histmap->histmap[sp[1] * HISTMAP_CHANNELS + HISTMAP_CHANNEL_G]++;
+			histmap->histmap[sp[2] * HISTMAP_CHANNELS + HISTMAP_CHANNEL_B]++;
+			histmap->histmap[avg   * HISTMAP_CHANNELS + HISTMAP_CHANNEL_AVG]++;
+			histmap->histmap[max   * HISTMAP_CHANNELS + HISTMAP_CHANNEL_MAX]++;
+			sp += step;
 			}
 		}
-	else
-		{
-		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_SIZE]++;
-				histogram->histmap[sp[1] + 1 * HISTOGRAM_SIZE]++;
-				histogram->histmap[sp[2] + 2 * HISTOGRAM_SIZE]++;
-				histogram->histmap[3 * HISTOGRAM_SIZE + (sp[0]+sp[1]+sp[2])/3]++;
-				sp += step;
-				}
-			}
-		}
-
-	return w*h;
+	histmap->area = w * h;
+	return histmap;
 }
 
-gint histogram_draw(Histogram *histogram, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height)
+HistMap *histmap_get(FileData *fd)
+{
+	if (fd->histmap) return fd->histmap;
+	
+	if (fd->pixbuf) 
+		{
+		fd->histmap = histmap_read(fd->pixbuf);
+		return fd->histmap;
+		}
+	return NULL;
+}
+
+gint histogram_draw(Histogram *histogram, HistMap *histmap, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height)
 {
 	/* FIXME: use the coordinates correctly */
 	gint i;
 	gulong max = 0;
 	gdouble logmax;
 
-	if (!histogram) return 0;
+	if (!histogram || !histmap) return 0;
 
 	for (i = 0; i < 1024; i++) {
+#if 0
+		/* this is probably broken for MAX or VAL mode */
 		gint 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;
+			case HCHAN_RGB: if ((i % HISTMAP_CHANNELS) < 3) flag = 1; break;
+			case HCHAN_R:   if ((i % HISTMAP_CHANNELS) == HISTMAP_CHANNEL_R) flag = 1; break;
+			case HCHAN_G:   if ((i % HISTMAP_CHANNELS) == HISTMAP_CHANNEL_G) flag = 1; break;
+			case HCHAN_B:   if ((i % HISTMAP_CHANNELS) == HISTMAP_CHANNEL_B) flag = 1; break;
+			case HCHAN_VAL: if ((i % HISTMAP_CHANNELS) == HISTMAP_CHANNEL_AVG) flag = 1; break;
+			case HCHAN_MAX: if ((i % HISTMAP_CHANNELS) == HISTMAP_CHANNEL_MAX) flag = 1; break;
 			}
-		if (flag && histogram->histmap[i] > max) max = histogram->histmap[i];
+		if (flag && histmap->histmap[i] > max) max = histmap->histmap[i];
+#else
+		if (histmap->histmap[i] > max) max = histmap->histmap[i];
+#endif
 	}
 
 	logmax = log(max);
@@ -191,15 +203,21 @@
 		gint rplus = 0;
 		gint gplus = 0;
 		gint bplus = 0;
-		gint ii = i * HISTOGRAM_SIZE / width;
-		gint combine  = (HISTOGRAM_SIZE - 1) / width + 1;
+		gint ii = i * HISTMAP_SIZE / width;
+		gint combine  = (HISTMAP_SIZE - 1) / width + 1;
 
 		for (j = 0; j < combine; j++)
 			{
-			v[0] += histogram->histmap[ii + j + 0 * HISTOGRAM_SIZE]; // r
-			v[1] += histogram->histmap[ii + j + 1 * HISTOGRAM_SIZE]; // g
-			v[2] += histogram->histmap[ii + j + 2 * HISTOGRAM_SIZE]; // b
-			v[3] += histogram->histmap[ii + j + 3 * HISTOGRAM_SIZE]; // value, max
+			v[0] += histmap->histmap[(ii + j) * HISTMAP_CHANNELS + HISTMAP_CHANNEL_R]; // r
+			v[1] += histmap->histmap[(ii + j) * HISTMAP_CHANNELS + HISTMAP_CHANNEL_G]; // g
+			v[2] += histmap->histmap[(ii + j) * HISTMAP_CHANNELS + HISTMAP_CHANNEL_B]; // b
+			v[3] += histmap->histmap[(ii + j) * HISTMAP_CHANNELS + 
+			        ((histogram->histogram_chan == HCHAN_VAL) ? HISTMAP_CHANNEL_AVG : HISTMAP_CHANNEL_MAX)]; // value, max
+			}
+			
+		for (j = 0; j < 4; j++)
+			{
+			v[j] /= combine;
 			}
 
 		for (j = 0; j < 4; j++)
@@ -258,4 +276,14 @@
 
 	return TRUE;
 }
+
+void histogram_notify_cb(FileData *fd, NotifyType type, gpointer data)
+{
+	if (type != NOTIFY_TYPE_INTERNAL && fd->histmap)
+		{
+		g_free(fd->histmap);
+		fd->histmap = NULL;
+		}
+}
+
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/histogram.h	Sun Feb 15 09:36:53 2009 +0000
+++ b/src/histogram.h	Sun Feb 15 13:11:21 2009 +0000
@@ -30,8 +30,10 @@
 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);
-gint histogram_draw(Histogram *histogram, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height);
+HistMap *histmap_get(FileData *fd);
+gint histogram_draw(Histogram *histogram, HistMap *histmap, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height);
+
+void histogram_notify_cb(FileData *fd, NotifyType type, gpointer data);
 
 #endif /* HISTOGRAM_H */
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/image-overlay.c	Sun Feb 15 09:36:53 2009 +0000
+++ b/src/image-overlay.c	Sun Feb 15 13:11:21 2009 +0000
@@ -442,6 +442,7 @@
 	gchar *text;
 	GdkPixbuf *imgpixbuf = NULL;
 	gboolean with_hist;
+	HistMap *histmap;
 	ImageWindow *imd = osd->imd;
 	FileData *fd = image_get_fd(imd);
 
@@ -553,7 +554,13 @@
 		text = g_markup_escape_text(_("Untitled"), -1);
 	}
 
-	with_hist = (imgpixbuf && (osd->show & OSD_SHOW_HISTOGRAM) && osd->histogram && (!imd->il || image_loader_get_is_done(imd->il)));
+	with_hist = ((osd->show & OSD_SHOW_HISTOGRAM) && osd->histogram);
+	if (with_hist)
+		{
+		histmap = histmap_get(imd->image_fd);
+		if (!histmap) with_hist = FALSE;
+		}
+	
 	
 	{
 		gint active_marks = 0;
@@ -611,7 +618,6 @@
 
 	if (with_hist)
 		{
-		histogram_read(osd->histogram, imgpixbuf);
 		if (width < HISTOGRAM_WIDTH + 10) width = HISTOGRAM_WIDTH + 10;
 		height += HISTOGRAM_HEIGHT + 5;
 		}
@@ -649,7 +655,7 @@
 				xoffset += add+d;
 				}
 						
-			histogram_draw(osd->histogram, pixbuf, x, y, w, HISTOGRAM_HEIGHT);
+			histogram_draw(osd->histogram, histmap, pixbuf, x, y, w, HISTOGRAM_HEIGHT);
 			}
 		pixbuf_draw_layout(pixbuf, layout, imd->pr, 5, 5, 0, 0, 0, 255);
 	}
--- a/src/image.c	Sun Feb 15 09:36:53 2009 +0000
+++ b/src/image.c	Sun Feb 15 13:11:21 2009 +0000
@@ -538,14 +538,14 @@
 
 	DEBUG_1("%s image done", get_exec_time());
 
-	g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
-	image_state_unset(imd, IMAGE_STATE_LOADING);
-
 	if (options->image.enable_read_ahead && imd->image_fd && !imd->image_fd->pixbuf && image_loader_get_pixbuf(imd->il))
 		{
 		imd->image_fd->pixbuf = g_object_ref(image_loader_get_pixbuf(imd->il));
 		image_cache_set(imd, imd->image_fd);
 		}
+	/* call the callback triggered by image_state after fd->pixbuf is set */
+	g_object_set(G_OBJECT(imd->pr), "loading", FALSE, NULL);
+	image_state_unset(imd, IMAGE_STATE_LOADING);
 
 	if (!image_loader_get_pixbuf(imd->il))
 		{
--- a/src/main.c	Sun Feb 15 09:36:53 2009 +0000
+++ b/src/main.c	Sun Feb 15 13:11:21 2009 +0000
@@ -33,6 +33,7 @@
 #include "metadata.h"
 #include "editors.h"
 #include "exif.h"
+#include "histogram.h"
 
 #include <gdk/gdkkeysyms.h> /* for keyboard values */
 
@@ -743,6 +744,7 @@
 	/* register global notify functions */
 	file_data_register_notify_func(cache_notify_cb, NULL, NOTIFY_PRIORITY_HIGH);
 	file_data_register_notify_func(thumb_notify_cb, NULL, NOTIFY_PRIORITY_HIGH);
+	file_data_register_notify_func(histogram_notify_cb, NULL, NOTIFY_PRIORITY_HIGH);
 	file_data_register_notify_func(collect_manager_notify_cb, NULL, NOTIFY_PRIORITY_LOW);
 
 	parse_command_line_for_debug_option(argc, argv);
--- a/src/typedefs.h	Sun Feb 15 09:36:53 2009 +0000
+++ b/src/typedefs.h	Sun Feb 15 13:11:21 2009 +0000
@@ -200,6 +200,7 @@
 
 typedef struct _PixmapFolders PixmapFolders;
 typedef struct _Histogram Histogram;
+typedef struct _HistMap HistMap;
 
 typedef struct _SecureSaveInfo SecureSaveInfo;
 
@@ -451,6 +452,8 @@
 
 	GdkPixbuf *pixbuf; /* full-size image, only complete images, NULL during loading
 			      all FileData with non-NULL pixbuf are referenced by image_cache */
+			      
+	HistMap *histmap;
 
 	gint ref;
 	gint version; /* increased when any field in this structure is changed */