diff --git a/src/main.c b/src/main.c
index 182fc81564d237410a0f7764f4afdbe8d95f04d1..cf4b87a79cd175f2b9b5c1e8dc8b48c7109097e3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2,6 +2,8 @@
  * language down at the bottom, so I gotta.  */
 
 #include <assert.h>
+#include <cairo-pdf.h>
+#include <cairo-svg.h>
 #include <ctype.h>
 #include <fcntl.h>
 #include <gtk/gtk.h>
@@ -41,6 +43,11 @@ struct colour {
 
 struct context {
 
+	GtkWidget* window;
+	int width;
+	int height;
+	bool size_set;
+
 	char* read_buffer;
 	size_t read_buffer_len;
 
@@ -126,6 +133,15 @@ struct fd_source {
 
 };
 
+struct save_size {
+
+	GtkWidget* dialogue;
+	GtkWidget* width;
+	GtkWidget* height;
+	struct context* context;
+
+};
+
 /* PROTOTYPES!!! */
 
 static bool add_to_column_list( const char* option_name,
@@ -143,6 +159,9 @@ static void listener_finalise( GSource* source );
 static int key_callback( GtkEventControllerKey* event_controller,
 	unsigned int keyval, unsigned int keycode, GdkModifierType mods,
 	void* data );
+static void save_size_ok( GtkWidget* widget, void* data );
+static void save_callback( GObject* source_object,
+	GAsyncResult* result, void* data );
 static int data_callback( void* data );
 static void parse_headers( struct context* context );
 static void parse_data( struct context* context );
@@ -586,19 +605,20 @@ static void app_activate( GtkApplication* app, void* data ) {
 
 	struct context* context = (struct context*) data;
 
-	GtkWidget* window = gtk_application_window_new( app );
-	gtk_window_set_title( GTK_WINDOW( window ), "E-Plot" );
+	context->window = gtk_application_window_new( app );
+	gtk_window_set_title( GTK_WINDOW( context->window ), "E-Plot" );
 
 	context->plot = gtk_drawing_area_new();
 	gtk_drawing_area_set_draw_func(
 		GTK_DRAWING_AREA( context->plot ), plot_draw, context, NULL );
-	gtk_window_set_child( GTK_WINDOW( window ), context->plot );
+	gtk_window_set_child(
+		GTK_WINDOW( context->window ), context->plot );
 
 	GtkEventController* event_controller =
 		gtk_event_controller_key_new();
 	g_signal_connect( event_controller, "key-released",
 		G_CALLBACK( &key_callback ), context );
-	gtk_widget_add_controller( window, event_controller );
+	gtk_widget_add_controller( context->window, event_controller );
 
 	static GSourceFuncs listener_funks = {
 		.prepare = &listener_prepare,
@@ -703,7 +723,7 @@ static void app_activate( GtkApplication* app, void* data ) {
 		}
 	}
 
-	gtk_window_present( GTK_WINDOW( window ) );
+	gtk_window_present( GTK_WINDOW( context->window ) );
 
 }
 
@@ -845,6 +865,61 @@ static int key_callback( GtkEventControllerKey* event_controller,
 
 		}
 
+		case 's':
+		case 'S': {
+
+			if ( 0 == mods || GDK_CONTROL_MASK == mods ) {
+
+				GtkFileDialog* dialogue = gtk_file_dialog_new();
+				gtk_file_dialog_save( dialogue,
+					GTK_WINDOW( context->window ), NULL,
+					save_callback, (void*) context );
+
+			} else if ( GDK_SHIFT_MASK == mods ||
+					( GDK_SHIFT_MASK | GDK_CONTROL_MASK ) == mods ) {
+
+				GtkWidget* dialogue_window = gtk_window_new();
+				GtkWidget* box = gtk_box_new(
+					GTK_ORIENTATION_VERTICAL, 6 );
+				gtk_window_set_child( GTK_WINDOW( dialogue_window ),
+					box );
+
+				gtk_box_append( GTK_BOX( box ),
+					gtk_label_new( "Size (pixels for png), "
+						"(points for svg or pdf)" ) );
+
+				GtkWidget* width = gtk_spin_button_new_with_range(
+					0., 99999., 1. );
+				GtkWidget* height = gtk_spin_button_new_with_range(
+					0., 99999., 1. );
+
+				gtk_box_append( GTK_BOX( box ), width );
+				gtk_box_append( GTK_BOX( box ), height );
+
+				GtkWidget* ok = gtk_button_new_with_label( "OK" );
+				gtk_box_append( GTK_BOX( box ), ok );
+
+				struct save_size* save_size = calloc(
+					1, sizeof *save_size );
+				save_size->width = width;
+				save_size->height = height;
+				save_size->context = context;
+				save_size->dialogue = dialogue_window;
+
+				g_signal_connect( ok, "clicked",
+					G_CALLBACK( save_size_ok ), save_size );
+
+				gtk_window_set_transient_for(
+					GTK_WINDOW( dialogue_window ),
+					GTK_WINDOW( context->window ) );
+				gtk_window_present( GTK_WINDOW( dialogue_window ) );
+
+			}
+
+			return true;
+
+		}
+
 		default: {
 
 			return false;
@@ -855,6 +930,111 @@ static int key_callback( GtkEventControllerKey* event_controller,
 
 }
 
+static void save_size_ok( GtkWidget* widget, void* data ) {
+
+	struct save_size* save_size = (struct save_size*) data;
+
+	save_size->context->width = gtk_spin_button_get_value_as_int(
+		GTK_SPIN_BUTTON( save_size->width ) );
+	save_size->context->height = gtk_spin_button_get_value_as_int(
+		GTK_SPIN_BUTTON( save_size->height ) );
+	save_size->context->size_set = true;
+
+	GtkFileDialog* dialogue = gtk_file_dialog_new();
+	gtk_file_dialog_save( dialogue,
+		GTK_WINDOW( save_size->context->window ), NULL,
+		save_callback, (void*) ( save_size->context ) );
+
+	gtk_window_destroy( GTK_WINDOW( save_size->dialogue ) );
+
+	free( save_size );
+
+	(void) widget;
+
+}
+
+static void save_callback( GObject* source_object,
+		GAsyncResult* result, void* data ) {
+
+	struct context* context = (struct context*) data;
+	context->size_set = false;
+
+	GFile* file = gtk_file_dialog_save_finish(
+		GTK_FILE_DIALOG( source_object ), result, NULL );
+	if ( NULL == file ) {
+		return;
+	}
+	const char* path = g_file_get_path( file );
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+
+	if ( strlen( path ) > 4 &&
+			0 == strcmp( path + strlen( path ) - 4, ".png" ) ) {
+
+		cairo_surface_t* surface = cairo_image_surface_create(
+			CAIRO_FORMAT_RGB24, context->width, context->height );
+		cairo_t* cr = cairo_create( surface );
+		plot_draw( NULL, cr, context->width, context->height, data );
+		cairo_destroy( cr );
+		cairo_surface_write_to_png( surface, path );
+		cairo_surface_destroy( surface );
+
+		return;
+
+	}
+
+#endif
+
+#ifdef CAIRO_HAS_SVG_SURFACE
+
+	if ( strlen( path ) > 4 &&
+			0 == strcmp( path + strlen( path ) - 4, ".svg" ) ) {
+
+		cairo_surface_t* surface = cairo_svg_surface_create(
+			path,
+			context->width, context->height );
+		cairo_t* cr = cairo_create( surface );
+		plot_draw( NULL, cr,
+			context->width, context->height,
+			data );
+		cairo_destroy( cr );
+		cairo_surface_finish( surface );
+		cairo_surface_flush( surface );
+		cairo_surface_destroy( surface );
+
+		return;
+
+	}
+
+#endif
+
+#ifdef CAIRO_HAS_PDF_SURFACE
+
+	if ( strlen( path ) > 4 &&
+			0 == strcmp( path + strlen( path ) - 4, ".pdf" ) ) {
+
+		cairo_surface_t* surface = cairo_pdf_surface_create(
+			path,
+			context->width, context->height );
+		cairo_t* cr = cairo_create( surface );
+		plot_draw( NULL, cr,
+			context->width, context->height,
+			data );
+		cairo_destroy( cr );
+		cairo_surface_finish( surface );
+		cairo_surface_flush( surface );
+		cairo_surface_destroy( surface );
+
+		return;
+
+	}
+
+#endif
+
+	fprintf( stderr, "No format supported for %s\n", path );
+
+}
+
 static int data_callback( void* data ) {
 
 	struct context* context = (struct context*) data;
@@ -1243,6 +1423,11 @@ static void plot_draw( GtkDrawingArea* plot,
 	struct context* context = (struct context*) data;
 	(void) plot;
 
+	if ( !context->size_set ) {
+		context->width = width;
+		context->height = height;
+	}
+
 	/* Texts */
 
 	double margin_reqs[4] = { 5., 5., 5., 5. };