3 * Copyright (C) 2008 - 2009 The Geeqie Team
5 * Author: Vladimir Nadvornik
6 * based on a patch by Uwe Ohse
8 * This software is released under the GNU General Public License (GNU GPL).
9 * Please read the included file COPYING for more information.
10 * This software comes with no warranty of any kind, use at your own risk!
14 #include "histogram.h"
16 #include "pixbuf_util.h"
21 *----------------------------------------------------------------------------
23 *----------------------------------------------------------------------------
26 #define HISTMAP_SIZE 256
29 gulong r[HISTMAP_SIZE];
30 gulong g[HISTMAP_SIZE];
31 gulong b[HISTMAP_SIZE];
32 gulong max[HISTMAP_SIZE];
36 Histogram *histogram_new(void)
40 histogram = g_new0(Histogram, 1);
41 histogram->histogram_channel = HCHAN_RGB;
42 histogram->histogram_mode = 0;
47 histogram->grid_color.R = 160;
48 histogram->grid_color.G = 160;
49 histogram->grid_color.B = 160;
50 histogram->grid_color.A = 250;
55 void histogram_free(Histogram *histogram)
61 gint histogram_set_channel(Histogram *histogram, gint chan)
63 if (!histogram) return 0;
64 histogram->histogram_channel = chan;
68 gint histogram_get_channel(Histogram *histogram)
70 if (!histogram) return 0;
71 return histogram->histogram_channel;
74 gint histogram_set_mode(Histogram *histogram, gint mode)
76 if (!histogram) return 0;
77 histogram->histogram_mode = mode;
81 gint histogram_get_mode(Histogram *histogram)
83 if (!histogram) return 0;
84 return histogram->histogram_mode;
87 gint histogram_toggle_channel(Histogram *histogram)
89 if (!histogram) return 0;
90 return histogram_set_channel(histogram, (histogram_get_channel(histogram)+1)%HCHAN_COUNT);
93 gint histogram_toggle_mode(Histogram *histogram)
95 if (!histogram) return 0;
96 return histogram_set_mode(histogram, !histogram_get_mode(histogram));
99 const gchar *histogram_label(Histogram *histogram)
101 const gchar *t1 = "";
103 if (!histogram) return NULL;
105 if (histogram->histogram_mode)
106 switch (histogram->histogram_channel)
108 case HCHAN_R: t1 = _("Log Histogram on Red"); break;
109 case HCHAN_G: t1 = _("Log Histogram on Green"); break;
110 case HCHAN_B: t1 = _("Log Histogram on Blue"); break;
111 case HCHAN_RGB: t1 = _("Log Histogram on RGB"); break;
112 case HCHAN_MAX: t1 = _("Log Histogram on value"); break;
115 switch (histogram->histogram_channel)
117 case HCHAN_R: t1 = _("Linear Histogram on Red"); break;
118 case HCHAN_G: t1 = _("Linear Histogram on Green"); break;
119 case HCHAN_B: t1 = _("Linear Histogram on Blue"); break;
120 case HCHAN_RGB: t1 = _("Linear Histogram on RGB"); break;
121 case HCHAN_MAX: t1 = _("Linear Histogram on value"); break;
126 static HistMap *histmap_read(GdkPixbuf *imgpixbuf)
128 gint w, h, i, j, srs, has_alpha, step;
132 w = gdk_pixbuf_get_width(imgpixbuf);
133 h = gdk_pixbuf_get_height(imgpixbuf);
134 srs = gdk_pixbuf_get_rowstride(imgpixbuf);
135 s_pix = gdk_pixbuf_get_pixels(imgpixbuf);
136 has_alpha = gdk_pixbuf_get_has_alpha(imgpixbuf);
138 histmap = g_new0(HistMap, 1);
140 step = 3 + !!(has_alpha);
141 for (i = 0; i < h; i++)
143 guchar *sp = s_pix + (i * srs); /* 8bit */
144 for (j = 0; j < w; j++)
147 if (sp[1] > max) max = sp[1];
148 if (sp[2] > max) max = sp[2];
162 const HistMap *histmap_get(FileData *fd)
164 if (fd->histmap) return fd->histmap;
168 fd->histmap = histmap_read(fd->pixbuf);
174 static void histogram_vgrid(Histogram *histogram, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height)
179 if (histogram->vgrid == 0) return;
181 add = width / (float)histogram->vgrid;
183 for (i = 1; i < histogram->vgrid; i++)
185 gint xpos = x + (int)(i * add + 0.5);
187 pixbuf_draw_line(pixbuf, x, y, width, height, xpos, y, xpos, y + height,
188 histogram->grid_color.R,
189 histogram->grid_color.G,
190 histogram->grid_color.B,
191 histogram->grid_color.A);
195 static void histogram_hgrid(Histogram *histogram, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height)
200 if (histogram->hgrid == 0) return;
202 add = height / (float)histogram->hgrid;
204 for (i = 1; i < histogram->hgrid; i++)
206 gint ypos = y + (int)(i * add + 0.5);
208 pixbuf_draw_line(pixbuf, x, y, width, height, x, ypos, x + width, ypos,
209 histogram->grid_color.R,
210 histogram->grid_color.G,
211 histogram->grid_color.B,
212 histogram->grid_color.A);
216 gint histogram_draw(Histogram *histogram, const HistMap *histmap, GdkPixbuf *pixbuf, gint x, gint y, gint width, gint height)
218 /* FIXME: use the coordinates correctly */
222 gint combine = (HISTMAP_SIZE - 1) / width + 1;
223 gint ypos = y + height;
225 if (!histogram || !histmap) return 0;
228 histogram_vgrid(histogram, pixbuf, x, y, width, height);
229 histogram_hgrid(histogram, pixbuf, x, y, width, height);
231 for (i = 0; i < HISTMAP_SIZE; i++)
233 if (histmap->r[i] > max) max = histmap->r[i];
234 if (histmap->g[i] > max) max = histmap->g[i];
235 if (histmap->b[i] > max) max = histmap->b[i];
243 for (i = 0; i < width; i++)
246 glong v[4] = {0, 0, 0, 0};
250 gint ii = i * HISTMAP_SIZE / width;
253 for (j = 0; j < combine; j++)
256 v[0] += histmap->r[p];
257 v[1] += histmap->g[p];
258 v[2] += histmap->b[p];
259 v[3] += histmap->max[p];
262 for (j = 0; combine > 1 && j < 4; j++)
265 for (j = 0; j < 4; j++)
267 gint chanmax = HCHAN_R;
269 if (v[HCHAN_G] > v[HCHAN_R]) chanmax = HCHAN_G;
270 if (v[HCHAN_B] > v[HCHAN_G]) chanmax = HCHAN_B;
272 if (histogram->histogram_channel >= HCHAN_RGB
273 || chanmax == histogram->histogram_channel)
282 case HCHAN_R: rplus = r = 255; break;
283 case HCHAN_G: gplus = g = 255; break;
284 case HCHAN_B: bplus = b = 255; break;
287 switch (histogram->histogram_channel)
290 if (r == 255 && g == 255 && b == 255)
295 case HCHAN_R: b = 0; g = 0; break;
296 case HCHAN_G: r = 0; b = 0; break;
297 case HCHAN_B: r = 0; g = 0; break;
298 case HCHAN_MAX: r = 0; b = 0; g = 0; break;
303 else if (histogram->histogram_mode)
304 pt = ((gdouble)log(v[chanmax])) / logmax * (height - 1);
306 pt = ((gdouble)v[chanmax]) / max * (height - 1);
308 pixbuf_draw_line(pixbuf,
310 xpos, ypos, xpos, ypos - pt,
321 void histogram_notify_cb(FileData *fd, NotifyType type, gpointer data)
323 if (type != NOTIFY_TYPE_INTERNAL && fd->histmap)
330 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */