# 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:

+ + + + + + + + + + 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;

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.