Skip to content

Commit

Permalink
histogram caching
Browse files Browse the repository at this point in the history
histogram interface prepared for histogram pane
  • Loading branch information
nadvornik committed Feb 15, 2009
1 parent c5ead17 commit a660cd9
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 61 deletions.
3 changes: 2 additions & 1 deletion src/filedata.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
132 changes: 80 additions & 52 deletions src/histogram.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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);
Expand All @@ -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++)
Expand Down Expand Up @@ -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: */
6 changes: 4 additions & 2 deletions src/histogram.h
Original file line number Diff line number Diff line change
Expand Up @@ -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: */
12 changes: 9 additions & 3 deletions src/image-overlay.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
}
Expand Down
6 changes: 3 additions & 3 deletions src/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down
2 changes: 2 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "metadata.h"
#include "editors.h"
#include "exif.h"
#include "histogram.h"

#include <gdk/gdkkeysyms.h> /* for keyboard values */

Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions src/typedefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ typedef struct _FullScreenData FullScreenData;

typedef struct _PixmapFolders PixmapFolders;
typedef struct _Histogram Histogram;
typedef struct _HistMap HistMap;

typedef struct _SecureSaveInfo SecureSaveInfo;

Expand Down Expand Up @@ -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 */
Expand Down

0 comments on commit a660cd9

Please sign in to comment.