histogram caching
authorVladimir Nadvornik <nadvornik@suse.cz>
Sun, 15 Feb 2009 13:11:21 +0000 (13:11 +0000)
committerVladimir Nadvornik <nadvornik@suse.cz>
Sun, 15 Feb 2009 13:11:21 +0000 (13:11 +0000)
histogram interface prepared for histogram pane

src/filedata.c
src/histogram.c
src/histogram.h
src/image-overlay.c
src/image.c
src/main.c
src/typedefs.h

index e8c4e1b..cf089fb 100644 (file)
@@ -515,7 +515,8 @@ 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);
+       
        g_assert(fd->sidecar_files == NULL); /* sidecar files must be freed before calling this */
 
        file_data_change_info_free(NULL, fd);
index d983166..8bb5fa5 100644 (file)
  *----------------------------------------------------------------------------
  */
 
-#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 @@ const gchar *histogram_label(Histogram *histogram)
        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];
-
-                               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;
-                               }
+                       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];
+
+                       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
+       histmap->area = w * h;
+       return histmap;
+}
+
+HistMap *histmap_get(FileData *fd)
+{
+       if (fd->histmap) return fd->histmap;
+       
+       if (fd->pixbuf) 
                {
-               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;
-                               }
-                       }
+               fd->histmap = histmap_read(fd->pixbuf);
+               return fd->histmap;
                }
-
-       return w*h;
+       return NULL;
 }
 
-gint histogram_draw(Histogram *histogram, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height)
+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 histogram_draw(Histogram *histogram, GdkPixbuf *pixbuf, gint x, gint y, gin
                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 @@ gint histogram_draw(Histogram *histogram, GdkPixbuf *pixbuf, gint x, gint y, gin
 
        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: */
index 309987f..fb93624 100644 (file)
@@ -30,8 +30,10 @@ 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);
-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: */
index 93ec331..dcab2b5 100644 (file)
@@ -442,6 +442,7 @@ static GdkPixbuf *image_osd_info_render(OverlayStateData *osd)
        gchar *text;
        GdkPixbuf *imgpixbuf = NULL;
        gboolean with_hist;
+       HistMap *histmap;
        ImageWindow *imd = osd->imd;
        FileData *fd = image_get_fd(imd);
 
@@ -553,7 +554,13 @@ static GdkPixbuf *image_osd_info_render(OverlayStateData *osd)
                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 @@ static GdkPixbuf *image_osd_info_render(OverlayStateData *osd)
 
        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 @@ static GdkPixbuf *image_osd_info_render(OverlayStateData *osd)
                                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);
        }
index ec601c8..303c71a 100644 (file)
@@ -538,14 +538,14 @@ static void image_load_done_cb(ImageLoader *il, gpointer data)
 
        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))
                {
index 2d99632..3e5b273 100644 (file)
@@ -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 @@ gint main(gint argc, gchar *argv[])
        /* 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);
index 762490d..b90b897 100644 (file)
@@ -200,6 +200,7 @@ typedef struct _FullScreenData FullScreenData;
 
 typedef struct _PixmapFolders PixmapFolders;
 typedef struct _Histogram Histogram;
+typedef struct _HistMap HistMap;
 
 typedef struct _SecureSaveInfo SecureSaveInfo;
 
@@ -451,6 +452,8 @@ struct _FileData {
 
        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 */