Trim trailing white spaces.
[geeqie.git] / src / histogram.c
index fb01ef0..8e379fb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Geeqie
- * Copyright (C) 2008 - 2009 The Geeqie Team
+ * Copyright (C) 2008 - 2012 The Geeqie Team
  *
  * Author: Vladimir Nadvornik
  * based on a patch by Uwe Ohse
@@ -14,6 +14,7 @@
 #include "histogram.h"
 
 #include "pixbuf_util.h"
+#include "filedata.h"
 
 #include <math.h>
 
@@ -30,6 +31,10 @@ struct _HistMap {
        gulong g[HISTMAP_SIZE];
        gulong b[HISTMAP_SIZE];
        gulong max[HISTMAP_SIZE];
+       
+       guint idle_id; /* event source id */
+       GdkPixbuf *pixbuf;
+       gint y;
 };
 
 
@@ -38,7 +43,7 @@ Histogram *histogram_new(void)
        Histogram *histogram;
 
        histogram = g_new0(Histogram, 1);
-       histogram->histogram_channel = HCHAN_RGB;
+       histogram->histogram_channel = HCHAN_DEFAULT;
        histogram->histogram_mode = 0;
 
        /* grid */
@@ -109,7 +114,7 @@ const gchar *histogram_label(Histogram *histogram)
                        case HCHAN_G:   t1 = _("Log Histogram on Green"); break;
                        case HCHAN_B:   t1 = _("Log Histogram on Blue"); break;
                        case HCHAN_RGB: t1 = _("Log Histogram on RGB"); break;
-                       case HCHAN_MAX: t1 = _("Log Histogram on max value"); break;
+                       case HCHAN_MAX: t1 = _("Log Histogram on value"); break;
                        }
        else
                switch (histogram->histogram_channel)
@@ -118,27 +123,50 @@ const gchar *histogram_label(Histogram *histogram)
                        case HCHAN_G:   t1 = _("Linear Histogram on Green"); break;
                        case HCHAN_B:   t1 = _("Linear Histogram on Blue"); break;
                        case HCHAN_RGB: t1 = _("Linear Histogram on RGB"); break;
-                       case HCHAN_MAX: t1 = _("Linear Histogram on max value"); break;
+                       case HCHAN_MAX: t1 = _("Linear Histogram on value"); break;
                        }
        return t1;
 }
 
-static HistMap *histmap_read(GdkPixbuf *imgpixbuf)
+static HistMap *histmap_new(void)
+{
+       HistMap *histmap = g_new0(HistMap, 1);
+       return histmap;
+}
+
+void histmap_free(HistMap *histmap)
 {
-       gint w, h, i, j, srs, has_alpha, step;
+       if (!histmap) return;
+       if (histmap->idle_id) g_source_remove(histmap->idle_id);
+       if (histmap->pixbuf) g_object_unref(histmap->pixbuf);
+       g_free(histmap);
+}
+
+static gboolean histmap_read(HistMap *histmap, gboolean whole)
+{
+       gint w, h, i, j, srs, has_alpha, step, end_line;
        guchar *s_pix;
-       HistMap *histmap;
+       GdkPixbuf *imgpixbuf = histmap->pixbuf;
        
        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);
-
-       histmap = g_new0(HistMap, 1);
+       
+       if (whole)
+               {
+               end_line = h;
+               }
+       else
+               {
+               gint lines = 1 + 16384 / w;
+               end_line = histmap->y + lines;
+               if (end_line > h) end_line = h;
+               }
 
        step = 3 + !!(has_alpha);
-       for (i = 0; i < h; i++)
+       for (i = histmap->y; i < end_line; i++)
                {
                guchar *sp = s_pix + (i * srs); /* 8bit */
                for (j = 0; j < w; j++)
@@ -155,22 +183,45 @@ static HistMap *histmap_read(GdkPixbuf *imgpixbuf)
                        sp += step;
                        }
                }
-       
-       return histmap;
+       histmap->y = end_line;
+       return end_line >= h;
 }
 
 const HistMap *histmap_get(FileData *fd)
 {
-       if (fd->histmap) return fd->histmap;
+       if (fd->histmap && !fd->histmap->idle_id) return fd->histmap; /* histmap exists and is finished */
        
-       if (fd->pixbuf)
+       return NULL;
+}
+
+static gboolean histmap_idle_cb(gpointer data)
+{
+       FileData *fd = data;
+       if (histmap_read(fd->histmap, FALSE))
                {
-               fd->histmap = histmap_read(fd->pixbuf);
-               return fd->histmap;
+               /* finished */
+               g_object_unref(fd->histmap->pixbuf); /*pixbuf is no longer needed */
+               fd->histmap->pixbuf = NULL;
+               fd->histmap->idle_id = 0;
+               file_data_send_notification(fd, NOTIFY_HISTMAP);
+               return FALSE;
                }
-       return NULL;
+       return TRUE;
 }
 
+gboolean histmap_start_idle(FileData *fd)
+{
+       if (fd->histmap || !fd->pixbuf) return FALSE;
+
+       fd->histmap = histmap_new();
+       fd->histmap->pixbuf = fd->pixbuf;
+       g_object_ref(fd->histmap->pixbuf);
+
+       fd->histmap->idle_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, histmap_idle_cb, fd, NULL);
+       return TRUE;
+}
+
+
 static void histogram_vgrid(Histogram *histogram, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height)
 {
        guint i;
@@ -213,7 +264,7 @@ static void histogram_hgrid(Histogram *histogram, GdkPixbuf *pixbuf, gint x, gin
                }
 }
 
-gint histogram_draw(Histogram *histogram, const HistMap *histmap, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height)
+gboolean histogram_draw(Histogram *histogram, const HistMap *histmap, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height)
 {
        /* FIXME: use the coordinates correctly */
        gint i;
@@ -222,17 +273,19 @@ gint histogram_draw(Histogram *histogram, const HistMap *histmap, GdkPixbuf *pix
        gint combine = (HISTMAP_SIZE - 1) / width + 1;
        gint ypos = y + height;
        
-       if (!histogram || !histmap) return 0;
+       if (!histogram || !histmap) return FALSE;
        
        /* Draw the grid */
        histogram_vgrid(histogram, pixbuf, x, y, width, height);
        histogram_hgrid(histogram, pixbuf, x, y, width, height);
 
-       for (i = 0; i < HISTMAP_SIZE; i++)
+       /* exclude overexposed and underexposed */
+       for (i = 1; i < HISTMAP_SIZE - 1; i++)
                {
                if (histmap->r[i] > max) max = histmap->r[i];
                if (histmap->g[i] > max) max = histmap->g[i];
                if (histmap->b[i] > max) max = histmap->b[i];
+               if (histmap->max[i] > max) max = histmap->max[i];
                }
 
        if (max > 0)
@@ -249,6 +302,7 @@ gint histogram_draw(Histogram *histogram, const HistMap *histmap, GdkPixbuf *pix
                gint bplus = 0;
                gint ii = i * HISTMAP_SIZE / width;
                gint xpos = x + i;
+               gint num_chan;
 
                for (j = 0; j < combine; j++)
                        {
@@ -262,15 +316,21 @@ gint histogram_draw(Histogram *histogram, const HistMap *histmap, GdkPixbuf *pix
                for (j = 0; combine > 1 && j < 4; j++)
                        v[j] /= combine;
                
-               for (j = 0; j < 4; j++)
+               num_chan = (histogram->histogram_channel == HCHAN_RGB) ? 3 : 1;
+               for (j = 0; j < num_chan; j++)
                        {
-                       gint chanmax = HCHAN_R;
-               
-                       if (v[HCHAN_G] > v[HCHAN_R]) chanmax = HCHAN_G;
-                       if (v[HCHAN_B] > v[HCHAN_G]) chanmax = HCHAN_B;
-                               
-                       if (histogram->histogram_channel >= HCHAN_RGB
-                           || chanmax == histogram->histogram_channel)
+                       gint chanmax;
+                       if (histogram->histogram_channel == HCHAN_RGB)
+                               {
+                               chanmax = HCHAN_R;
+                               if (v[HCHAN_G] > v[HCHAN_R]) chanmax = HCHAN_G;
+                               if (v[HCHAN_B] > v[chanmax]) chanmax = HCHAN_B;
+                               }
+                       else
+                               {
+                               chanmax = histogram->histogram_channel;
+                               }
+                       
                                {
                                gulong pt;
                                gint r = rplus;
@@ -320,9 +380,10 @@ gint histogram_draw(Histogram *histogram, const HistMap *histmap, GdkPixbuf *pix
 
 void histogram_notify_cb(FileData *fd, NotifyType type, gpointer data)
 {
-       if (type != NOTIFY_TYPE_INTERNAL && fd->histmap)
+       if ((type & NOTIFY_REREAD) && fd->histmap)
                {
-               g_free(fd->histmap);
+               DEBUG_1("Notify histogram: %s %04x", fd->path, type);
+               histmap_free(fd->histmap);
                fd->histmap = NULL;
                }
 }