diff options
author | Thomas White <taw@physics.org> | 2010-04-27 18:01:25 +0200 |
---|---|---|
committer | Thomas White <taw@physics.org> | 2010-04-27 18:01:47 +0200 |
commit | 206c163522a4d3e5ffc8ab6817dce1675196344f (patch) | |
tree | 42785276b4b4b33a86fb84ae200f82dfb60cba8a | |
parent | 409fd287a1c29a661b138a90b8b4334d502a1847 (diff) |
hdfsee: Add ability to save image as PNG
Also moves the "Image" menu to "View", where it belongs.
-rwxr-xr-x | configure | 19 | ||||
-rw-r--r-- | configure.ac | 13 | ||||
-rw-r--r-- | data/displaywindow.ui | 4 | ||||
-rw-r--r-- | src/displaywindow.c | 96 | ||||
-rw-r--r-- | src/render.c | 110 | ||||
-rw-r--r-- | src/render.h | 5 |
6 files changed, 242 insertions, 5 deletions
@@ -5700,6 +5700,25 @@ done +{ $as_echo "$as_me:$LINENO: checking libpng" >&5 +$as_echo_n "checking libpng... " >&6; } +if $PKG_CONFIG --atleast-version 1.2.0 libpng ; then + LIBPNG_VERSION=`$PKG_CONFIG --modversion libpng` + { $as_echo "$as_me:$LINENO: result: $LIBPNG_VERSION" >&5 +$as_echo "$LIBPNG_VERSION" >&6; } + LIBPNG_CFLAGS=`$PKG_CONFIG --cflags libpng` + LIBPNG_LIBS=`$PKG_CONFIG --libs libpng` +else + { $as_echo "$as_me:$LINENO: result: Lower than 1.2.0 or not found" >&5 +$as_echo "Lower than 1.2.0 or not found" >&6; } + { { $as_echo "$as_me:$LINENO: error: +*** libPNG is required to build CrystFEL" >&5 +$as_echo "$as_me: error: +*** libPNG is required to build CrystFEL" >&2;} + { (exit 1); exit 1; }; } +fi + + CFLAGS="$CFLAGS $HDF5_CFLAGS $GTK_CFLAGS $GSL_CFLAGS $OPENCL_CFLAGS -pthread" LIBS="$LIBS $HDF5_LIBS -lm -lz $GSL_LIBS $GTK_LIBS $OPENCL_LIBS -pthread" diff --git a/configure.ac b/configure.ac index ab8b4790..9fb61bc2 100644 --- a/configure.ac +++ b/configure.ac @@ -91,6 +91,19 @@ AC_CHECK_FUNCS(forkpty, ) +AC_MSG_CHECKING([libpng]) +if $PKG_CONFIG --atleast-version 1.2.0 libpng ; then + LIBPNG_VERSION=`$PKG_CONFIG --modversion libpng` + AC_MSG_RESULT($LIBPNG_VERSION) + LIBPNG_CFLAGS=`$PKG_CONFIG --cflags libpng` + LIBPNG_LIBS=`$PKG_CONFIG --libs libpng` +else + AC_MSG_RESULT([Lower than 1.2.0 or not found]) + AC_MSG_ERROR([ +*** libPNG is required to build CrystFEL]) +fi + + CFLAGS="$CFLAGS $HDF5_CFLAGS $GTK_CFLAGS $GSL_CFLAGS $OPENCL_CFLAGS -pthread" LIBS="$LIBS $HDF5_LIBS -lm -lz $GSL_LIBS $GTK_LIBS $OPENCL_LIBS -pthread" diff --git a/data/displaywindow.ui b/data/displaywindow.ui index 4ca3f737..7975ad4f 100644 --- a/data/displaywindow.ui +++ b/data/displaywindow.ui @@ -2,12 +2,14 @@ <menubar name="displaywindow"> <menu name="file" action="FileAction"> - <menuitem name="images" action="ImagesAction" /> + <menuitem name="save" action="SaveAction" /> <separator /> <menuitem name="close" action="CloseAction" /> </menu> <menu name="view" action="ViewAction"> + <menuitem name="images" action="ImagesAction" /> + <separator /> <menuitem name="binning" action="BinningAction" /> <menuitem name="boostint" action="BoostIntAction" /> <separator /> diff --git a/src/displaywindow.c b/src/displaywindow.c index a5141dab..7dd51aea 100644 --- a/src/displaywindow.c +++ b/src/displaywindow.c @@ -517,6 +517,92 @@ static gint displaywindow_peak_overlay(GtkWidget *widget, DisplayWindow *dw) } +struct savedialog { + DisplayWindow *dw; + GtkWidget *cb; +}; + + +static gint displaywindow_save_response(GtkWidget *d, gint response, + struct savedialog *cd) +{ + DisplayWindow *dw = cd->dw; + int r; + + if ( response == GTK_RESPONSE_ACCEPT ) { + + char *file; + int type; + + file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d)); + + type = gtk_combo_box_get_active(GTK_COMBO_BOX(cd->cb)); + + if ( type == 0 ) { + r = render_png(dw, file); + } else if ( type == 1 ) { + r = render_tiff_fp(dw, file); + } else if ( type == 2 ) { + r = render_tiff_int16(dw, file); + } else { + r = -1; + } + + if ( r != 0 ) { + displaywindow_error(dw, "Unable to save the image."); + } + + g_free(file); + + } + + gtk_widget_destroy(d); + free(cd); + + return 0; +} + + +static gint displaywindow_save(GtkWidget *widget, DisplayWindow *dw) +{ + GtkWidget *d, *hbox, *l, *cb; + struct savedialog *cd; + + d = gtk_file_chooser_dialog_new("Save Image", + GTK_WINDOW(dw->window), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(d), + TRUE); + + hbox = gtk_hbox_new(FALSE, 0); + gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(d), hbox); + cb = gtk_combo_box_new_text(); + gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(cb), TRUE, TRUE, 5); + l = gtk_label_new("Save as type:"); + gtk_box_pack_end(GTK_BOX(hbox), GTK_WIDGET(l), FALSE, FALSE, 5); + + gtk_combo_box_append_text(GTK_COMBO_BOX(cb), "PNG - 8 bit RGB"); + gtk_combo_box_append_text(GTK_COMBO_BOX(cb), "TIFF - Floating point"); + gtk_combo_box_append_text(GTK_COMBO_BOX(cb), "TIFF - 16 bit integer"); + gtk_combo_box_set_active(GTK_COMBO_BOX(cb), 0); + + cd = malloc(sizeof(*cd)); + cd->dw = dw; + cd->cb = cb; + + g_signal_connect(G_OBJECT(d), "response", + G_CALLBACK(displaywindow_save_response), cd); + + gtk_widget_show_all(d); + + return 0; +} + + static gint displaywindow_set_colscale(GtkWidget *widget, DisplayWindow *dw) { dw->show_col_scale = 1 - dw->show_col_scale; @@ -701,11 +787,13 @@ static void displaywindow_addmenubar(DisplayWindow *dw, GtkWidget *vbox) GtkActionEntry entries[] = { { "FileAction", NULL, "_File", NULL, NULL, NULL }, - { "ImagesAction", NULL, "Images", NULL, NULL, NULL }, + { "SaveAction", GTK_STOCK_SAVE, "Save Image...", NULL, NULL, + G_CALLBACK(displaywindow_save) }, { "CloseAction", GTK_STOCK_CLOSE, "_Close", NULL, NULL, G_CALLBACK(displaywindow_close) }, { "ViewAction", NULL, "_View", NULL, NULL, NULL }, + { "ImagesAction", NULL, "Images", NULL, NULL, NULL }, { "BinningAction", NULL, "Set Binning...", "F3", NULL, G_CALLBACK(displaywindow_set_binning) }, { "BoostIntAction", NULL, "Boost Intensity...", "F5", NULL, @@ -897,13 +985,13 @@ static void displaywindow_update_menus(DisplayWindow *dw) /* Too bad. You'd better hope that /data/data exists... */ ERROR("Couldn't get list of images in HDF file\n"); w = gtk_ui_manager_get_widget(dw->ui, - "/ui/displaywindow/file/images"); + "/ui/displaywindow/view/images"); gtk_widget_set_sensitive(GTK_WIDGET(w), FALSE); /* Add a dummy menu so that the user knows what's going on */ ms = gtk_menu_new(); w = gtk_ui_manager_get_widget(dw->ui, - "/ui/displaywindow/file/images"); + "/ui/displaywindow/view/images"); gtk_menu_item_set_submenu(GTK_MENU_ITEM(w), ms); return; @@ -911,7 +999,7 @@ static void displaywindow_update_menus(DisplayWindow *dw) } /* Make new menu be the submenu for File->Images */ - w = gtk_ui_manager_get_widget(dw->ui, "/ui/displaywindow/file/images"); + w = gtk_ui_manager_get_widget(dw->ui, "/ui/displaywindow/view/images"); gtk_menu_item_set_submenu(GTK_MENU_ITEM(w), ms); gtk_widget_show_all(ms); diff --git a/src/render.c b/src/render.c index 7c66f67c..e0189b0a 100644 --- a/src/render.c +++ b/src/render.c @@ -17,6 +17,7 @@ #include <gdk-pixbuf/gdk-pixbuf.h> #include <math.h> #include <stdint.h> +#include <png.h> #include "hdf5-file.h" #include "render.h" @@ -325,3 +326,112 @@ GdkPixbuf *render_get_colour_scale(size_t w, size_t h, int monochrome) return gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, FALSE, 8, w, h, w*3, render_free_data, NULL); } + + +int render_png(DisplayWindow *dw, const char *filename) +{ + FILE *fh; + png_structp png_ptr; + png_infop info_ptr; + png_bytep *row_pointers; + int x, y; + float *hdr; + float max; + int w, h; + + w = dw->width; + h = dw->height; + + hdr = render_get_image_binned(dw, dw->binning, &max); + if ( hdr == NULL ) return 1; + + fh = fopen(filename, "wb"); + if ( !fh ) { + ERROR("Couldn't open output file.\n"); + return 1; + } + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + if ( !png_ptr ) { + ERROR("Couldn't create PNG write structure.\n"); + fclose(fh); + return 1; + } + info_ptr = png_create_info_struct(png_ptr); + if ( !info_ptr ) { + png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + ERROR("Couldn't create PNG info structure.\n"); + fclose(fh); + return 1; + } + if ( setjmp(png_jmpbuf(png_ptr)) ) { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fh); + ERROR( "PNG write failed.\n"); + return 1; + } + png_init_io(png_ptr, fh); + + png_set_IHDR(png_ptr, info_ptr, w, h, 8, + PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + row_pointers = malloc(h*sizeof(png_bytep *)); + + /* Write the image data */ + max /= dw->boostint; + if ( max <= 6 ) { max = 10; } + + for ( y=0; y<h; y++ ) { + + row_pointers[y] = malloc(w*3); + + for ( x=0; x<w; x++ ) { + + int r, g, b; + float val; + + val = hdr[x+w*y]; + + RENDER_RGB + + row_pointers[y][3*x] = (png_byte)r; + row_pointers[y][3*x+1] = (png_byte)g; + row_pointers[y][3*x+2] = (png_byte)b; + + } + } + + for ( y=0; y<h/2+1; y++ ) { + png_bytep scratch; + scratch = row_pointers[y]; + row_pointers[y] = row_pointers[h-y-1]; + row_pointers[h-y-1] = scratch; + } + + png_set_rows(png_ptr, info_ptr, row_pointers); + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + png_destroy_write_struct(&png_ptr, &info_ptr); + for ( y=0; y<h; y++ ) { + free(row_pointers[y]); + } + free(row_pointers); + fclose(fh); + + free(hdr); + + return 0; +} + + +int render_tiff_fp(DisplayWindow *dw, const char *filename) +{ + return 1; +} + + +int render_tiff_int16(DisplayWindow *dw, const char *filename) +{ + return 1; +} diff --git a/src/render.h b/src/render.h index 29f69ec4..c0570d2f 100644 --- a/src/render.h +++ b/src/render.h @@ -22,6 +22,7 @@ #include <stddef.h> #include "displaywindow.h" +#include "image.h" enum { SCALE_COLOUR, @@ -32,5 +33,9 @@ enum { extern GdkPixbuf *render_get_image(DisplayWindow *dw); extern GdkPixbuf *render_get_colour_scale(size_t w, size_t h, int scale); +extern int render_png(DisplayWindow *dw, const char *filename); +extern int render_tiff_fp(DisplayWindow *dw, const char *filename); +extern int render_tiff_int16(DisplayWindow *dw, const char *filename); + #endif /* RENDER_H */ |