aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/detector.c24
-rw-r--r--src/detector.h2
-rw-r--r--src/displaywindow.c179
-rw-r--r--src/displaywindow.h7
-rw-r--r--src/render.c142
-rw-r--r--src/render.h5
6 files changed, 325 insertions, 34 deletions
diff --git a/src/detector.c b/src/detector.c
index 209958b1..633af6df 100644
--- a/src/detector.c
+++ b/src/detector.c
@@ -491,3 +491,27 @@ void free_detector_geometry(struct detector *det)
free(det->panels);
free(det);
}
+
+
+struct detector *simple_geometry(const struct image *image)
+{
+ struct detector *geom;
+
+ geom = calloc(1, sizeof(struct detector));
+
+ geom->n_panels = 1;
+ geom->panels = calloc(1, sizeof(struct panel));
+
+ geom->panels[0].min_fs = 0;
+ geom->panels[0].max_fs = image->width-1;
+ geom->panels[0].min_ss = 0;
+ geom->panels[0].max_ss = image->height-1;
+ geom->panels[0].cx = -image->width / 2.0;
+ geom->panels[0].cy = -image->height / 2.0;
+ geom->panels[0].fsx = 1;
+ geom->panels[0].fsy = 0;
+ geom->panels[0].ssx = 0;
+ geom->panels[0].ssy = 1;
+
+ return geom;
+}
diff --git a/src/detector.h b/src/detector.h
index c32fd07b..f5ae25ca 100644
--- a/src/detector.h
+++ b/src/detector.h
@@ -60,4 +60,6 @@ extern struct panel *find_panel(struct detector *det, int x, int y);
extern struct detector *get_detector_geometry(const char *filename);
extern void free_detector_geometry(struct detector *det);
+extern struct detector *simple_geometry(const struct image *image);
+
#endif /* DETECTOR_H */
diff --git a/src/displaywindow.c b/src/displaywindow.c
index 07e121eb..cb985b64 100644
--- a/src/displaywindow.c
+++ b/src/displaywindow.c
@@ -70,21 +70,29 @@ static void displaywindow_update(DisplayWindow *dw)
GTK_WIDGET(dw->drawingarea), &geom,
GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
- if ( dw->pixbuf != NULL ) {
- gdk_pixbuf_unref(dw->pixbuf);
+ /* Free old pixbufs */
+ if ( dw->pixbufs != NULL ) {
+ int i;
+ for ( i=0; i<dw->n_pixbufs; i++ ) {
+ gdk_pixbuf_unref(dw->pixbufs[i]);
+ }
+ free(dw->pixbufs);
+ }
+ if ( dw->col_scale != NULL ) {
+ gdk_pixbuf_unref(dw->col_scale);
}
+
if ( dw->image != NULL ) {
- dw->pixbuf = render_get_image(dw->image, dw->binning, dw->scale,
- dw->boostint);
+ dw->pixbufs = render_panels(dw->image, dw->binning,
+ dw->scale, dw->boostint,
+ &dw->n_pixbufs);
} else {
- dw->pixbuf = NULL;
+ dw->pixbufs = NULL;
}
- if ( dw->col_scale != NULL ) {
- gdk_pixbuf_unref(dw->col_scale);
- }
dw->col_scale = render_get_colour_scale(20, dw->height, dw->scale);
+ /* Schedule redraw */
gdk_window_invalidate_rect(dw->drawingarea->window, NULL, FALSE);
}
@@ -114,26 +122,49 @@ static gboolean displaywindow_expose(GtkWidget *da, GdkEventExpose *event,
/* Blank white background */
cairo_rectangle(cr, 0.0, 0.0, da->allocation.width,
da->allocation.height);
- cairo_set_source_rgb(cr, 0.0, 0.0, 1.0);
+ cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
cairo_fill(cr);
- if ( dw->pixbuf != NULL ) {
- gdk_draw_pixbuf(da->window,
- da->style->bg_gc[GTK_WIDGET_STATE(da)],
- dw->pixbuf,
- 0, 0, 0, 0, dw->width, dw->height,
- GDK_RGB_DITHER_NONE, 0, 0);
+ if ( dw->pixbufs != NULL ) {
+
+ int i;
+
+ for ( i=0; i<dw->image->det->n_panels; i++ ) {
+
+ struct panel p = dw->image->det->panels[i];
+ int w = gdk_pixbuf_get_width(dw->pixbufs[i]);
+ int h = gdk_pixbuf_get_height(dw->pixbufs[i]);
+ cairo_matrix_t m;
+
+ cairo_identity_matrix(cr);
+ cairo_translate(cr, dw->width/2.0, dw->height/2.0);
+ cairo_translate(cr, p.cx/dw->binning, p.cy/dw->binning);
+
+ cairo_matrix_init(&m, p.fsx, p.fsy, p.ssx, p.ssy,
+ 0.0, 0.0);
+ cairo_transform(cr, &m);
+
+ gdk_cairo_set_source_pixbuf(cr, dw->pixbufs[i],
+ 0.0, 0.0);
+ cairo_rectangle(cr, 0.0, 0.0, w, h);
+ cairo_fill(cr);
+
+ }
+
}
if ( (dw->show_col_scale) && (dw->col_scale != NULL) ) {
- gdk_draw_pixbuf(da->window,
- da->style->bg_gc[GTK_WIDGET_STATE(da)],
- dw->col_scale,
- 0, 0, dw->width, 0, 20, dw->height,
- GDK_RGB_DITHER_NONE, 0, 0);
+ cairo_identity_matrix(cr);
+ cairo_translate(cr, dw->width, 0.0);
+ cairo_rectangle(cr, 0.0, 0.0, 20.0, dw->height);
+ gdk_cairo_set_source_pixbuf(cr, dw->col_scale, 0.0, 0.0);
+ cairo_fill(cr);
}
- if ( dw->image->features == NULL ) return FALSE;
+ if ( dw->image->features == NULL ) {
+ cairo_destroy(cr);
+ return FALSE;
+ }
for ( i=0; i<image_feature_count(dw->image->features); i++ ) {
@@ -533,15 +564,36 @@ static gint displaywindow_about(GtkWidget *widget, DisplayWindow *dw)
static int load_geometry_file(DisplayWindow *dw, struct image *image,
- const char *filename)
+ const char *filename)
{
struct detector *geom;
+ GtkWidget *w;
geom = get_detector_geometry(filename);
- if ( geom == NULL ) return -1;
+ if ( geom == NULL ) {
+ displaywindow_error(dw, "Failed to load geometry file");
+ return -1;
+ }
+
+ if ( (1+geom->max_fs != dw->image->width)
+ || (1+geom->max_ss != dw->image->height) ) {
+
+ displaywindow_error(dw, "Geometry doesn't match image.");
+ return -1;
+
+ }
+
+ if ( dw->loaded_geom != NULL ) free_detector_geometry(dw->loaded_geom);
+ dw->loaded_geom = geom;
+
+
+ w = gtk_ui_manager_get_widget(dw->ui,
+ "/ui/displaywindow/view/usegeom");
+ gtk_widget_set_sensitive(GTK_WIDGET(w), TRUE);
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), TRUE);
+ dw->use_geom = 1;
+ displaywindow_update(dw);
- if ( image->det != NULL ) free_detector_geometry(image->det);
- image->det = geom;
return 0;
}
@@ -557,8 +609,6 @@ static gint displaywindow_loadgeom_response(GtkWidget *d, gint response,
if ( load_geometry_file(dw, dw->image, filename) == 0 ) {
displaywindow_update(dw);
- } else {
- displaywindow_error(dw, "Failed to load geometry file");
}
g_free(filename);
@@ -611,9 +661,23 @@ static gint displaywindow_peak_overlay(GtkWidget *widget, DisplayWindow *dw)
}
-static gint displaywindow_set_usegeom(GtkWidget *d, gint response,
- DisplayWindow *dw)
+static gint displaywindow_set_usegeom(GtkWidget *d, DisplayWindow *dw)
{
+ GtkWidget *w;
+
+ /* Get new value */
+ w = gtk_ui_manager_get_widget(dw->ui,
+ "/ui/displaywindow/view/usegeom");
+ dw->use_geom = gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w));
+
+ if ( dw->use_geom ) {
+ dw->image->det = dw->loaded_geom;
+ } else {
+ dw->image->det = dw->simple_geom;
+ }
+
+ displaywindow_update(dw);
+
return 0;
}
@@ -641,7 +705,8 @@ static gint displaywindow_save_response(GtkWidget *d, gint response,
type = gtk_combo_box_get_active(GTK_COMBO_BOX(cd->cb));
if ( type == 0 ) {
- r = render_png(dw->pixbuf, file);
+ /* FIXME: Use Cairo or something */
+ r = render_png(dw->pixbufs[0], file);
} else if ( type == 1 ) {
r = render_tiff_fp(dw->image, file);
} else if ( type == 2 ) {
@@ -917,8 +982,6 @@ static void displaywindow_addmenubar(DisplayWindow *dw, GtkWidget *vbox,
G_CALLBACK(displaywindow_set_binning) },
{ "BoostIntAction", NULL, "Boost Intensity...", "F5", NULL,
G_CALLBACK(displaywindow_set_boostint) },
- { "GeometryAction", NULL, "Use Detector Geometry", NULL, NULL,
- G_CALLBACK(displaywindow_set_usegeom) },
{ "ToolsAction", NULL, "_Tools", NULL, NULL, NULL },
{ "NumbersAction", NULL, "View Numbers...", "F2", NULL,
@@ -939,6 +1002,8 @@ static void displaywindow_addmenubar(DisplayWindow *dw, GtkWidget *vbox,
GtkToggleActionEntry toggles[] = {
{ "ColScaleAction", NULL, "Show Colour Scale", NULL, NULL,
G_CALLBACK(displaywindow_set_colscale), FALSE },
+ { "GeometryAction", NULL, "Use Detector Geometry", NULL, NULL,
+ G_CALLBACK(displaywindow_set_usegeom), FALSE },
};
guint n_toggles = G_N_ELEMENTS(toggles);
GtkRadioActionEntry radios[] = {
@@ -977,6 +1042,16 @@ static void displaywindow_addmenubar(DisplayWindow *dw, GtkWidget *vbox,
}
+
+static int geometry_fits(struct image *image, struct detector *geom)
+{
+ if ( (1+geom->max_fs != image->width)
+ || (1+geom->max_ss != image->height) ) return 0;
+
+ return 1;
+}
+
+
struct newhdf {
DisplayWindow *dw;
char name[1024];
@@ -986,6 +1061,34 @@ static gint displaywindow_newhdf(GtkMenuItem *item, struct newhdf *nh)
{
hdfile_set_image(nh->dw->hdfile, nh->name);
hdf5_read(nh->dw->hdfile, nh->dw->image, 0, 0.0);
+
+ /* Check that the geometry still fits */
+ if ( !geometry_fits(nh->dw->image, nh->dw->simple_geom) ) {
+ free_detector_geometry(nh->dw->simple_geom);
+ nh->dw->simple_geom = simple_geometry(nh->dw->image);
+ }
+
+ if ( (nh->dw->loaded_geom != NULL )
+ && (!geometry_fits(nh->dw->image, nh->dw->loaded_geom)) ) {
+
+ GtkWidget *w;
+
+ free_detector_geometry(nh->dw->loaded_geom);
+
+ w = gtk_ui_manager_get_widget(nh->dw->ui,
+ "/ui/displaywindow/view/usegeom");
+ gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE);
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w), FALSE);
+ nh->dw->use_geom = 0;
+
+ }
+
+ if ( nh->dw->use_geom ) {
+ nh->dw->image->det = nh->dw->loaded_geom;
+ } else {
+ nh->dw->image->det = nh->dw->simple_geom;
+ }
+
displaywindow_update(nh->dw);
return 0;
}
@@ -1229,10 +1332,11 @@ DisplayWindow *displaywindow_open(const char *filename, const char *peaks,
DisplayWindow *dw;
char *title;
GtkWidget *vbox;
+ GtkWidget *w;
dw = malloc(sizeof(DisplayWindow));
if ( dw == NULL ) return NULL;
- dw->pixbuf = NULL;
+ dw->pixbufs = NULL;
dw->binning_dialog = NULL;
dw->show_col_scale = 0;
dw->col_scale = NULL;
@@ -1241,6 +1345,7 @@ DisplayWindow *displaywindow_open(const char *filename, const char *peaks,
dw->motion_callback = 0;
dw->numbers_window = NULL;
dw->image = NULL;
+ dw->use_geom = 0;
dw->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@@ -1301,6 +1406,14 @@ DisplayWindow *displaywindow_open(const char *filename, const char *peaks,
gtk_window_set_resizable(GTK_WINDOW(dw->window), FALSE);
gtk_widget_show_all(dw->window);
+ /* No geometry loaded initially */
+ w = gtk_ui_manager_get_widget(dw->ui,
+ "/ui/displaywindow/view/usegeom");
+ gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE);
+ dw->loaded_geom = NULL;
+ dw->simple_geom = simple_geometry(dw->image);
+ dw->image->det = dw->simple_geom;
+
dw->scale = colscale;
dw->binning = binning;
dw->boostint = boost;
diff --git a/src/displaywindow.h b/src/displaywindow.h
index 72917e00..fb7192cf 100644
--- a/src/displaywindow.h
+++ b/src/displaywindow.h
@@ -47,9 +47,13 @@ typedef struct {
GtkWidget *drawingarea;
GtkUIManager *ui;
GtkActionGroup *action_group;
- GdkPixbuf *pixbuf;
+ int n_pixbufs;
+ GdkPixbuf **pixbufs;
gulong motion_callback;
+ struct detector *loaded_geom;
+ struct detector *simple_geom;
+
struct hdfile *hdfile;
struct image *image;
@@ -64,6 +68,7 @@ typedef struct {
double boostint;
int cmfilter; /* Use CM subtraction */
int noisefilter; /* Use aggressive noise filter */
+ int use_geom;
int show_col_scale;
int scale;
diff --git a/src/render.c b/src/render.c
index 231225f2..96fab6d2 100644
--- a/src/render.c
+++ b/src/render.c
@@ -185,6 +185,50 @@ static float *get_binned_image(struct image *image, int binning, float *pmax)
}
+static float *get_binned_panel(struct image *image, int binning,
+ int min_fs, int max_fs, int min_ss, int max_ss)
+{
+ float *data;
+ int x, y;
+ int w, h;
+ int fw;
+ float *in;
+
+ fw = image->width;
+ in = image->data;
+
+ /* Some pixels might get discarded */
+ w = (max_fs - min_fs + 1) / binning;
+ h = (max_ss - min_ss + 1) / binning;
+
+ data = malloc(w*h*sizeof(float));
+
+ for ( x=0; x<w; x++ ) {
+ for ( y=0; y<h; y++ ) {
+
+ double total;
+ size_t xb, yb;
+
+ total = 0;
+ for ( xb=0; xb<binning; xb++ ) {
+ for ( yb=0; yb<binning; yb++ ) {
+
+ double v;
+ v = in[binning*x+xb+min_fs + (binning*y+yb+min_ss)*fw];
+ total += v;
+
+ }
+ }
+
+ data[x+w*y] = total / ((double)binning * (double)binning);
+
+ }
+ }
+
+ return data;
+}
+
+
/* NB This function is shared between render_get_image() and
* render_get_colour_scale() */
static void render_free_data(guchar *data, gpointer p)
@@ -254,6 +298,104 @@ GdkPixbuf *render_get_image(struct image *image, int binning, int scale,
}
+static GdkPixbuf *render_panel(struct image *image,
+ int binning, int scale, double boost,
+ int min_fs, int max_fs, int min_ss, int max_ss)
+{
+ int w, h;
+ guchar *data;
+ float *hdr;
+ int x, y;
+ double max;
+ int pw, ph;
+ int i;
+
+ /* Calculate panel width and height
+ * (add one because min and max are inclusive) */
+ pw = max_fs - min_fs + 1;
+ ph = max_ss - min_ss + 1;
+ w = pw / binning;
+ h = ph / binning;
+
+ /* High dynamic range version */
+ max = 0.0;
+ for ( i=0; i<image->width*image->height; i++ ) {
+ if ( image->data[i] > max ) max = image->data[i];
+ }
+ hdr = get_binned_panel(image, binning, min_fs, max_fs, min_ss, max_ss);
+ if ( hdr == NULL ) return NULL;
+
+ /* Rendered (colourful) version */
+ data = malloc(3*w*h);
+ if ( data == NULL ) {
+ free(hdr);
+ return NULL;
+ }
+
+ max /= boost;
+ if ( max <= 6 ) { max = 10; }
+ /* These x,y coordinates are measured relative to the bottom-left
+ * corner */
+ for ( y=0; y<h; y++ ) {
+ for ( x=0; x<w; x++ ) {
+
+ float val;
+ float r, g, b;
+
+ val = hdr[x+w*y];
+ render_scale(val, max, scale, &r, &g, &b);
+
+ /* Stuff inside square brackets makes this pixel go to
+ * the expected location in the pixbuf (which measures
+ * from the top-left corner */
+ data[3*( x+w*(h-1-y) )+0] = 255*r;
+ data[3*( x+w*(h-1-y) )+1] = 255*g;
+ data[3*( x+w*(h-1-y) )+2] = 255*b;
+
+ }
+ }
+
+ /* Finished with this */
+ free(hdr);
+
+ /* Create the pixbuf from the 8-bit display data */
+ return gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, FALSE, 8,
+ w, h, w*3, render_free_data, NULL);
+
+}
+
+
+/* Render an image into multiple pixbufs according to geometry */
+GdkPixbuf **render_panels(struct image *image,
+ int binning, int scale, double boost,
+ int *n_pixbufs)
+{
+ int i;
+ int np = image->det->n_panels;
+ GdkPixbuf **pixbufs;
+
+ pixbufs = calloc(np, sizeof(GdkPixbuf*));
+ if ( pixbufs == NULL ) {
+ *n_pixbufs = 0;
+ return NULL;
+ }
+
+ for ( i=0; i<np; i++ ) {
+
+ pixbufs[i] = render_panel(image, binning, scale, boost,
+ image->det->panels[i].min_fs,
+ image->det->panels[i].max_fs,
+ image->det->panels[i].min_ss,
+ image->det->panels[i].max_ss);
+
+ }
+
+ *n_pixbufs = np;
+
+ return pixbufs;
+}
+
+
GdkPixbuf *render_get_colour_scale(size_t w, size_t h, int scale)
{
guchar *data;
diff --git a/src/render.h b/src/render.h
index 214e011e..79d7ec68 100644
--- a/src/render.h
+++ b/src/render.h
@@ -39,6 +39,11 @@ extern void render_scale(float val, float max, int scale,
extern GdkPixbuf *render_get_image(struct image *image,
int binning, int scale, double boost);
+
+extern GdkPixbuf **render_panels(struct image *image,
+ int binning, int scale, double boost,
+ int *n_pixbufs);
+
extern GdkPixbuf *render_get_colour_scale(size_t w, size_t h, int scale);
extern int render_png(GdkPixbuf *pixbuf, const char *filename);