summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Schodet2019-11-14 00:41:01 +0100
committerNicolas Schodet2019-11-14 00:41:59 +0100
commitead53d7843e184c3f733041a11ce118cafa6c8d4 (patch)
tree84d15f01c3106be201a269376c3cac8747a9b2c2
parentea90facf4674046e0a58969a6e0eb23054c550de (diff)
Add save image
-rw-r--r--gui_app_window.c72
-rw-r--r--utils.c26
-rw-r--r--utils.h11
-rw-r--r--window.ui14
4 files changed, 106 insertions, 17 deletions
diff --git a/gui_app_window.c b/gui_app_window.c
index 8403d8e..4ec9e6d 100644
--- a/gui_app_window.c
+++ b/gui_app_window.c
@@ -26,6 +26,7 @@
#include <math.h>
#include "device.h"
+#include "utils.h"
#include "gui_app.h"
#include "gui_app_window.h"
@@ -44,6 +45,7 @@ struct _GuiAppWindowPrivate {
GtkAdjustment *exposure_adj;
GtkAdjustment *gain_adj;
GtkCheckButton *rotate_button;
+ GtkButton *save_button;
GdkRectangle allocation;
cairo_matrix_t transform;
cairo_surface_t *surface;
@@ -107,6 +109,7 @@ video_ready_cb(GuiApp *app, gpointer user_data)
(unsigned char *) image->pixels, CAIRO_FORMAT_RGB24, image->width,
image->height, image->stride);
gtk_widget_queue_draw(GTK_WIDGET(priv->video));
+ gtk_widget_set_sensitive(GTK_WIDGET(priv->save_button), TRUE);
}
}
}
@@ -141,6 +144,7 @@ video_stop(GuiAppWindowPrivate *priv)
priv->started = false;
gtk_widget_queue_draw(GTK_WIDGET(priv->video));
gtk_button_set_label(priv->start_stop_button, "Start");
+ gtk_widget_set_sensitive(GTK_WIDGET(priv->save_button), FALSE);
}
static gboolean
@@ -242,6 +246,70 @@ rotate_button_toggled_cb(GtkToggleButton *button, gpointer user_data)
}
static void
+save_button_clicked_cb(GtkButton *button, gpointer user_data)
+{
+ GuiAppWindow *win =
+ GUI_APP_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button)));
+ GuiAppWindowPrivate *priv = gui_app_window_get_instance_private(win);
+ if (priv->surface) {
+ GdkPixbuf *pixbuf = gdk_pixbuf_get_from_surface(priv->surface, 0, 0,
+ priv->width, priv->height);
+ if (priv->rotate && pixbuf) {
+ GdkPixbuf *rotated = gdk_pixbuf_rotate_simple(pixbuf, 180);
+ g_object_unref(pixbuf);
+ pixbuf = rotated;
+ }
+ if (pixbuf) {
+ GtkWidget *dialog = gtk_file_chooser_dialog_new("Save image",
+ GTK_WINDOW(win),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ "_Cancel", GTK_RESPONSE_CANCEL,
+ "_Save", GTK_RESPONSE_ACCEPT,
+ NULL);
+ GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog);
+ gtk_file_chooser_set_do_overwrite_confirmation(chooser, TRUE);
+ GtkFileFilter *png_filter = gtk_file_filter_new();
+ gtk_file_filter_set_name(png_filter, "PNG image");
+ gtk_file_filter_add_mime_type(png_filter, "image/png");
+ gtk_file_filter_add_pattern(png_filter, "*.png");
+ gtk_file_chooser_add_filter(chooser, png_filter);
+ GtkFileFilter *jpg_filter = gtk_file_filter_new();
+ gtk_file_filter_set_name(jpg_filter, "JPEG image");
+ gtk_file_filter_add_mime_type(jpg_filter, "image/jpeg");
+ gtk_file_filter_add_pattern(jpg_filter, "*.jpg");
+ gtk_file_filter_add_pattern(jpg_filter, "*.jpeg");
+ gtk_file_chooser_add_filter(chooser, jpg_filter);
+ gint res = gtk_dialog_run(GTK_DIALOG(dialog));
+ if (res == GTK_RESPONSE_ACCEPT) {
+ char *filename = gtk_file_chooser_get_filename(chooser);
+ if (filename) {
+ GtkFileFilter *filter =
+ gtk_file_chooser_get_filter(chooser);
+ const char *type = NULL;
+ if (filter == png_filter)
+ type = "png";
+ else if (filter == jpg_filter)
+ type = "jpeg";
+ if (type) {
+ GError *error = NULL;
+ if (!gdk_pixbuf_save(pixbuf, filename, type, &error,
+ NULL)) {
+ utils_dialog_error(GTK_WINDOW(win),
+ "can not save image: %s",
+ error->message);
+ g_error_free(error);
+ }
+ }
+ g_free(filename);
+ }
+ }
+ gtk_widget_destroy(dialog);
+ g_object_unref(pixbuf);
+ }
+ }
+}
+
+static void
gui_app_window_init(GuiAppWindow *win)
{
gtk_widget_init_template(GTK_WIDGET(win));
@@ -275,6 +343,8 @@ gui_app_window_class_init(GuiAppWindowClass *class)
GuiAppWindow, gain_adj);
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(class),
GuiAppWindow, rotate_button);
+ gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(class),
+ GuiAppWindow, save_button);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class),
destroy_cb);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class),
@@ -291,6 +361,8 @@ gui_app_window_class_init(GuiAppWindowClass *class)
gain_adj_value_changed_cb);
gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class),
rotate_button_toggled_cb);
+ gtk_widget_class_bind_template_callback(GTK_WIDGET_CLASS(class),
+ save_button_clicked_cb);
}
GuiAppWindow *
diff --git a/utils.c b/utils.c
index 2f944b5..489c794 100644
--- a/utils.c
+++ b/utils.c
@@ -42,17 +42,6 @@ utils_fatal(const char *fmt, ...)
}
void
-utils_warning(const char *fmt, ...)
-{
- va_list ap;
- fprintf(stderr, "%s: warning: ", program_invocation_short_name);
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fputc('\n', stderr);
-}
-
-void
utils_info(const char *fmt, ...)
{
va_list ap;
@@ -86,3 +75,18 @@ utils_delay_us(int us)
}
}
+void
+utils_dialog_error(GtkWindow *parent, const char *fmt, ...)
+{
+ va_list ap;
+ char *msg;
+ va_start(ap, fmt);
+ if (vasprintf(&msg, fmt, ap) == -1)
+ utils_fatal("memory exhausted");
+ va_end(ap);
+ GtkWidget *dialog = gtk_message_dialog_new(parent, GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", msg);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ free(msg);
+}
diff --git a/utils.h b/utils.h
index a47cc5b..af43dc9 100644
--- a/utils.h
+++ b/utils.h
@@ -22,17 +22,13 @@
* Web: http://ni.fr.eu.org/
* Email: <nico at ni.fr.eu.org>
*/
+#include <gtk/gtk.h>
/* Report a fatal error. */
void
utils_fatal(const char *fmt, ...)
__attribute__((format(printf, 1, 2), noreturn));
-/* Report a warning. */
-void
-utils_warning(const char *fmt, ...)
- __attribute__((format(printf, 1, 2)));
-
/* Report an info. */
void
utils_info(const char *fmt, ...)
@@ -46,4 +42,9 @@ utils_malloc(size_t size);
void
utils_delay_us(int us);
+/* Display an error message. */
+void
+utils_dialog_error(GtkWindow *parent, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+
#endif /* utils_h */
diff --git a/window.ui b/window.ui
index fd44a1c..767ef34 100644
--- a/window.ui
+++ b/window.ui
@@ -142,7 +142,19 @@
</packing>
</child>
<child>
- <placeholder/>
+ <object class="GtkButton" id="save_button">
+ <property name="label" translatable="yes">Save image</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="save_button_clicked_cb" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">7</property>
+ </packing>
</child>
</object>
<packing>