aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@physics.org>2010-04-27 18:01:25 +0200
committerThomas White <taw@physics.org>2010-04-27 18:01:47 +0200
commit206c163522a4d3e5ffc8ab6817dce1675196344f (patch)
tree42785276b4b4b33a86fb84ae200f82dfb60cba8a
parent409fd287a1c29a661b138a90b8b4334d502a1847 (diff)
hdfsee: Add ability to save image as PNG
Also moves the "Image" menu to "View", where it belongs.
-rwxr-xr-xconfigure19
-rw-r--r--configure.ac13
-rw-r--r--data/displaywindow.ui4
-rw-r--r--src/displaywindow.c96
-rw-r--r--src/render.c110
-rw-r--r--src/render.h5
6 files changed, 242 insertions, 5 deletions
diff --git a/configure b/configure
index 8b36eee3..b85ee57e 100755
--- a/configure
+++ b/configure
@@ -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 */