/* * imagedisplay.c * * Show raw and processed images * * (c) 2007 Thomas White * * dtr - Diffraction Tomography Reconstruction * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include "imagedisplay.h" #include "utils.h" #include "control.h" /* Free pixbuf data when reference count drops to zero */ static void imagedisplay_free_data(guchar *image_eightbit, ImageDisplay *imagedisplay) { free(image_eightbit); } static void imagedisplay_rescale(ImageDisplay *imagedisplay, unsigned int v_w, unsigned int v_h) { unsigned int w, h; float aspect_image, aspect_window; w = imagedisplay->imagerecord.width; h = imagedisplay->imagerecord.height; /* Preserve aspect ratio */ aspect_image = (float)w/h; aspect_window = (float)v_w/v_h; if ( aspect_window > aspect_image ) { v_w = aspect_image*v_h; } else { v_h = v_w/aspect_image; } /* Create the scaled pixbuf from the 8-bit display data */ imagedisplay->pixbuf_scaled = gdk_pixbuf_scale_simple(imagedisplay->pixbuf, v_w, v_h, GDK_INTERP_BILINEAR); imagedisplay->view_width = v_w; imagedisplay->view_height = v_h; } static gboolean imagedisplay_configure_event(GtkWidget *widget, GdkEventConfigure *event, ImageDisplay *imagedisplay) { imagedisplay->drawingarea_width = event->width; imagedisplay->drawingarea_height = event->height; imagedisplay_rescale(imagedisplay, event->width, event->height); return FALSE; } void imagedisplay_put_data(ImageDisplay *imagedisplay, ImageRecord imagerecord) { unsigned int x, y; unsigned int w, h; int min, max; double c, scale; h = imagerecord.height; w = imagerecord.width; if ( imagedisplay->pixbuf ) { g_object_unref(imagedisplay->pixbuf); } min = 2<<15; max = 0; for ( y=0; y max ) max = val; if ( val < min ) min = val; } } c = 0.1; scale = 255.0 / log(1+c*(max-min)); /* Turn 16-bit image data into 8-bit display data */ imagedisplay->data = malloc(3*w*h); for ( y=0; ydata[3*( x+w*(h-1-y) )] = val8; imagedisplay->data[3*( x+w*(h-1-y) )+1] = val8; imagedisplay->data[3*( x+w*(h-1-y) )+2] = val8; } } /* Create the pixbuf from the 8-bit display data */ imagedisplay->pixbuf = gdk_pixbuf_new_from_data(imagedisplay->data, GDK_COLORSPACE_RGB, FALSE, 8, w, h, w*3, (GdkPixbufDestroyNotify)imagedisplay_free_data, imagedisplay); if ( imagedisplay->realised ) { imagedisplay_force_redraw(imagedisplay); } } static void imagedisplay_destroyed(GtkWidget *widget, ImageDisplay *imagedisplay) { ImageDisplayMark *cur; if ( imagedisplay->flags & IMAGEDISPLAY_QUIT_IF_CLOSED ) { gtk_exit(0); } g_object_unref(G_OBJECT(imagedisplay->gc_centre)); g_object_unref(G_OBJECT(imagedisplay->gc_tiltaxis)); g_object_unref(G_OBJECT(imagedisplay->gc_marks)); cur = imagedisplay->marks; while ( cur ) { ImageDisplayMark *next = cur->next; free(cur); cur = next; } free(imagedisplay); } void imagedisplay_close(ImageDisplay *imagedisplay) { imagedisplay->flags = (imagedisplay->flags | IMAGEDISPLAY_QUIT_IF_CLOSED)^IMAGEDISPLAY_QUIT_IF_CLOSED; gtk_widget_destroy(imagedisplay->window); } #define imagedisplay_draw_line(gc,x1,y1,x2,y2) (gdk_draw_line(drawingarea->window,gc, \ xoffs+(x1), yoffs+imagedisplay->view_height-(y1), \ xoffs+(x2), yoffs+imagedisplay->view_height-(y2))) static gboolean imagedisplay_redraw(GtkWidget *drawingarea, GdkEventExpose *event, ImageDisplay *imagedisplay) { double scale, xoffs, yoffs; ImageDisplayMark *cur; xoffs = ((double)imagedisplay->drawingarea_width - imagedisplay->view_width) / 2; yoffs = ((double)imagedisplay->drawingarea_height - imagedisplay->view_height) / 2; scale = (double)imagedisplay->view_width/imagedisplay->imagerecord.width; gdk_draw_pixbuf(drawingarea->window, drawingarea->style->bg_gc[GTK_WIDGET_STATE(drawingarea)], imagedisplay->pixbuf_scaled, 0, 0, xoffs, yoffs, imagedisplay->view_width, imagedisplay->view_height, GDK_RGB_DITHER_NONE, 0, 0); if ( imagedisplay->flags & IMAGEDISPLAY_SHOW_TILT_AXIS ) { /* This is nasty, but works */ imagedisplay_draw_line(imagedisplay->gc_tiltaxis, imagedisplay->imagerecord.x_centre * scale, imagedisplay->imagerecord.y_centre * scale, (imagedisplay->imagerecord.x_centre + imagedisplay->imagerecord.width) * scale, (imagedisplay->imagerecord.y_centre + imagedisplay->imagerecord.width * tan(deg2rad(imagedisplay->imagerecord.omega))) * scale); imagedisplay_draw_line(imagedisplay->gc_tiltaxis, imagedisplay->imagerecord.x_centre * scale, imagedisplay->imagerecord.y_centre * scale, (imagedisplay->imagerecord.x_centre - imagedisplay->imagerecord.width) * scale, (imagedisplay->imagerecord.y_centre - imagedisplay->imagerecord.width * tan(deg2rad(imagedisplay->imagerecord.omega))) * scale); } if ( imagedisplay->flags & IMAGEDISPLAY_SHOW_CENTRE ) { imagedisplay_draw_line(imagedisplay->gc_centre, imagedisplay->imagerecord.x_centre * scale - 10, imagedisplay->imagerecord.y_centre * scale, imagedisplay->imagerecord.x_centre * scale + 10, imagedisplay->imagerecord.y_centre * scale); imagedisplay_draw_line(imagedisplay->gc_centre, imagedisplay->imagerecord.x_centre * scale, imagedisplay->imagerecord.y_centre * scale - 10, imagedisplay->imagerecord.x_centre * scale, imagedisplay->imagerecord.y_centre * scale + 10); } cur = imagedisplay->marks; while ( cur ) { gdk_draw_arc(drawingarea->window, imagedisplay->gc_marks, FALSE, xoffs + imagedisplay->view_height-cur->x*scale - 5, yoffs + imagedisplay->view_height-cur->y*scale - 5, 11, 11, 0, 64*360); cur = cur->next; } return FALSE; } static gint imagedisplay_realize(GtkWidget *widget, ImageDisplay *imagedisplay) { GdkColor colour; imagedisplay->gc_centre = gdk_gc_new(imagedisplay->drawingarea->window); gdk_color_parse("yellow", &colour); gdk_gc_set_rgb_fg_color(imagedisplay->gc_centre, &colour); imagedisplay->gc_tiltaxis = gdk_gc_new(imagedisplay->drawingarea->window); gdk_color_parse("#6600dd", &colour); gdk_gc_set_rgb_fg_color(imagedisplay->gc_tiltaxis, &colour); imagedisplay->gc_marks = gdk_gc_new(imagedisplay->drawingarea->window); gdk_color_parse("#dd0000", &colour); gdk_gc_set_rgb_fg_color(imagedisplay->gc_marks, &colour); imagedisplay->realised = TRUE; return 0; } /* Display an image */ ImageDisplay *imagedisplay_open_with_message(ImageRecord imagerecord, const char *title, const char *message, ImageDisplayFlags flags, GCallback mouse_click_func, gpointer callback_data) { ImageDisplay *imagedisplay; GdkGeometry geom; imagedisplay = malloc(sizeof(ImageDisplay)); imagedisplay->imagerecord = imagerecord; imagedisplay->view_width = 512; imagedisplay->view_height = 512; imagedisplay->title = strdup(title); imagedisplay->message = message; imagedisplay->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); imagedisplay->mouse_click_func = mouse_click_func; imagedisplay->flags = flags; imagedisplay->marks = NULL; imagedisplay->pixbuf = NULL; imagedisplay->realised = FALSE; gtk_window_set_title(GTK_WINDOW(imagedisplay->window), imagedisplay->title); imagedisplay_put_data(imagedisplay, imagerecord); imagedisplay->vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(imagedisplay->window), imagedisplay->vbox); if ( message ) { GtkWidget *label; label = gtk_label_new(message); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); gtk_box_pack_start(GTK_BOX(imagedisplay->vbox), label, FALSE, TRUE, 3); } imagedisplay->drawingarea = gtk_drawing_area_new(); gtk_box_pack_start(GTK_BOX(imagedisplay->vbox), imagedisplay->drawingarea, TRUE, TRUE, 0); if ( imagedisplay->mouse_click_func ) { gtk_widget_add_events(GTK_WIDGET(imagedisplay->drawingarea), GDK_BUTTON_PRESS_MASK); g_signal_connect(GTK_OBJECT(imagedisplay->drawingarea), "button-press-event", G_CALLBACK(imagedisplay->mouse_click_func), callback_data); } g_signal_connect(GTK_OBJECT(imagedisplay->drawingarea), "realize", G_CALLBACK(imagedisplay_realize), imagedisplay); g_signal_connect(GTK_OBJECT(imagedisplay->drawingarea), "destroy", G_CALLBACK(imagedisplay_destroyed), imagedisplay); g_signal_connect(GTK_OBJECT(imagedisplay->drawingarea), "configure_event", G_CALLBACK(imagedisplay_configure_event), imagedisplay); g_signal_connect(GTK_OBJECT(imagedisplay->drawingarea), "expose-event", G_CALLBACK(imagedisplay_redraw), imagedisplay); geom.min_width = 128; geom.min_height = 128; gtk_window_set_geometry_hints(GTK_WINDOW(imagedisplay->window), GTK_WIDGET(imagedisplay->drawingarea), &geom, GDK_HINT_MIN_SIZE); gtk_window_set_default_size(GTK_WINDOW(imagedisplay->window), 512, 512); gtk_widget_show_all(imagedisplay->window); return imagedisplay; } ImageDisplay *imagedisplay_open(ImageRecord image, const char *title, ImageDisplayFlags flags) { return imagedisplay_open_with_message(image, title, NULL, flags, NULL, NULL); } void imagedisplay_mark_circle(ImageDisplay *imagedisplay, double x, double y) { ImageDisplayMark *new; new = malloc(sizeof(ImageDisplayMark)); new->x = x; new->y = y; new->type = IMAGEDISPLAY_MARK_CIRCLE; new->next = NULL; if ( !imagedisplay->marks ) { imagedisplay->marks = new; } else { ImageDisplayMark *cur = imagedisplay->marks; while ( cur->next ) { cur = cur->next; } cur->next = new; } } void imagedisplay_force_redraw(ImageDisplay *imagedisplay) { imagedisplay_rescale(imagedisplay, imagedisplay->drawingarea_width, imagedisplay->drawingarea_height); gtk_widget_queue_draw_area(imagedisplay->drawingarea, 0, 0, imagedisplay->drawingarea_width, imagedisplay->drawingarea_height); }