compute histogram in idle time
authorVladimir Nadvornik <nadvornik@suse.cz>
Sun, 15 Mar 2009 11:34:09 +0000 (11:34 +0000)
committerVladimir Nadvornik <nadvornik@suse.cz>
Sun, 15 Mar 2009 11:34:09 +0000 (11:34 +0000)
src/bar_histogram.c
src/filedata.c
src/histogram.c
src/histogram.h
src/image-overlay.c

index 5bbe806..0869fd0 100644 (file)
@@ -83,7 +83,11 @@ static gboolean bar_pane_histogram_update_cb(gpointer data)
        
        histmap = histmap_get(phd->fd);
        
-       if (!histmap) return FALSE;
+       if (!histmap) 
+               {
+               histmap_start_idle(phd->fd);
+               return FALSE;
+               }
        
        phd->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, phd->histogram_width, phd->histogram_height);
        gdk_pixbuf_fill(phd->pixbuf, 0xffffffff);
@@ -126,7 +130,7 @@ static void bar_pane_histogram_write_config(GtkWidget *pane, GString *outstr, gi
 static void bar_pane_histogram_notify_cb(FileData *fd, NotifyType type, gpointer data)
 {
        PaneHistogramData *phd = data;
-       if (fd == phd->fd) bar_pane_histogram_update(phd);
+       if ((type & (NOTIFY_REREAD | NOTIFY_CHANGE | NOTIFY_HISTMAP | NOTIFY_PIXBUF)) && fd == phd->fd) bar_pane_histogram_update(phd);
 }
 
 static gboolean bar_pane_histogram_expose_event_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data)
index ea9748a..785b84f 100644 (file)
@@ -20,6 +20,7 @@
 #include "ui_fileops.h"
 #include "metadata.h"
 #include "trash.h"
+#include "histogram.h"
 
 
 static GHashTable *file_data_pool = NULL;
@@ -509,7 +510,7 @@ static void file_data_free(FileData *fd)
        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);
+       histmap_free(fd->histmap);
        
        g_assert(fd->sidecar_files == NULL); /* sidecar files must be freed before calling this */
 
index b35488a..8f65376 100644 (file)
@@ -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];
+       
+       gint idle_id;
+       GdkPixbuf *pixbuf;
+       gint y;
 };
 
 
@@ -123,22 +128,46 @@ const gchar *histogram_label(Histogram *histogram)
        return t1;
 }
 
-static HistMap *histmap_read(GdkPixbuf *imgpixbuf)
+static HistMap *histmap_new(void)
+{
+       HistMap *histmap = g_new0(HistMap, 1);
+       histmap->idle_id = -1;
+       return histmap;
+}
+
+void histmap_free(HistMap *histmap)
+{
+       if (!histmap) return;
+       if (histmap->idle_id != -1) 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;
+       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 +184,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 == -1) 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 = -1;
+               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;
@@ -322,7 +374,7 @@ void histogram_notify_cb(FileData *fd, NotifyType type, gpointer data)
 {
        if ((type & (NOTIFY_CHANGE || NOTIFY_REREAD)) && fd->histmap)
                {
-               g_free(fd->histmap);
+               histmap_free(fd->histmap);
                fd->histmap = NULL;
                }
 }
index cb3ada8..991367b 100644 (file)
@@ -31,7 +31,12 @@ gint histogram_get_mode(Histogram *histogram);
 gint histogram_toggle_channel(Histogram *histogram);
 gint histogram_toggle_mode(Histogram *histogram);
 const gchar *histogram_label(Histogram *histogram);
+
+void histmap_free(HistMap *histmap);
+
 const HistMap *histmap_get(FileData *fd);
+gboolean histmap_start_idle(FileData *fd);
+
 gboolean histogram_draw(Histogram *histogram, const HistMap *histmap, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height);
 
 void histogram_notify_cb(FileData *fd, NotifyType type, gpointer data);
index 929c0fd..50c6f2d 100644 (file)
@@ -37,6 +37,7 @@ typedef struct _OverlayStateData OverlayStateData;
 struct _OverlayStateData {
        ImageWindow *imd;
        ImageState changed_states;
+       NotifyType notify;
 
        Histogram *histogram;
 
@@ -557,7 +558,11 @@ static GdkPixbuf *image_osd_info_render(OverlayStateData *osd)
        if (with_hist)
                {
                histmap = histmap_get(imd->image_fd);
-               if (!histmap) with_hist = FALSE;
+               if (!histmap) 
+                       {
+                       histmap_start_idle(imd->image_fd);
+                       with_hist = FALSE;
+                       }
                }
        
        
@@ -829,7 +834,8 @@ static gboolean image_osd_update_cb(gpointer data)
                /* redraw when the image was changed, 
                   with histogram we have to redraw also when loading is finished */
                if (osd->changed_states & IMAGE_STATE_IMAGE ||
-                   (osd->changed_states & IMAGE_STATE_LOADING && osd->show & OSD_SHOW_HISTOGRAM)) 
+                   (osd->changed_states & IMAGE_STATE_LOADING && osd->show & OSD_SHOW_HISTOGRAM) ||
+                   osd->notify & NOTIFY_HISTMAP)
                        {
                        GdkPixbuf *pixbuf;
 
@@ -884,6 +890,7 @@ static gboolean image_osd_update_cb(gpointer data)
 
        if (osd->imd->il && image_loader_get_is_done(osd->imd->il))
                osd->changed_states = IMAGE_STATE_NONE;
+       osd->notify = 0;
        osd->idle_id = -1;
        return FALSE;
 }
@@ -958,6 +965,18 @@ static void image_osd_state_cb(ImageWindow *imd, ImageState state, gpointer data
        image_osd_update_schedule(osd, FALSE);
 }
 
+static void image_osd_notify_cb(FileData *fd, NotifyType type, gpointer data)
+{
+       OverlayStateData *osd = data;
+
+       if ((type & (NOTIFY_HISTMAP)) && osd->imd && fd == osd->imd->image_fd)
+               {
+               osd->notify |= type;
+               image_osd_update_schedule(osd, FALSE);
+               }
+}
+
+
 static void image_osd_free(OverlayStateData *osd)
 {
        if (!osd) return;
@@ -965,6 +984,8 @@ static void image_osd_free(OverlayStateData *osd)
        if (osd->idle_id != -1) g_source_remove(osd->idle_id);
        if (osd->timer_id != -1) g_source_remove(osd->timer_id);
 
+       file_data_unregister_notify_func(image_osd_notify_cb, osd);
+
        if (osd->imd)
                {
                image_set_osd_data(osd->imd, NULL);
@@ -1017,6 +1038,7 @@ static void image_osd_enable(ImageWindow *imd, OsdShowFlags show)
                image_set_osd_data(imd, osd);
 
                image_set_state_func(osd->imd, image_osd_state_cb, osd);
+               file_data_register_notify_func(image_osd_notify_cb, osd, NOTIFY_PRIORITY_LOW);
                }
 
        if (show & OSD_SHOW_STATUS)